diff --git a/Amalgam.sln b/Amalgam.sln new file mode 100644 index 0000000..241a037 --- /dev/null +++ b/Amalgam.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34525.116 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Amalgam", "Amalgam\Amalgam.vcxproj", "{2550C133-72A8-4AF7-B22A-A8012BD9F376}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x64.ActiveCfg = Debug|x64 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x64.Build.0 = Debug|x64 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x86.ActiveCfg = Debug|Win32 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Debug|x86.Build.0 = Debug|Win32 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x64.ActiveCfg = Release|x64 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x64.Build.0 = Release|x64 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x86.ActiveCfg = Release|Win32 + {2550C133-72A8-4AF7-B22A-A8012BD9F376}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5E35C5DE-7694-4637-AC86-EF5BEB5B0763} + EndGlobalSection +EndGlobal diff --git a/Amalgam/Amalgam.vcxproj b/Amalgam/Amalgam.vcxproj new file mode 100644 index 0000000..6029559 --- /dev/null +++ b/Amalgam/Amalgam.vcxproj @@ -0,0 +1,641 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {2550c133-72a8-4af7-b22a-a8012bd9f376} + Amalgam + 10.0 + + + + DynamicLibrary + true + v143 + MultiByte + true + + + DynamicLibrary + false + v143 + true + MultiByte + + + DynamicLibrary + true + v143 + MultiByte + true + + + DynamicLibrary + false + v143 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(ProjectName)$(Platform)$(Configuration) + $(SolutionDir)build\$(Platform)\$(Configuration)\ + $(ProjectDir)include\;$(IncludePath) + $(SolutionDir)output\$(Platform)\$(Configuration)\ + + + $(ProjectDir)include\;$(IncludePath) + $(SolutionDir)build\$(Platform)\$(Configuration)\ + $(ProjectName)$(Platform)$(Configuration) + $(SolutionDir)output\$(Platform)\$(Configuration)\ + + + $(SolutionDir)output\$(Platform)\$(Configuration)\ + $(SolutionDir)build\$(Platform)\$(Configuration)\ + $(ProjectName)$(Platform)$(Configuration) + $(ProjectDir)include\;$(IncludePath) + $(VC_ExecutablePath_x64);$(CommonExecutablePath) + $(VC_ReferencesPath_x64); + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + $(CommonExcludePath);$(VC_ExecutablePath_x64);$(VC_LibraryPath_x64) + + + $(SolutionDir)output\$(Platform)\$(Configuration)\ + $(SolutionDir)build\$(Platform)\$(Configuration)\ + $(ProjectName)$(Platform)$(Configuration) + $(ProjectDir)include\;$(IncludePath) + $(VC_ExecutablePath_x64);$(CommonExecutablePath) + $(VC_ReferencesPath_x64); + $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + $(CommonExcludePath);$(VC_ExecutablePath_x64);$(VC_LibraryPath_x64) + false + + + + Level3 + false + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + Default + true + MaxSpeed + Speed + true + true + true + AdvancedVectorExtensions2 + + true + ProgramDatabase + MultiThreadedDebugDLL + true + + + Console + true + + + + + Level3 + true + true + false + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + true + Speed + true + AdvancedVectorExtensions2 + + false + ProgramDatabase + + + Console + true + true + true + + + + + Level3 + false + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + true + Speed + + + true + MaxSpeed + true + Default + true + AdvancedVectorExtensions2 + true + ProgramDatabase + true + MultiThreadedDebugDLL + + + Console + true + + + + + Level3 + true + true + false + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + true + Speed + + + true + AdvancedVectorExtensions2 + ProgramDatabase + false + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/Amalgam/Amalgam.vcxproj.filters b/Amalgam/Amalgam.vcxproj.filters new file mode 100644 index 0000000..9ce4cad --- /dev/null +++ b/Amalgam/Amalgam.vcxproj.filters @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Amalgam/cpp.hint b/Amalgam/cpp.hint new file mode 100644 index 0000000..ef70ae1 --- /dev/null +++ b/Amalgam/cpp.hint @@ -0,0 +1,59 @@ +#define MAKE_HOOK(name, address, type, callconvo, ...) namespace Hooks \ +{\ + namespace name\ + {\ + void Init(); \ + inline CHook Hook(Init); \ + using FN = type(callconvo *)(__VA_ARGS__); \ + type callconvo Func(__VA_ARGS__); \ + }\ +} \ +void Hooks::name::Init() { Hook.Create(reinterpret_cast(address), Func); } \ +type callconvo Hooks::name::Func(__VA_ARGS__) +#define CALL_ORIGINAL Hook.Original() +#define MAKE_INTERFACE_VERSION(type, name, dll, version) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, version, -1, 0); \ +} +#define MAKE_INTERFACE_SIGNATURE(type, name, dll, version, offset, deref) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, version, offset, deref); \ +} +#define MAKE_INTERFACE_NULL(type, name) namespace I { inline type *name = nullptr; } +#define MAKE_INTERFACE_VERSION_SEARCH(type, name, dll, version) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, version, -1, 0, true); \ +} +#define MAKE_INTERFACE_SIGNATURE_SEARCH(type, name, dll, signature, offset, deref) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, signature, offset, deref, true); \ +} +#define NETVAR(_name, type, table, name) type& _name() \ +{ \ + static int nOffset = U::NetVars.GetNetVar(table, name); \ + return *reinterpret_cast(std::uintptr_t(this) + nOffset); \ +} +#define NETVAR_OFF(_name, type, table, name, offset) type& _name() \ +{ \ + static int nOffset = U::NetVars.GetNetVar(table, name) + offset; \ + return *reinterpret_cast(std::uintptr_t(this) + nOffset); \ +} +#define OFFSET(name, type, offset) type& name() \ +{ \ + return *reinterpret_cast(std::uintptr_t(this) + offset); \ +} +#define VIRTUAL(name, type, fn, base, index) type name() \ +{ \ + return reinterpret_cast(U::Memory.GetVFunc(base, index))(base); \ +} +#define CONDGET(name, conditions, cond) bool name() \ +{ \ + return (conditions & cond); \ +} +#define MAKE_SIGNATURE(name, dll, sig, offset) namespace S { inline CSignature name(dll, sig, offset, #name); } +#define ADD_FEATURE_CUSTOM(type, name, scope) namespace scope { inline type name; } +#define ADD_FEATURE(type, name) ADD_FEATURE_CUSTOM(type, name, F) \ No newline at end of file diff --git a/Amalgam/include/ImGui/TextEditor.cpp b/Amalgam/include/ImGui/TextEditor.cpp new file mode 100644 index 0000000..18128cf --- /dev/null +++ b/Amalgam/include/ImGui/TextEditor.cpp @@ -0,0 +1,3597 @@ +#include +#include +#include +#include +#include + +#include "TextEditor.h" + +#define IMGUI_DEFINE_MATH_OPERATORS +#include "imgui.h" // for imGui::GetCurrentWindow() + +#pragma warning( push ) +#pragma warning( disable : 4018 ) + +// TODO +// - multiline comments vs single-line: latter is blocking start of a ML + +template +bool equals(InputIt1 first1, InputIt1 last1, + InputIt2 first2, InputIt2 last2, BinaryPredicate p) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + { + if (!p(*first1, *first2)) + { + return false; + } + } + return first1 == last1 && first2 == last2; +} + +TextEditor::TextEditor() + : mLineSpacing(1.0f) + , mUndoIndex(0) + , mTabSize(4) + , mOverwrite(false) + , mReadOnly(false) + , mWithinRender(false) + , mScrollToCursor(false) + , mScrollToTop(false) + , mTextChanged(false) + , mColorizerEnabled(true) + , mTextStart(20.0f) + , mLeftMargin(10) + , mCursorPositionChanged(false) + , mColorRangeMin(0) + , mColorRangeMax(0) + , mSelectionMode(SelectionMode::Normal) + , mHandleKeyboardInputs(true) + , mHandleMouseInputs(true) + , mIgnoreImGuiChild(false) + , mShowWhitespaces(true) + , mCheckComments(true) + , mStartTime(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()) + , mLastClick(-1.0f) +{ + SetPalette(GetDarkPalette()); + SetLanguageDefinition(LanguageDefinition::HLSL()); + mLines.push_back(Line()); +} + +TextEditor::~TextEditor() = default; + +void TextEditor::SetLanguageDefinition(const LanguageDefinition & aLanguageDef) +{ + mLanguageDefinition = aLanguageDef; + mRegexList.clear(); + + for (auto& r : mLanguageDefinition.mTokenRegexStrings) + { + mRegexList.push_back(std::make_pair(std::regex(r.first, std::regex_constants::optimize), r.second)); + } + + Colorize(); +} + +void TextEditor::SetPalette(const Palette & aValue) +{ + mPaletteBase = aValue; +} + +std::string TextEditor::GetText(const Coordinates & aStart, const Coordinates & aEnd) const +{ + std::string result; + + auto lstart = aStart.mLine; + auto lend = aEnd.mLine; + auto istart = GetCharacterIndex(aStart); + auto iend = GetCharacterIndex(aEnd); + size_t s = 0; + + for (size_t i = lstart; i < lend; i++) + { + s += mLines[i].size(); + } + + result.reserve(s + s / 8); + + while (istart < iend || lstart < lend) + { + if (lstart >= static_cast(mLines.size())) + { + break; + } + + auto& line = mLines[lstart]; + if (istart < static_cast(line.size())) + { + result += line[istart].mChar; + istart++; + } + else + { + istart = 0; + ++lstart; + result += '\n'; + } + } + + return result; +} + +TextEditor::Coordinates TextEditor::GetActualCursorCoordinates() const +{ + return SanitizeCoordinates(mState.mCursorPosition); +} + +TextEditor::Coordinates TextEditor::SanitizeCoordinates(const Coordinates & aValue) const +{ + auto line = aValue.mLine; + auto column = aValue.mColumn; + if (line >= static_cast(mLines.size())) + { + if (mLines.empty()) + { + line = 0; + column = 0; + } + else + { + line = static_cast(mLines.size()) - 1; + column = GetLineMaxColumn(line); + } + return Coordinates(line, column); + } + column = mLines.empty() ? 0 : std::min(column, GetLineMaxColumn(line)); + return Coordinates(line, column); +} + +// https://en.wikipedia.org/wiki/UTF-8 +// We assume that the char is a standalone character (<128) or a leading byte of an UTF-8 code sequence (non-10xxxxxx code) +static int UTF8CharLength(TextEditor::Char c) +{ + if ((c & 0xFE) == 0xFC) + { + return 6; + } + if ((c & 0xFC) == 0xF8) + { + return 5; + } + if ((c & 0xF8) == 0xF0) + { + return 4; + } + if ((c & 0xF0) == 0xE0) + { + return 3; + } + if ((c & 0xE0) == 0xC0) + { + return 2; + } + return 1; +} + +// "Borrowed" from ImGui source +static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c) +{ + if (c < 0x80) + { + buf[0] = static_cast(c); + return 1; + } + if (c < 0x800) + { + if (buf_size < 2) + { + return 0; + } + buf[0] = static_cast(0xc0 + (c >> 6)); + buf[1] = static_cast(0x80 + (c & 0x3f)); + return 2; + } + if (c >= 0xdc00 && c < 0xe000) + { + return 0; + } + if (c >= 0xd800 && c < 0xdc00) + { + if (buf_size < 4) + { + return 0; + } + buf[0] = static_cast(0xf0 + (c >> 18)); + buf[1] = static_cast(0x80 + ((c >> 12) & 0x3f)); + buf[2] = static_cast(0x80 + ((c >> 6) & 0x3f)); + buf[3] = static_cast(0x80 + ((c) & 0x3f)); + return 4; + } + //else if (c < 0x10000) + { + if (buf_size < 3) + { + return 0; + } + buf[0] = static_cast(0xe0 + (c >> 12)); + buf[1] = static_cast(0x80 + ((c >> 6) & 0x3f)); + buf[2] = static_cast(0x80 + ((c) & 0x3f)); + return 3; + } +} + +void TextEditor::Advance(Coordinates & aCoordinates) const +{ + if (aCoordinates.mLine < static_cast(mLines.size())) + { + auto& line = mLines[aCoordinates.mLine]; + auto cindex = GetCharacterIndex(aCoordinates); + + if (cindex + 1 < static_cast(line.size())) + { + auto delta = UTF8CharLength(line[cindex].mChar); + cindex = std::min(cindex + delta, static_cast(line.size()) - 1); + } + else + { + ++aCoordinates.mLine; + cindex = 0; + } + aCoordinates.mColumn = GetCharacterColumn(aCoordinates.mLine, cindex); + } +} + +void TextEditor::DeleteRange(const Coordinates & aStart, const Coordinates & aEnd) +{ + assert(aEnd >= aStart); + assert(!mReadOnly); + + //printf("D(%d.%d)-(%d.%d)\n", aStart.mLine, aStart.mColumn, aEnd.mLine, aEnd.mColumn); + + if (aEnd == aStart) + { + return; + } + + auto start = GetCharacterIndex(aStart); + auto end = GetCharacterIndex(aEnd); + + if (aStart.mLine == aEnd.mLine) + { + auto& line = mLines[aStart.mLine]; + auto n = GetLineMaxColumn(aStart.mLine); + if (aEnd.mColumn >= n) + { + line.erase(line.begin() + start, line.end()); + } + else + { + line.erase(line.begin() + start, line.begin() + end); + } + } + else + { + auto& firstLine = mLines[aStart.mLine]; + auto& lastLine = mLines[aEnd.mLine]; + + firstLine.erase(firstLine.begin() + start, firstLine.end()); + lastLine.erase(lastLine.begin(), lastLine.begin() + end); + + if (aStart.mLine < aEnd.mLine) + { + firstLine.insert(firstLine.end(), lastLine.begin(), lastLine.end()); + } + + if (aStart.mLine < aEnd.mLine) + { + RemoveLine(aStart.mLine + 1, aEnd.mLine + 1); + } + } + + mTextChanged = true; +} + +int TextEditor::InsertTextAt(Coordinates & /* inout */ aWhere, const char* aValue) +{ + assert(!mReadOnly); + + int cindex = GetCharacterIndex(aWhere); + int totalLines = 0; + while (*aValue != '\0') + { + assert(!mLines.empty()); + + if (*aValue == '\r') + { + // skip + ++aValue; + } + else if (*aValue == '\n') + { + if (cindex < static_cast(mLines[aWhere.mLine].size())) + { + auto& newLine = InsertLine(aWhere.mLine + 1); + auto& line = mLines[aWhere.mLine]; + newLine.insert(newLine.begin(), line.begin() + cindex, line.end()); + line.erase(line.begin() + cindex, line.end()); + } + else + { + InsertLine(aWhere.mLine + 1); + } + ++aWhere.mLine; + aWhere.mColumn = 0; + cindex = 0; + ++totalLines; + ++aValue; + } + else + { + auto& line = mLines[aWhere.mLine]; + auto d = UTF8CharLength(*aValue); + while (d-- > 0 && *aValue != '\0') + { + line.insert(line.begin() + cindex++, Glyph(*aValue++, PaletteIndex::Default)); + } + ++aWhere.mColumn; + } + + mTextChanged = true; + } + + return totalLines; +} + +void TextEditor::AddUndo(UndoRecord & aValue) +{ + assert(!mReadOnly); + //printf("AddUndo: (@%d.%d) +\'%s' [%d.%d .. %d.%d], -\'%s', [%d.%d .. %d.%d] (@%d.%d)\n", + // aValue.mBefore.mCursorPosition.mLine, aValue.mBefore.mCursorPosition.mColumn, + // aValue.mAdded.c_str(), aValue.mAddedStart.mLine, aValue.mAddedStart.mColumn, aValue.mAddedEnd.mLine, aValue.mAddedEnd.mColumn, + // aValue.mRemoved.c_str(), aValue.mRemovedStart.mLine, aValue.mRemovedStart.mColumn, aValue.mRemovedEnd.mLine, aValue.mRemovedEnd.mColumn, + // aValue.mAfter.mCursorPosition.mLine, aValue.mAfter.mCursorPosition.mColumn + // ); + + mUndoBuffer.resize(static_cast(mUndoIndex + 1)); + mUndoBuffer.back() = aValue; + ++mUndoIndex; +} + +TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2 & aPosition) const +{ + ImVec2 origin = ImGui::GetCursorScreenPos(); + ImVec2 local(aPosition.x - origin.x, aPosition.y - origin.y); + + int lineNo = std::max(0, static_cast(floor(local.y / mCharAdvance.y))); + + int columnCoord = 0; + + if (lineNo >= 0 && lineNo < static_cast(mLines.size())) + { + auto& line = mLines.at(lineNo); + + int columnIndex = 0; + float columnX = 0.0f; + + while (static_cast(columnIndex) < line.size()) + { + float columnWidth = 0.0f; + + if (line[columnIndex].mChar == '\t') + { + float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ").x; + float oldX = columnX; + float newColumnX = (1.0f + std::floor((1.0f + columnX) / (static_cast(mTabSize) * spaceSize))) * (static_cast(mTabSize) * spaceSize); + columnWidth = newColumnX - oldX; + if (mTextStart + columnX + columnWidth * 0.5f > local.x) + { + break; + } + columnX = newColumnX; + columnCoord = (columnCoord / mTabSize) * mTabSize + mTabSize; + columnIndex++; + } + else + { + char buf[7]; + auto d = UTF8CharLength(line[columnIndex].mChar); + int i = 0; + while (i < 6 && d-- > 0) + { + buf[i++] = line[columnIndex++].mChar; + } + buf[i] = '\0'; + columnWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf).x; + if (mTextStart + columnX + columnWidth * 0.5f > local.x) + { + break; + } + columnX += columnWidth; + columnCoord++; + } + } + } + + return SanitizeCoordinates(Coordinates(lineNo, columnCoord)); +} + +TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates & aFrom) const +{ + Coordinates at = aFrom; + if (at.mLine >= static_cast(mLines.size())) + { + return at; + } + + auto& line = mLines[at.mLine]; + auto cindex = GetCharacterIndex(at); + + if (cindex >= static_cast(line.size())) + { + return at; + } + + while (cindex > 0 && isspace(line[cindex].mChar)) + { + --cindex; + } + + auto cstart = static_cast(line[cindex].mColorIndex); + while (cindex > 0) + { + auto c = line[cindex].mChar; + if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx + { + if (c <= 32 && isspace(c)) + { + cindex++; + break; + } + if (cstart != static_cast(line[static_cast(cindex - 1)].mColorIndex)) + { + break; + } + } + --cindex; + } + return Coordinates(at.mLine, GetCharacterColumn(at.mLine, cindex)); +} + +TextEditor::Coordinates TextEditor::FindWordEnd(const Coordinates & aFrom) const +{ + Coordinates at = aFrom; + if (at.mLine >= static_cast(mLines.size())) + { + return at; + } + + auto& line = mLines[at.mLine]; + auto cindex = GetCharacterIndex(at); + + if (cindex >= static_cast(line.size())) + { + return at; + } + + bool prevspace = static_cast(isspace(line[cindex].mChar)); + auto cstart = static_cast(line[cindex].mColorIndex); + while (cindex < static_cast(line.size())) + { + auto c = line[cindex].mChar; + auto d = UTF8CharLength(c); + if (cstart != static_cast(line[cindex].mColorIndex)) + { + break; + } + + if (prevspace != !!isspace(c)) + { + if (isspace(c)) + { + while (cindex < static_cast(line.size()) && isspace(line[cindex].mChar)) + { + ++cindex; + } + } + break; + } + cindex += d; + } + return Coordinates(aFrom.mLine, GetCharacterColumn(aFrom.mLine, cindex)); +} + +TextEditor::Coordinates TextEditor::FindNextWord(const Coordinates & aFrom) const +{ + Coordinates at = aFrom; + if (at.mLine >= static_cast(mLines.size())) + { + return at; + } + + // skip to the next non-word character + auto cindex = GetCharacterIndex(aFrom); + bool isword = false; + bool skip = false; + if (cindex < static_cast(mLines[at.mLine].size())) + { + auto& line = mLines[at.mLine]; + isword = isalnum(line[cindex].mChar); + skip = isword; + } + + while (!isword || skip) + { + if (at.mLine >= mLines.size()) + { + auto l = std::max(0, static_cast(mLines.size()) - 1); + return Coordinates(l, GetLineMaxColumn(l)); + } + + auto& line = mLines[at.mLine]; + if (cindex < static_cast(line.size())) + { + isword = isalnum(line[cindex].mChar); + + if (isword && !skip) + { + return Coordinates(at.mLine, GetCharacterColumn(at.mLine, cindex)); + } + + if (!isword) + { + skip = false; + } + + cindex++; + } + else + { + cindex = 0; + ++at.mLine; + skip = false; + isword = false; + } + } + + return at; +} + +int TextEditor::GetCharacterIndex(const Coordinates & aCoordinates) const +{ + if (aCoordinates.mLine >= mLines.size()) + { + return -1; + } + auto& line = mLines[aCoordinates.mLine]; + int c = 0; + int i = 0; + for (; i < line.size() && c < aCoordinates.mColumn;) + { + if (line[i].mChar == '\t') + { + c = (c / mTabSize) * mTabSize + mTabSize; + } + else + { + ++c; + } + i += UTF8CharLength(line[i].mChar); + } + return i; +} + +int TextEditor::GetCharacterColumn(int aLine, int aIndex) const +{ + if (aLine >= mLines.size()) + { + return 0; + } + auto& line = mLines[aLine]; + int col = 0; + int i = 0; + while (i < aIndex && i < static_cast(line.size())) + { + auto c = line[i].mChar; + i += UTF8CharLength(c); + if (c == '\t') + { + col = (col / mTabSize) * mTabSize + mTabSize; + } + else + { + col++; + } + } + return col; +} + +int TextEditor::GetLineCharacterCount(int aLine) const +{ + if (aLine >= mLines.size()) + { + return 0; + } + auto& line = mLines[aLine]; + int c = 0; + for (unsigned i = 0; i < line.size(); c++) + { + i += UTF8CharLength(line[i].mChar); + } + return c; +} + +int TextEditor::GetLineMaxColumn(int aLine) const +{ + if (aLine >= mLines.size()) + { + return 0; + } + auto& line = mLines[aLine]; + int col = 0; + for (unsigned i = 0; i < line.size();) + { + auto c = line[i].mChar; + if (c == '\t') + { + col = (col / mTabSize) * mTabSize + mTabSize; + } + else + { + col++; + } + i += UTF8CharLength(c); + } + return col; +} + +bool TextEditor::IsOnWordBoundary(const Coordinates & aAt) const +{ + if (aAt.mLine >= static_cast(mLines.size()) || aAt.mColumn == 0) + { + return true; + } + + auto& line = mLines[aAt.mLine]; + auto cindex = GetCharacterIndex(aAt); + if (cindex >= static_cast(line.size())) + { + return true; + } + + if (mColorizerEnabled) + { + return line[cindex].mColorIndex != line[static_cast(cindex - 1)].mColorIndex; + } + + return isspace(line[cindex].mChar) != isspace(line[cindex - 1].mChar); +} + +void TextEditor::RemoveLine(int aStart, int aEnd) +{ + assert(!mReadOnly); + assert(aEnd >= aStart); + assert(mLines.size() > static_cast(aEnd - aStart)); + + ErrorMarkers etmp; + for (auto& i : mErrorMarkers) + { + ErrorMarkers::value_type e(i.first >= aStart ? i.first - 1 : i.first, i.second); + if (e.first >= aStart && e.first <= aEnd) + { + continue; + } + etmp.insert(e); + } + mErrorMarkers = std::move(etmp); + + Breakpoints btmp; + for (auto i : mBreakpoints) + { + if (i >= aStart && i <= aEnd) + { + continue; + } + btmp.insert(i >= aStart ? i - 1 : i); + } + mBreakpoints = std::move(btmp); + + mLines.erase(mLines.begin() + aStart, mLines.begin() + aEnd); + assert(!mLines.empty()); + + mTextChanged = true; +} + +void TextEditor::RemoveLine(int aIndex) +{ + assert(!mReadOnly); + assert(mLines.size() > 1); + + ErrorMarkers etmp; + for (auto& i : mErrorMarkers) + { + ErrorMarkers::value_type e(i.first > aIndex ? i.first - 1 : i.first, i.second); + if (e.first - 1 == aIndex) + { + continue; + } + etmp.insert(e); + } + mErrorMarkers = std::move(etmp); + + Breakpoints btmp; + for (auto i : mBreakpoints) + { + if (i == aIndex) + { + continue; + } + btmp.insert(i >= aIndex ? i - 1 : i); + } + mBreakpoints = std::move(btmp); + + mLines.erase(mLines.begin() + aIndex); + assert(!mLines.empty()); + + mTextChanged = true; +} + +TextEditor::Line& TextEditor::InsertLine(int aIndex) +{ + assert(!mReadOnly); + + auto& result = *mLines.insert(mLines.begin() + aIndex, Line()); + + ErrorMarkers etmp; + for (auto& i : mErrorMarkers) + { + etmp.insert(ErrorMarkers::value_type(i.first >= aIndex ? i.first + 1 : i.first, i.second)); + } + mErrorMarkers = std::move(etmp); + + Breakpoints btmp; + for (auto i : mBreakpoints) + { + btmp.insert(i >= aIndex ? i + 1 : i); + } + mBreakpoints = std::move(btmp); + + return result; +} + +std::string TextEditor::GetWordUnderCursor() const +{ + auto c = GetCursorPosition(); + return GetWordAt(c); +} + +std::string TextEditor::GetWordAt(const Coordinates & aCoords) const +{ + auto start = FindWordStart(aCoords); + auto end = FindWordEnd(aCoords); + + std::string r; + + auto istart = GetCharacterIndex(start); + auto iend = GetCharacterIndex(end); + + for (auto it = istart; it < iend; ++it) + { + r.push_back(mLines[aCoords.mLine][it].mChar); + } + + return r; +} + +ImU32 TextEditor::GetGlyphColor(const Glyph & aGlyph) const +{ + if (!mColorizerEnabled) + { + return mPalette[static_cast(PaletteIndex::Default)]; + } + if (aGlyph.mComment) + { + return mPalette[static_cast(PaletteIndex::Comment)]; + } + if (aGlyph.mMultiLineComment) + { + return mPalette[static_cast(PaletteIndex::MultiLineComment)]; + } + const auto color = mPalette[static_cast(aGlyph.mColorIndex)]; + if (aGlyph.mPreprocessor) + { + const auto ppcolor = mPalette[static_cast(PaletteIndex::Preprocessor)]; + const int c0 = ((ppcolor & 0xff) + (color & 0xff)) / 2; + const int c1 = (((ppcolor >> 8) & 0xff) + ((color >> 8) & 0xff)) / 2; + const int c2 = (((ppcolor >> 16) & 0xff) + ((color >> 16) & 0xff)) / 2; + const int c3 = (((ppcolor >> 24) & 0xff) + ((color >> 24) & 0xff)) / 2; + return static_cast(c0 | (c1 << 8) | (c2 << 16) | (c3 << 24)); + } + return color; +} + +void TextEditor::HandleKeyboardInputs() +{ + ImGuiIO& io = ImGui::GetIO(); + auto shift = io.KeyShift; + auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl; + auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt; + + if (ImGui::IsWindowFocused()) + { + if (ImGui::IsWindowHovered()) + { + ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput); + } + //ImGui::CaptureKeyboardFromApp(true); + + io.WantCaptureKeyboard = true; + io.WantTextInput = true; + + if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z))) + { + Undo(); + } + else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace))) + { + Undo(); + } + else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y))) + { + Redo(); + } + else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow))) + { + MoveUp(1, shift); + } + else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow))) + { + MoveDown(1, shift); + } + else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow))) + { + MoveLeft(1, shift, ctrl); + } + else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow))) + { + MoveRight(1, shift, ctrl); + } + else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp))) + { + MoveUp(GetPageSize() - 4, shift); + } + else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown))) + { + MoveDown(GetPageSize() - 4, shift); + } + else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home))) + { + MoveTop(shift); + } + else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End))) + { + MoveBottom(shift); + } + else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home))) + { + MoveHome(shift); + } + else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End))) + { + MoveEnd(shift); + } + else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete))) + { + Delete(); + } + else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace))) + { + Backspace(); + } + else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert))) + { + mOverwrite ^= true; + } + else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert))) + { + Copy(); + } + else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C))) + { + Copy(); + } + else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert))) + { + Paste(); + } + else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V))) + { + Paste(); + } + else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X))) + { + Cut(); + } + else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete))) + { + Cut(); + } + else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A))) + { + SelectAll(); + } + else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter))) + { + EnterCharacter('\n', false); + } + else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab))) + { + EnterCharacter('\t', shift); + } + + if (!IsReadOnly() && !io.InputQueueCharacters.empty()) + { + for (int i = 0; i < io.InputQueueCharacters.Size; i++) + { + auto c = io.InputQueueCharacters[i]; + if (c != 0 && (c == '\n' || c >= 32)) + { + EnterCharacter(c, shift); + } + } + io.InputQueueCharacters.resize(0); + } + } +} + +void TextEditor::HandleMouseInputs() +{ + ImGuiIO& io = ImGui::GetIO(); + auto shift = io.KeyShift; + auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl; + auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt; + + if (ImGui::IsWindowHovered()) + { + if (!shift && !alt) + { + auto click = ImGui::IsMouseClicked(0); + auto doubleClick = ImGui::IsMouseDoubleClicked(0); + auto t = ImGui::GetTime(); + auto tripleClick = click && !doubleClick && (mLastClick != -1.0f && (t - mLastClick) < io.MouseDoubleClickTime); + + /* + Left mouse button triple click + */ + + if (tripleClick) + { + if (!ctrl) + { + mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos()); + mSelectionMode = SelectionMode::Line; + SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode); + } + + mLastClick = -1.0f; + } + + /* + Left mouse button double click + */ + + else if (doubleClick) + { + if (!ctrl) + { + mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos()); + if (mSelectionMode == SelectionMode::Line) + { + mSelectionMode = SelectionMode::Normal; + } + else + { + mSelectionMode = SelectionMode::Word; + } + SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode); + } + + mLastClick = static_cast(ImGui::GetTime()); + } + + /* + Left mouse button click + */ + else if (click) + { + mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos()); + if (ctrl) + { + mSelectionMode = SelectionMode::Word; + } + else + { + mSelectionMode = SelectionMode::Normal; + } + SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode); + + mLastClick = static_cast(ImGui::GetTime()); + } + // Mouse left button dragging (=> update selection) + else if (ImGui::IsMouseDragging(0) && ImGui::IsMouseDown(0)) + { + io.WantCaptureMouse = true; + mState.mCursorPosition = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos()); + SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode); + } + } + } +} + +void TextEditor::Render() +{ + /* Compute mCharAdvance regarding to scaled font size (Ctrl + mouse wheel)*/ + const float fontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x; + mCharAdvance = ImVec2(fontSize, ImGui::GetTextLineHeightWithSpacing() * mLineSpacing); + + /* Update palette with the current alpha from style */ + for (int i = 0; i < static_cast(PaletteIndex::Max); ++i) + { + auto color = ImGui::ColorConvertU32ToFloat4(mPaletteBase[i]); + color.w *= ImGui::GetStyle().Alpha; + mPalette[i] = ImGui::ColorConvertFloat4ToU32(color); + } + + assert(mLineBuffer.empty()); + + auto contentSize = ImGui::GetWindowContentRegionMax(); + auto drawList = ImGui::GetWindowDrawList(); + float longest(mTextStart); + + if (mScrollToTop) + { + mScrollToTop = false; + ImGui::SetScrollY(0.f); + } + + ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos(); + auto scrollX = ImGui::GetScrollX(); + auto scrollY = ImGui::GetScrollY(); + + auto lineNo = static_cast(floor(scrollY / mCharAdvance.y)); + auto globalLineMax = static_cast(mLines.size()); + auto lineMax = std::max(0, std::min(static_cast(mLines.size()) - 1, lineNo + static_cast(floor((scrollY + contentSize.y) / mCharAdvance.y)))); + + // Deduce mTextStart by evaluating mLines size (global lineMax) plus two spaces as text width + char buf[16]; + snprintf(buf, 16, " %d ", globalLineMax); + mTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x + mLeftMargin; + + if (!mLines.empty()) + { + float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x; + + while (lineNo <= lineMax) + { + auto lineStartScreenPos = ImVec2(cursorScreenPos.x, cursorScreenPos.y + lineNo * mCharAdvance.y); + auto textScreenPos = ImVec2(lineStartScreenPos.x + mTextStart, lineStartScreenPos.y); + + auto& line = mLines[lineNo]; + longest = std::max(mTextStart + TextDistanceToLineStart(Coordinates(lineNo, GetLineMaxColumn(lineNo))), longest); + auto columnNo = 0; + Coordinates lineStartCoord(lineNo, 0); + Coordinates lineEndCoord(lineNo, GetLineMaxColumn(lineNo)); + + // Draw selection for the current line + float sstart = -1.0f; + float ssend = -1.0f; + + assert(mState.mSelectionStart <= mState.mSelectionEnd); + if (mState.mSelectionStart <= lineEndCoord) + { + sstart = mState.mSelectionStart > lineStartCoord ? TextDistanceToLineStart(mState.mSelectionStart) : 0.0f; + } + if (mState.mSelectionEnd > lineStartCoord) + { + ssend = TextDistanceToLineStart(mState.mSelectionEnd < lineEndCoord ? mState.mSelectionEnd : lineEndCoord); + } + + if (mState.mSelectionEnd.mLine > lineNo) + { + ssend += mCharAdvance.x; + } + + if (sstart != -1 && ssend != -1 && sstart < ssend) + { + ImVec2 vstart(lineStartScreenPos.x + mTextStart + sstart, lineStartScreenPos.y); + ImVec2 vend(lineStartScreenPos.x + mTextStart + ssend, lineStartScreenPos.y + mCharAdvance.y); + drawList->AddRectFilled(vstart, vend, mPalette[static_cast(PaletteIndex::Selection)]); + } + + // Draw breakpoints + auto start = ImVec2(lineStartScreenPos.x + scrollX, lineStartScreenPos.y); + + if (mBreakpoints.count(lineNo + 1) != 0) + { + auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y); + drawList->AddRectFilled(start, end, mPalette[static_cast(PaletteIndex::Breakpoint)]); + } + + // Draw error markers + auto errorIt = mErrorMarkers.find(lineNo + 1); + if (errorIt != mErrorMarkers.end()) + { + auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y); + drawList->AddRectFilled(start, end, mPalette[static_cast(PaletteIndex::ErrorMarker)]); + + if (ImGui::IsMouseHoveringRect(lineStartScreenPos, end)) + { + ImGui::BeginTooltip(); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.2f, 0.2f, 1.0f)); + ImGui::Text("Error at line %d:", errorIt->first); + ImGui::PopStyleColor(); + ImGui::Separator(); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.2f, 1.0f)); + ImGui::Text("%s", errorIt->second.c_str()); + ImGui::PopStyleColor(); + ImGui::EndTooltip(); + } + } + + // Draw line number (right aligned) + snprintf(buf, 16, "%d ", lineNo + 1); + + auto lineNoWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x; + drawList->AddText(ImVec2(lineStartScreenPos.x + mTextStart - lineNoWidth, lineStartScreenPos.y), mPalette[static_cast(PaletteIndex::LineNumber)], buf); + + if (mState.mCursorPosition.mLine == lineNo) + { + auto focused = ImGui::IsWindowFocused(); + + // Highlight the current line (where the cursor is) + if (!HasSelection()) + { + auto end = ImVec2(start.x + contentSize.x + scrollX, start.y + mCharAdvance.y); + drawList->AddRectFilled(start, end, mPalette[static_cast(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]); + drawList->AddRect(start, end, mPalette[static_cast(PaletteIndex::CurrentLineEdge)], 1.0f); + } + + // Render the cursor + if (focused) + { + auto timeEnd = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto elapsed = timeEnd - mStartTime; + if (elapsed > 400) + { + float width = 1.0f; + auto cindex = GetCharacterIndex(mState.mCursorPosition); + float cx = TextDistanceToLineStart(mState.mCursorPosition); + + if (mOverwrite && cindex < static_cast(line.size())) + { + auto c = line[cindex].mChar; + if (c == '\t') + { + auto x = (1.0f + std::floor((1.0f + cx) / (static_cast(mTabSize) * spaceSize))) * (static_cast(mTabSize) * spaceSize); + width = x - cx; + } + else + { + char buf2[2]; + buf2[0] = line[cindex].mChar; + buf2[1] = '\0'; + width = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf2).x; + } + } + ImVec2 cstart(textScreenPos.x + cx, lineStartScreenPos.y); + ImVec2 cend(textScreenPos.x + cx + width, lineStartScreenPos.y + mCharAdvance.y); + drawList->AddRectFilled(cstart, cend, mPalette[static_cast(PaletteIndex::Cursor)]); + if (elapsed > 800) + { + mStartTime = timeEnd; + } + } + } + } + + // Render colorized text + auto prevColor = line.empty() ? mPalette[static_cast(PaletteIndex::Default)] : GetGlyphColor(line[0]); + ImVec2 bufferOffset; + + for (int i = 0; i < line.size();) + { + auto& glyph = line[i]; + auto color = GetGlyphColor(glyph); + + if ((color != prevColor || glyph.mChar == '\t' || glyph.mChar == ' ') && !mLineBuffer.empty()) + { + const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y); + drawList->AddText(newOffset, prevColor, mLineBuffer.c_str()); + auto textSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, mLineBuffer.c_str(), nullptr, nullptr); + bufferOffset.x += textSize.x; + mLineBuffer.clear(); + } + prevColor = color; + + if (glyph.mChar == '\t') + { + auto oldX = bufferOffset.x; + bufferOffset.x = (1.0f + std::floor((1.0f + bufferOffset.x) / (static_cast(mTabSize) * spaceSize))) * (static_cast(mTabSize) * spaceSize); + ++i; + + if (mShowWhitespaces) + { + const auto s = ImGui::GetFontSize(); + const auto x1 = textScreenPos.x + oldX + 1.0f; + const auto x2 = textScreenPos.x + bufferOffset.x - 1.0f; + const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f; + const ImVec2 p1(x1, y); + const ImVec2 p2(x2, y); + const ImVec2 p3(x2 - s * 0.2f, y - s * 0.2f); + const ImVec2 p4(x2 - s * 0.2f, y + s * 0.2f); + drawList->AddLine(p1, p2, 0x90909090); + drawList->AddLine(p2, p3, 0x90909090); + drawList->AddLine(p2, p4, 0x90909090); + } + } + else if (glyph.mChar == ' ') + { + if (mShowWhitespaces) + { + const auto s = ImGui::GetFontSize(); + const auto x = textScreenPos.x + bufferOffset.x + spaceSize * 0.5f; + const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f; + drawList->AddCircleFilled(ImVec2(x, y), 1.5f, 0x80808080, 4); + } + bufferOffset.x += spaceSize; + i++; + } + else + { + auto l = UTF8CharLength(glyph.mChar); + while (l-- > 0) + { + mLineBuffer.push_back(line[i++].mChar); + } + } + ++columnNo; + } + + if (!mLineBuffer.empty()) + { + const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y); + drawList->AddText(newOffset, prevColor, mLineBuffer.c_str()); + mLineBuffer.clear(); + } + + ++lineNo; + } + + // Draw a tooltip on known identifiers/preprocessor symbols + if (ImGui::IsMousePosValid()) + { + auto id = GetWordAt(ScreenPosToCoordinates(ImGui::GetMousePos())); + if (!id.empty()) + { + auto it = mLanguageDefinition.mIdentifiers.find(id); + if (it != mLanguageDefinition.mIdentifiers.end()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(it->second.mDeclaration.c_str()); + ImGui::EndTooltip(); + } + else + { + auto pi = mLanguageDefinition.mPreprocIdentifiers.find(id); + if (pi != mLanguageDefinition.mPreprocIdentifiers.end()) + { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(pi->second.mDeclaration.c_str()); + ImGui::EndTooltip(); + } + } + } + } + } + + + ImGui::Dummy(ImVec2((longest + 2), mLines.size() * mCharAdvance.y)); + + if (mScrollToCursor) + { + EnsureCursorVisible(); + ImGui::SetWindowFocus(); + mScrollToCursor = false; + } +} + +void TextEditor::Render(const char* aTitle, const ImVec2 & aSize, bool aBorder) +{ + mWithinRender = true; + mTextChanged = false; + mCursorPositionChanged = false; + + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::ColorConvertU32ToFloat4(mPalette[static_cast(PaletteIndex::Background)])); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + if (!mIgnoreImGuiChild) + { + ImGui::BeginChild(aTitle, aSize, aBorder, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NoMove); + } + + if (mHandleKeyboardInputs) + { + HandleKeyboardInputs(); + ImGui::PushAllowKeyboardFocus(true); + } + + if (mHandleMouseInputs) + { + HandleMouseInputs(); + } + + ColorizeInternal(); + Render(); + + if (mHandleKeyboardInputs) + { + ImGui::PopAllowKeyboardFocus(); + } + + if (!mIgnoreImGuiChild) + { + ImGui::EndChild(); + } + + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); + + mWithinRender = false; +} + +void TextEditor::SetText(const std::string & aText) +{ + mLines.clear(); + mLines.emplace_back(Line()); + for (auto chr : aText) + { + if (chr == '\r') + { + // ignore the carriage return character + } + else if (chr == '\n') + { + mLines.emplace_back(Line()); + } + else + { + mLines.back().emplace_back(Glyph(chr, PaletteIndex::Default)); + } + } + + mTextChanged = true; + mScrollToTop = true; + + mUndoBuffer.clear(); + mUndoIndex = 0; + + Colorize(); +} + +void TextEditor::SetTextLines(const std::vector&aLines) +{ + mLines.clear(); + + if (aLines.empty()) + { + mLines.emplace_back(Line()); + } + else + { + mLines.resize(aLines.size()); + + for (size_t i = 0; i < aLines.size(); ++i) + { + const std::string& aLine = aLines[i]; + + mLines[i].reserve(aLine.size()); + for (size_t j = 0; j < aLine.size(); ++j) + { + mLines[i].emplace_back(Glyph(aLine[j], PaletteIndex::Default)); + } + } + } + + mTextChanged = true; + mScrollToTop = true; + + mUndoBuffer.clear(); + mUndoIndex = 0; + + Colorize(); +} + +void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) +{ + assert(!mReadOnly); + + UndoRecord u; + + u.mBefore = mState; + + if (HasSelection()) + { + if (aChar == '\t' && mState.mSelectionStart.mLine != mState.mSelectionEnd.mLine) + { + auto start = mState.mSelectionStart; + auto end = mState.mSelectionEnd; + auto originalEnd = end; + + if (start > end) + { + std::swap(start, end); + } + start.mColumn = 0; + // end.mColumn = end.mLine < mLines.size() ? mLines[end.mLine].size() : 0; + if (end.mColumn == 0 && end.mLine > 0) + { + --end.mLine; + } + if (end.mLine >= static_cast(mLines.size())) + { + end.mLine = mLines.empty() ? 0 : static_cast(mLines.size()) - 1; + } + end.mColumn = GetLineMaxColumn(end.mLine); + + //if (end.mColumn >= GetLineMaxColumn(end.mLine)) + // end.mColumn = GetLineMaxColumn(end.mLine) - 1; + + u.mRemovedStart = start; + u.mRemovedEnd = end; + u.mRemoved = GetText(start, end); + + bool modified = false; + + for (int i = start.mLine; i <= end.mLine; i++) + { + auto& line = mLines[i]; + if (aShift) + { + if (!line.empty()) + { + if (line.front().mChar == '\t') + { + line.erase(line.begin()); + modified = true; + } + else + { + for (int j = 0; j < mTabSize && !line.empty() && line.front().mChar == ' '; j++) + { + line.erase(line.begin()); + modified = true; + } + } + } + } + else + { + line.insert(line.begin(), Glyph('\t', PaletteIndex::Background)); + modified = true; + } + } + + if (modified) + { + start = Coordinates(start.mLine, GetCharacterColumn(start.mLine, 0)); + Coordinates rangeEnd; + if (originalEnd.mColumn != 0) + { + end = Coordinates(end.mLine, GetLineMaxColumn(end.mLine)); + rangeEnd = end; + u.mAdded = GetText(start, end); + } + else + { + end = Coordinates(originalEnd.mLine, 0); + rangeEnd = Coordinates(end.mLine - 1, GetLineMaxColumn(end.mLine - 1)); + u.mAdded = GetText(start, rangeEnd); + } + + u.mAddedStart = start; + u.mAddedEnd = rangeEnd; + u.mAfter = mState; + + mState.mSelectionStart = start; + mState.mSelectionEnd = end; + AddUndo(u); + + mTextChanged = true; + + EnsureCursorVisible(); + } + + return; + } // c == '\t' + u.mRemoved = GetSelectedText(); + u.mRemovedStart = mState.mSelectionStart; + u.mRemovedEnd = mState.mSelectionEnd; + DeleteSelection(); + } // HasSelection + + auto coord = GetActualCursorCoordinates(); + u.mAddedStart = coord; + + assert(!mLines.empty()); + + if (aChar == '\n') + { + InsertLine(coord.mLine + 1); + auto& line = mLines[coord.mLine]; + auto& newLine = mLines[coord.mLine + 1]; + + if (mLanguageDefinition.mAutoIndentation) + { + for (size_t it = 0; it < line.size() && isascii(line[it].mChar) && isblank(line[it].mChar); ++it) + { + newLine.push_back(line[it]); + } + } + + const size_t whitespaceSize = newLine.size(); + auto cindex = GetCharacterIndex(coord); + newLine.insert(newLine.end(), line.begin() + cindex, line.end()); + line.erase(line.begin() + cindex, line.begin() + line.size()); + SetCursorPosition(Coordinates(coord.mLine + 1, GetCharacterColumn(coord.mLine + 1, static_cast(whitespaceSize)))); + u.mAdded = static_cast(aChar); + } + else + { + char buf[7]; + int e = ImTextCharToUtf8(buf, 7, aChar); + if (e > 0) + { + buf[e] = '\0'; + auto& line = mLines[coord.mLine]; + auto cindex = GetCharacterIndex(coord); + + if (mOverwrite && cindex < static_cast(line.size())) + { + auto d = UTF8CharLength(line[cindex].mChar); + + u.mRemovedStart = mState.mCursorPosition; + u.mRemovedEnd = Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex + d)); + + while (d-- > 0 && cindex < static_cast(line.size())) + { + u.mRemoved += line[cindex].mChar; + line.erase(line.begin() + cindex); + } + } + + for (auto p = buf; *p != '\0'; p++, ++cindex) + { + line.insert(line.begin() + cindex, Glyph(*p, PaletteIndex::Default)); + } + u.mAdded = buf; + + SetCursorPosition(Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex))); + } + else + { + return; + } + } + + mTextChanged = true; + + u.mAddedEnd = GetActualCursorCoordinates(); + u.mAfter = mState; + + AddUndo(u); + + Colorize(coord.mLine - 1, 3); + EnsureCursorVisible(); +} + +void TextEditor::SetReadOnly(bool aValue) +{ + mReadOnly = aValue; +} + +void TextEditor::SetColorizerEnable(bool aValue) +{ + mColorizerEnabled = aValue; +} + +void TextEditor::SetCursorPosition(const Coordinates & aPosition) +{ + if (mState.mCursorPosition != aPosition) + { + mState.mCursorPosition = aPosition; + mCursorPositionChanged = true; + EnsureCursorVisible(); + } +} + +void TextEditor::SetSelectionStart(const Coordinates & aPosition) +{ + mState.mSelectionStart = SanitizeCoordinates(aPosition); + if (mState.mSelectionStart > mState.mSelectionEnd) + { + std::swap(mState.mSelectionStart, mState.mSelectionEnd); + } +} + +void TextEditor::SetSelectionEnd(const Coordinates & aPosition) +{ + mState.mSelectionEnd = SanitizeCoordinates(aPosition); + if (mState.mSelectionStart > mState.mSelectionEnd) + { + std::swap(mState.mSelectionStart, mState.mSelectionEnd); + } +} + +void TextEditor::SetSelection(const Coordinates & aStart, const Coordinates & aEnd, SelectionMode aMode) +{ + auto oldSelStart = mState.mSelectionStart; + auto oldSelEnd = mState.mSelectionEnd; + + mState.mSelectionStart = SanitizeCoordinates(aStart); + mState.mSelectionEnd = SanitizeCoordinates(aEnd); + if (mState.mSelectionStart > mState.mSelectionEnd) + { + std::swap(mState.mSelectionStart, mState.mSelectionEnd); + } + + switch (aMode) + { + case SelectionMode::Normal: + break; + case SelectionMode::Word: + { + mState.mSelectionStart = FindWordStart(mState.mSelectionStart); + if (!IsOnWordBoundary(mState.mSelectionEnd)) + { + mState.mSelectionEnd = FindWordEnd(FindWordStart(mState.mSelectionEnd)); + } + break; + } + case SelectionMode::Line: + { + const auto lineNo = mState.mSelectionEnd.mLine; + const auto lineSize = static_cast(lineNo) < mLines.size() ? mLines[lineNo].size() : 0; + mState.mSelectionStart = Coordinates(mState.mSelectionStart.mLine, 0); + mState.mSelectionEnd = Coordinates(lineNo, GetLineMaxColumn(lineNo)); + break; + } + default: + break; + } + + if (mState.mSelectionStart != oldSelStart || + mState.mSelectionEnd != oldSelEnd) + { + mCursorPositionChanged = true; + } +} + +void TextEditor::SetTabSize(int aValue) +{ + mTabSize = std::max(0, std::min(32, aValue)); +} + +void TextEditor::InsertText(const std::string & aValue) +{ + InsertText(aValue.c_str()); +} + +void TextEditor::InsertText(const char* aValue) +{ + if (aValue == nullptr) + { + return; + } + + auto pos = GetActualCursorCoordinates(); + auto start = std::min(pos, mState.mSelectionStart); + int totalLines = pos.mLine - start.mLine; + + totalLines += InsertTextAt(pos, aValue); + + SetSelection(pos, pos); + SetCursorPosition(pos); + Colorize(start.mLine - 1, totalLines + 2); +} + +void TextEditor::DeleteSelection() +{ + assert(mState.mSelectionEnd >= mState.mSelectionStart); + + if (mState.mSelectionEnd == mState.mSelectionStart) + { + return; + } + + DeleteRange(mState.mSelectionStart, mState.mSelectionEnd); + + SetSelection(mState.mSelectionStart, mState.mSelectionStart); + SetCursorPosition(mState.mSelectionStart); + Colorize(mState.mSelectionStart.mLine, 1); +} + +void TextEditor::MoveUp(int aAmount, bool aSelect) +{ + auto oldPos = mState.mCursorPosition; + mState.mCursorPosition.mLine = std::max(0, mState.mCursorPosition.mLine - aAmount); + if (oldPos != mState.mCursorPosition) + { + if (aSelect) + { + if (oldPos == mInteractiveStart) + { + mInteractiveStart = mState.mCursorPosition; + } + else if (oldPos == mInteractiveEnd) + { + mInteractiveEnd = mState.mCursorPosition; + } + else + { + mInteractiveStart = mState.mCursorPosition; + mInteractiveEnd = oldPos; + } + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd); + + EnsureCursorVisible(); + } +} + +void TextEditor::MoveDown(int aAmount, bool aSelect) +{ + assert(mState.mCursorPosition.mColumn >= 0); + auto oldPos = mState.mCursorPosition; + mState.mCursorPosition.mLine = std::max(0, std::min(static_cast(mLines.size()) - 1, mState.mCursorPosition.mLine + aAmount)); + + if (mState.mCursorPosition != oldPos) + { + if (aSelect) + { + if (oldPos == mInteractiveEnd) + { + mInteractiveEnd = mState.mCursorPosition; + } + else if (oldPos == mInteractiveStart) + { + mInteractiveStart = mState.mCursorPosition; + } + else + { + mInteractiveStart = oldPos; + mInteractiveEnd = mState.mCursorPosition; + } + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd); + + EnsureCursorVisible(); + } +} + +static bool IsUTFSequence(char c) +{ + return (c & 0xC0) == 0x80; +} + +void TextEditor::MoveLeft(int aAmount, bool aSelect, bool aWordMode) +{ + if (mLines.empty()) + { + return; + } + + auto oldPos = mState.mCursorPosition; + mState.mCursorPosition = GetActualCursorCoordinates(); + auto line = mState.mCursorPosition.mLine; + auto cindex = GetCharacterIndex(mState.mCursorPosition); + + while (aAmount-- > 0) + { + if (cindex == 0) + { + if (line > 0) + { + --line; + if (static_cast(mLines.size()) > line) + { + cindex = static_cast(mLines[line].size()); + } + else + { + cindex = 0; + } + } + } + else + { + --cindex; + if (cindex > 0) + { + if (static_cast(mLines.size()) > line) + { + while (cindex > 0 && IsUTFSequence(mLines[line][cindex].mChar)) + { + --cindex; + } + } + } + } + + mState.mCursorPosition = Coordinates(line, GetCharacterColumn(line, cindex)); + if (aWordMode) + { + mState.mCursorPosition = FindWordStart(mState.mCursorPosition); + cindex = GetCharacterIndex(mState.mCursorPosition); + } + } + + mState.mCursorPosition = Coordinates(line, GetCharacterColumn(line, cindex)); + + assert(mState.mCursorPosition.mColumn >= 0); + if (aSelect) + { + if (oldPos == mInteractiveStart) + { + mInteractiveStart = mState.mCursorPosition; + } + else if (oldPos == mInteractiveEnd) + { + mInteractiveEnd = mState.mCursorPosition; + } + else + { + mInteractiveStart = mState.mCursorPosition; + mInteractiveEnd = oldPos; + } + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd, aSelect && aWordMode ? SelectionMode::Word : SelectionMode::Normal); + + EnsureCursorVisible(); +} + +void TextEditor::MoveRight(int aAmount, bool aSelect, bool aWordMode) +{ + auto oldPos = mState.mCursorPosition; + + if (mLines.empty() || oldPos.mLine >= mLines.size()) + { + return; + } + + auto cindex = GetCharacterIndex(mState.mCursorPosition); + while (aAmount-- > 0) + { + auto lindex = mState.mCursorPosition.mLine; + auto& line = mLines[lindex]; + + if (cindex >= line.size()) + { + if (mState.mCursorPosition.mLine < mLines.size() - 1) + { + mState.mCursorPosition.mLine = std::max(0, std::min(static_cast(mLines.size()) - 1, mState.mCursorPosition.mLine + 1)); + mState.mCursorPosition.mColumn = 0; + } + else + { + return; + } + } + else + { + cindex += UTF8CharLength(line[cindex].mChar); + mState.mCursorPosition = Coordinates(lindex, GetCharacterColumn(lindex, cindex)); + if (aWordMode) + { + mState.mCursorPosition = FindNextWord(mState.mCursorPosition); + } + } + } + + if (aSelect) + { + if (oldPos == mInteractiveEnd) + { + mInteractiveEnd = SanitizeCoordinates(mState.mCursorPosition); + } + else if (oldPos == mInteractiveStart) + { + mInteractiveStart = mState.mCursorPosition; + } + else + { + mInteractiveStart = oldPos; + mInteractiveEnd = mState.mCursorPosition; + } + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd, aSelect && aWordMode ? SelectionMode::Word : SelectionMode::Normal); + + EnsureCursorVisible(); +} + +void TextEditor::MoveTop(bool aSelect) +{ + auto oldPos = mState.mCursorPosition; + SetCursorPosition(Coordinates(0, 0)); + + if (mState.mCursorPosition != oldPos) + { + if (aSelect) + { + mInteractiveEnd = oldPos; + mInteractiveStart = mState.mCursorPosition; + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd); + } +} + +void TextEditor::MoveBottom(bool aSelect) +{ + auto oldPos = GetCursorPosition(); + auto newPos = Coordinates(static_cast(mLines.size()) - 1, 0); + SetCursorPosition(newPos); + if (aSelect) + { + mInteractiveStart = oldPos; + mInteractiveEnd = newPos; + } + else + { + mInteractiveStart = mInteractiveEnd = newPos; + } + SetSelection(mInteractiveStart, mInteractiveEnd); +} + +void TextEditor::MoveHome(bool aSelect) +{ + auto oldPos = mState.mCursorPosition; + SetCursorPosition(Coordinates(mState.mCursorPosition.mLine, 0)); + + if (mState.mCursorPosition != oldPos) + { + if (aSelect) + { + if (oldPos == mInteractiveStart) + { + mInteractiveStart = mState.mCursorPosition; + } + else if (oldPos == mInteractiveEnd) + { + mInteractiveEnd = mState.mCursorPosition; + } + else + { + mInteractiveStart = mState.mCursorPosition; + mInteractiveEnd = oldPos; + } + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd); + } +} + +void TextEditor::MoveEnd(bool aSelect) +{ + auto oldPos = mState.mCursorPosition; + SetCursorPosition(Coordinates(mState.mCursorPosition.mLine, GetLineMaxColumn(oldPos.mLine))); + + if (mState.mCursorPosition != oldPos) + { + if (aSelect) + { + if (oldPos == mInteractiveEnd) + { + mInteractiveEnd = mState.mCursorPosition; + } + else if (oldPos == mInteractiveStart) + { + mInteractiveStart = mState.mCursorPosition; + } + else + { + mInteractiveStart = oldPos; + mInteractiveEnd = mState.mCursorPosition; + } + } + else + { + mInteractiveStart = mInteractiveEnd = mState.mCursorPosition; + } + SetSelection(mInteractiveStart, mInteractiveEnd); + } +} + +void TextEditor::Delete() +{ + assert(!mReadOnly); + + if (mLines.empty()) + { + return; + } + + UndoRecord u; + u.mBefore = mState; + + if (HasSelection()) + { + u.mRemoved = GetSelectedText(); + u.mRemovedStart = mState.mSelectionStart; + u.mRemovedEnd = mState.mSelectionEnd; + + DeleteSelection(); + } + else + { + auto pos = GetActualCursorCoordinates(); + SetCursorPosition(pos); + auto& line = mLines[pos.mLine]; + + if (pos.mColumn == GetLineMaxColumn(pos.mLine)) + { + if (pos.mLine == static_cast(mLines.size()) - 1) + { + return; + } + + u.mRemoved = '\n'; + u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates(); + Advance(u.mRemovedEnd); + + auto& nextLine = mLines[pos.mLine + 1]; + line.insert(line.end(), nextLine.begin(), nextLine.end()); + RemoveLine(pos.mLine + 1); + } + else + { + auto cindex = GetCharacterIndex(pos); + u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates(); + u.mRemovedEnd.mColumn++; + u.mRemoved = GetText(u.mRemovedStart, u.mRemovedEnd); + + auto d = UTF8CharLength(line[cindex].mChar); + while (d-- > 0 && cindex < static_cast(line.size())) + { + line.erase(line.begin() + cindex); + } + } + + mTextChanged = true; + + Colorize(pos.mLine, 1); + } + + u.mAfter = mState; + AddUndo(u); +} + +void TextEditor::Backspace() +{ + assert(!mReadOnly); + + if (mLines.empty()) + { + return; + } + + UndoRecord u; + u.mBefore = mState; + + if (HasSelection()) + { + u.mRemoved = GetSelectedText(); + u.mRemovedStart = mState.mSelectionStart; + u.mRemovedEnd = mState.mSelectionEnd; + + DeleteSelection(); + } + else + { + auto pos = GetActualCursorCoordinates(); + SetCursorPosition(pos); + + if (mState.mCursorPosition.mColumn == 0) + { + if (mState.mCursorPosition.mLine == 0) + { + return; + } + + u.mRemoved = '\n'; + u.mRemovedStart = u.mRemovedEnd = Coordinates(pos.mLine - 1, GetLineMaxColumn(pos.mLine - 1)); + Advance(u.mRemovedEnd); + + auto& line = mLines[mState.mCursorPosition.mLine]; + auto& prevLine = mLines[mState.mCursorPosition.mLine - 1]; + auto prevSize = GetLineMaxColumn(mState.mCursorPosition.mLine - 1); + prevLine.insert(prevLine.end(), line.begin(), line.end()); + + ErrorMarkers etmp; + for (auto& i : mErrorMarkers) + { + etmp.insert(ErrorMarkers::value_type(i.first - 1 == mState.mCursorPosition.mLine ? i.first - 1 : i.first, i.second)); + } + mErrorMarkers = std::move(etmp); + + RemoveLine(mState.mCursorPosition.mLine); + --mState.mCursorPosition.mLine; + mState.mCursorPosition.mColumn = prevSize; + } + else + { + auto& line = mLines[mState.mCursorPosition.mLine]; + auto cindex = GetCharacterIndex(pos) - 1; + auto cend = cindex + 1; + while (cindex > 0 && IsUTFSequence(line[cindex].mChar)) + { + --cindex; + } + + //if (cindex > 0 && UTF8CharLength(line[cindex].mChar) > 1) + // --cindex; + + u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates(); + --u.mRemovedStart.mColumn; + --mState.mCursorPosition.mColumn; + + while (cindex < line.size() && cend-- > cindex) + { + u.mRemoved += line[cindex].mChar; + line.erase(line.begin() + cindex); + } + } + + mTextChanged = true; + + EnsureCursorVisible(); + Colorize(mState.mCursorPosition.mLine, 1); + } + + u.mAfter = mState; + AddUndo(u); +} + +void TextEditor::SelectWordUnderCursor() +{ + auto c = GetCursorPosition(); + SetSelection(FindWordStart(c), FindWordEnd(c)); +} + +void TextEditor::SelectAll() +{ + SetSelection(Coordinates(0, 0), Coordinates(static_cast(mLines.size()), 0)); +} + +bool TextEditor::HasSelection() const +{ + return mState.mSelectionEnd > mState.mSelectionStart; +} + +void TextEditor::Copy() +{ + if (HasSelection()) + { + ImGui::SetClipboardText(GetSelectedText().c_str()); + } + else + { + if (!mLines.empty()) + { + std::string str; + auto& line = mLines[GetActualCursorCoordinates().mLine]; + for (auto& g : line) + { + str.push_back(g.mChar); + } + ImGui::SetClipboardText(str.c_str()); + } + } +} + +void TextEditor::Cut() +{ + if (IsReadOnly()) + { + Copy(); + } + else + { + if (HasSelection()) + { + UndoRecord u; + u.mBefore = mState; + u.mRemoved = GetSelectedText(); + u.mRemovedStart = mState.mSelectionStart; + u.mRemovedEnd = mState.mSelectionEnd; + + Copy(); + DeleteSelection(); + + u.mAfter = mState; + AddUndo(u); + } + } +} + +void TextEditor::Paste() +{ + if (IsReadOnly()) + { + return; + } + + auto clipText = ImGui::GetClipboardText(); + if (clipText != nullptr && strlen(clipText) > 0) + { + UndoRecord u; + u.mBefore = mState; + + if (HasSelection()) + { + u.mRemoved = GetSelectedText(); + u.mRemovedStart = mState.mSelectionStart; + u.mRemovedEnd = mState.mSelectionEnd; + DeleteSelection(); + } + + u.mAdded = clipText; + u.mAddedStart = GetActualCursorCoordinates(); + + InsertText(clipText); + + u.mAddedEnd = GetActualCursorCoordinates(); + u.mAfter = mState; + AddUndo(u); + } +} + +bool TextEditor::CanUndo() const +{ + return !mReadOnly && mUndoIndex > 0; +} + +bool TextEditor::CanRedo() const +{ + return !mReadOnly && mUndoIndex < static_cast(mUndoBuffer.size()); +} + +void TextEditor::Undo(int aSteps) +{ + while (CanUndo() && aSteps-- > 0) + { + mUndoBuffer[--mUndoIndex].Undo(this); + } +} + +void TextEditor::Redo(int aSteps) +{ + while (CanRedo() && aSteps-- > 0) + { + mUndoBuffer[mUndoIndex++].Redo(this); + } +} + +const TextEditor::Palette& TextEditor::GetDarkPalette() +{ + const static Palette p = { + { + 0xff7f7f7f, // Default + 0xffd69c56, // Keyword + 0xff00ff00, // Number + 0xff7070e0, // String + 0xff70a0e0, // Char literal + 0xffffffff, // Punctuation + 0xff408080, // Preprocessor + 0xffaaaaaa, // Identifier + 0xff9bc64d, // Known identifier + 0xffc040a0, // Preproc identifier + 0xff206020, // Comment (single line) + 0xff406020, // Comment (multi line) + 0xff101010, // Background + 0xffe0e0e0, // Cursor + 0x80a06020, // Selection + 0x800020ff, // ErrorMarker + 0x40f08000, // Breakpoint + 0xff707000, // Line number + 0x40000000, // Current line fill + 0x40808080, // Current line fill (inactive) + 0x40a0a0a0, // Current line edge + } + }; + return p; +} + +const TextEditor::Palette& TextEditor::GetLightPalette() +{ + const static Palette p = { + { + 0xff7f7f7f, // None + 0xffff0c06, // Keyword + 0xff008000, // Number + 0xff2020a0, // String + 0xff304070, // Char literal + 0xff000000, // Punctuation + 0xff406060, // Preprocessor + 0xff404040, // Identifier + 0xff606010, // Known identifier + 0xffc040a0, // Preproc identifier + 0xff205020, // Comment (single line) + 0xff405020, // Comment (multi line) + 0xffffffff, // Background + 0xff000000, // Cursor + 0x80600000, // Selection + 0xa00010ff, // ErrorMarker + 0x80f08000, // Breakpoint + 0xff505000, // Line number + 0x40000000, // Current line fill + 0x40808080, // Current line fill (inactive) + 0x40000000, // Current line edge + } + }; + return p; +} + +const TextEditor::Palette& TextEditor::GetRetroBluePalette() +{ + const static Palette p = { + { + 0xff00ffff, // None + 0xffffff00, // Keyword + 0xff00ff00, // Number + 0xff808000, // String + 0xff808000, // Char literal + 0xffffffff, // Punctuation + 0xff008000, // Preprocessor + 0xff00ffff, // Identifier + 0xffffffff, // Known identifier + 0xffff00ff, // Preproc identifier + 0xff808080, // Comment (single line) + 0xff404040, // Comment (multi line) + 0xff800000, // Background + 0xff0080ff, // Cursor + 0x80ffff00, // Selection + 0xa00000ff, // ErrorMarker + 0x80ff8000, // Breakpoint + 0xff808000, // Line number + 0x40000000, // Current line fill + 0x40808080, // Current line fill (inactive) + 0x40000000, // Current line edge + } + }; + return p; +} + + +std::string TextEditor::GetText() const +{ + return GetText(Coordinates(), Coordinates(static_cast(mLines.size()), 0)); +} + +std::vector TextEditor::GetTextLines() const +{ + std::vector result; + + result.reserve(mLines.size()); + + for (auto& line : mLines) + { + std::string text; + + text.resize(line.size()); + + for (size_t i = 0; i < line.size(); ++i) + { + text[i] = line[i].mChar; + } + + result.emplace_back(std::move(text)); + } + + return result; +} + +std::string TextEditor::GetSelectedText() const +{ + return GetText(mState.mSelectionStart, mState.mSelectionEnd); +} + +std::string TextEditor::GetCurrentLineText() const +{ + auto lineLength = GetLineMaxColumn(mState.mCursorPosition.mLine); + return GetText( + Coordinates(mState.mCursorPosition.mLine, 0), + Coordinates(mState.mCursorPosition.mLine, lineLength)); +} + +void TextEditor::ProcessInputs() {} + +void TextEditor::Colorize(int aFromLine, int aLines) +{ + int toLine = aLines == -1 ? static_cast(mLines.size()) : std::min(static_cast(mLines.size()), aFromLine + aLines); + mColorRangeMin = std::min(mColorRangeMin, aFromLine); + mColorRangeMax = std::max(mColorRangeMax, toLine); + mColorRangeMin = std::max(0, mColorRangeMin); + mColorRangeMax = std::max(mColorRangeMin, mColorRangeMax); + mCheckComments = true; +} + +void TextEditor::ColorizeRange(int aFromLine, int aToLine) +{ + if (mLines.empty() || aFromLine >= aToLine) + { + return; + } + + std::string buffer; + std::cmatch results; + std::string id; + + int endLine = std::max(0, std::min(static_cast(mLines.size()), aToLine)); + for (int i = aFromLine; i < endLine; ++i) + { + auto& line = mLines[i]; + + if (line.empty()) + { + continue; + } + + buffer.resize(line.size()); + for (size_t j = 0; j < line.size(); ++j) + { + auto& col = line[j]; + buffer[j] = col.mChar; + col.mColorIndex = PaletteIndex::Default; + } + + const char* bufferBegin = &buffer.front(); + const char* bufferEnd = bufferBegin + buffer.size(); + + auto last = bufferEnd; + + for (auto first = bufferBegin; first != last;) + { + const char* token_begin = nullptr; + const char* token_end = nullptr; + auto token_color = PaletteIndex::Default; + + bool hasTokenizeResult = false; + + if (mLanguageDefinition.mTokenize != nullptr) + { + if (mLanguageDefinition.mTokenize(first, last, token_begin, token_end, token_color)) + { + hasTokenizeResult = true; + } + } + + if (hasTokenizeResult == false) + { + // todo : remove + //printf("using regex for %.*s\n", first + 10 < last ? 10 : int(last - first), first); + + for (auto& p : mRegexList) + { + if (std::regex_search(first, last, results, p.first, std::regex_constants::match_continuous)) + { + hasTokenizeResult = true; + + auto& v = *results.begin(); + token_begin = v.first; + token_end = v.second; + token_color = p.second; + break; + } + } + } + + if (hasTokenizeResult == false) + { + first++; + } + else + { + const size_t token_length = token_end - token_begin; + + if (token_color == PaletteIndex::Identifier) + { + id.assign(token_begin, token_end); + + // todo : allmost all language definitions use lower case to specify keywords, so shouldn't this use ::tolower ? + if (!mLanguageDefinition.mCaseSensitive) + { + std::transform(id.begin(), id.end(), id.begin(), toupper); + } + + if (!line[first - bufferBegin].mPreprocessor) + { + if (mLanguageDefinition.mKeywords.count(id) != 0) + { + token_color = PaletteIndex::Keyword; + } + else if (mLanguageDefinition.mIdentifiers.count(id) != 0) + { + token_color = PaletteIndex::KnownIdentifier; + } + else if (mLanguageDefinition.mPreprocIdentifiers.count(id) != 0) + { + token_color = PaletteIndex::PreprocIdentifier; + } + } + else + { + if (mLanguageDefinition.mPreprocIdentifiers.count(id) != 0) + { + token_color = PaletteIndex::PreprocIdentifier; + } + } + } + + for (size_t j = 0; j < token_length; ++j) + { + line[(token_begin - bufferBegin) + j].mColorIndex = token_color; + } + + first = token_end; + } + } + } +} + +void TextEditor::ColorizeInternal() +{ + if (mLines.empty() || !mColorizerEnabled) + { + return; + } + + if (mCheckComments) + { + auto endLine = mLines.size(); + auto endIndex = 0; + auto commentStartLine = endLine; + auto commentStartIndex = endIndex; + auto withinString = false; + auto withinSingleLineComment = false; + auto withinPreproc = false; + auto firstChar = true; // there is no other non-whitespace characters in the line before + auto concatenate = false; // '\' on the very end of the line + auto currentLine = 0; + auto currentIndex = 0; + while (currentLine < endLine || currentIndex < endIndex) + { + auto& line = mLines[currentLine]; + + if (currentIndex == 0 && !concatenate) + { + withinSingleLineComment = false; + withinPreproc = false; + firstChar = true; + } + + concatenate = false; + + if (!line.empty()) + { + auto& g = line[currentIndex]; + auto c = g.mChar; + + if (c != mLanguageDefinition.mPreprocChar && !isspace(c)) + { + firstChar = false; + } + + if (currentIndex == static_cast(line.size()) - 1 && line[line.size() - 1].mChar == '\\') + { + concatenate = true; + } + + bool inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex)); + + if (withinString) + { + line[currentIndex].mMultiLineComment = inComment; + + if (c == '\"') + { + if (currentIndex + 1 < static_cast(line.size()) && line[currentIndex + 1].mChar == '\"') + { + currentIndex += 1; + if (currentIndex < static_cast(line.size())) + { + line[currentIndex].mMultiLineComment = inComment; + } + } + else + { + withinString = false; + } + } + else if (c == '\\') + { + currentIndex += 1; + if (currentIndex < static_cast(line.size())) + { + line[currentIndex].mMultiLineComment = inComment; + } + } + } + else + { + if (firstChar && c == mLanguageDefinition.mPreprocChar) + { + withinPreproc = true; + } + + if (c == '\"') + { + withinString = true; + line[currentIndex].mMultiLineComment = inComment; + } + else + { + auto pred = [](const char& a, const Glyph& b) { return a == b.mChar; }; + auto from = line.begin() + currentIndex; + auto& startStr = mLanguageDefinition.mCommentStart; + auto& singleStartStr = mLanguageDefinition.mSingleLineComment; + + if (singleStartStr.size() > 0 && + currentIndex + singleStartStr.size() <= line.size() && + equals(singleStartStr.begin(), singleStartStr.end(), from, from + singleStartStr.size(), pred)) + { + withinSingleLineComment = true; + } + else if (!withinSingleLineComment && currentIndex + startStr.size() <= line.size() && + equals(startStr.begin(), startStr.end(), from, from + startStr.size(), pred)) + { + commentStartLine = currentLine; + commentStartIndex = currentIndex; + } + + inComment = inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex)); + + line[currentIndex].mMultiLineComment = inComment; + line[currentIndex].mComment = withinSingleLineComment; + + auto& endStr = mLanguageDefinition.mCommentEnd; + if (currentIndex + 1 >= static_cast(endStr.size()) && + equals(endStr.begin(), endStr.end(), from + 1 - endStr.size(), from + 1, pred)) + { + commentStartIndex = endIndex; + commentStartLine = endLine; + } + } + } + line[currentIndex].mPreprocessor = withinPreproc; + currentIndex += UTF8CharLength(c); + if (currentIndex >= static_cast(line.size())) + { + currentIndex = 0; + ++currentLine; + } + } + else + { + currentIndex = 0; + ++currentLine; + } + } + mCheckComments = false; + } + + if (mColorRangeMin < mColorRangeMax) + { + const int increment = (mLanguageDefinition.mTokenize == nullptr) ? 10 : 10000; + const int to = std::min(mColorRangeMin + increment, mColorRangeMax); + ColorizeRange(mColorRangeMin, to); + mColorRangeMin = to; + + if (mColorRangeMax == mColorRangeMin) + { + mColorRangeMin = std::numeric_limits::max(); + mColorRangeMax = 0; + } + } +} + +float TextEditor::TextDistanceToLineStart(const Coordinates & aFrom) const +{ + auto& line = mLines[aFrom.mLine]; + float distance = 0.0f; + float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x; + int colIndex = GetCharacterIndex(aFrom); + for (size_t it = 0u; it < line.size() && it < colIndex;) + { + if (line[it].mChar == '\t') + { + distance = (1.0f + std::floor((1.0f + distance) / (static_cast(mTabSize) * spaceSize))) * (static_cast(mTabSize) * spaceSize); + ++it; + } + else + { + auto d = UTF8CharLength(line[it].mChar); + char tempCString[7]; + int i = 0; + for (; i < 6 && d-- > 0 && it < static_cast(line.size()); i++, it++) + { + tempCString[i] = line[it].mChar; + } + + tempCString[i] = '\0'; + distance += ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, tempCString, nullptr, nullptr).x; + } + } + + return distance; +} + +void TextEditor::EnsureCursorVisible() +{ + if (!mWithinRender) + { + mScrollToCursor = true; + return; + } + + float scrollX = ImGui::GetScrollX(); + float scrollY = ImGui::GetScrollY(); + + auto height = ImGui::GetWindowHeight(); + auto width = ImGui::GetWindowWidth(); + + auto top = 1 + static_cast(ceil(scrollY / mCharAdvance.y)); + auto bottom = static_cast(ceil((scrollY + height) / mCharAdvance.y)); + + auto left = static_cast(ceil(scrollX / mCharAdvance.x)); + auto right = static_cast(ceil((scrollX + width) / mCharAdvance.x)); + + auto pos = GetActualCursorCoordinates(); + auto len = TextDistanceToLineStart(pos); + + if (pos.mLine < top) + { + ImGui::SetScrollY(std::max(0.0f, (pos.mLine - 1) * mCharAdvance.y)); + } + if (pos.mLine > bottom - 4) + { + ImGui::SetScrollY(std::max(0.0f, (pos.mLine + 4) * mCharAdvance.y - height)); + } + if (len + mTextStart < left + 4) + { + ImGui::SetScrollX(std::max(0.0f, len + mTextStart - 4)); + } + if (len + mTextStart > right - 4) + { + ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width)); + } +} + +int TextEditor::GetPageSize() const +{ + auto height = ImGui::GetWindowHeight() - 20.0f; + return static_cast(floor(height / mCharAdvance.y)); +} + +TextEditor::UndoRecord::UndoRecord( + const std::string & aAdded, + const Coordinates aAddedStart, + const Coordinates aAddedEnd, + const std::string & aRemoved, + const Coordinates aRemovedStart, + const Coordinates aRemovedEnd, + EditorState & aBefore, + EditorState & aAfter) + : mAdded(aAdded) + , mAddedStart(aAddedStart) + , mAddedEnd(aAddedEnd) + , mRemoved(aRemoved) + , mRemovedStart(aRemovedStart) + , mRemovedEnd(aRemovedEnd) + , mBefore(aBefore) + , mAfter(aAfter) +{ + assert(mAddedStart <= mAddedEnd); + assert(mRemovedStart <= mRemovedEnd); +} + +void TextEditor::UndoRecord::Undo(TextEditor * aEditor) +{ + if (!mAdded.empty()) + { + aEditor->DeleteRange(mAddedStart, mAddedEnd); + aEditor->Colorize(mAddedStart.mLine - 1, mAddedEnd.mLine - mAddedStart.mLine + 2); + } + + if (!mRemoved.empty()) + { + auto start = mRemovedStart; + aEditor->InsertTextAt(start, mRemoved.c_str()); + aEditor->Colorize(mRemovedStart.mLine - 1, mRemovedEnd.mLine - mRemovedStart.mLine + 2); + } + + aEditor->mState = mBefore; + aEditor->EnsureCursorVisible(); +} + +void TextEditor::UndoRecord::Redo(TextEditor * aEditor) +{ + if (!mRemoved.empty()) + { + aEditor->DeleteRange(mRemovedStart, mRemovedEnd); + aEditor->Colorize(mRemovedStart.mLine - 1, mRemovedEnd.mLine - mRemovedStart.mLine + 1); + } + + if (!mAdded.empty()) + { + auto start = mAddedStart; + aEditor->InsertTextAt(start, mAdded.c_str()); + aEditor->Colorize(mAddedStart.mLine - 1, mAddedEnd.mLine - mAddedStart.mLine + 1); + } + + aEditor->mState = mAfter; + aEditor->EnsureCursorVisible(); +} + +static bool TokenizeCStyleString(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end) +{ + const char* p = in_begin; + + if (*p == '"') + { + p++; + + while (p < in_end) + { + // handle end of string + if (*p == '"') + { + out_begin = in_begin; + out_end = p + 1; + return true; + } + + // handle escape character for " + if (*p == '\\' && p + 1 < in_end && p[1] == '"') + { + p++; + } + + p++; + } + } + + return false; +} + +static bool TokenizeCStyleCharacterLiteral(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end) +{ + const char* p = in_begin; + + if (*p == '\'') + { + p++; + + // handle escape characters + if (p < in_end && *p == '\\') + { + p++; + } + + if (p < in_end) + { + p++; + } + + // handle end of character literal + if (p < in_end && *p == '\'') + { + out_begin = in_begin; + out_end = p + 1; + return true; + } + } + + return false; +} + +static bool TokenizeCStyleIdentifier(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end) +{ + const char* p = in_begin; + + if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '_') + { + p++; + + while ((p < in_end) && ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_')) + { + p++; + } + + out_begin = in_begin; + out_end = p; + return true; + } + + return false; +} + +static bool TokenizeCStyleNumber(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end) +{ + const char* p = in_begin; + + const bool startsWithNumber = *p >= '0' && *p <= '9'; + + if (*p != '+' && *p != '-' && !startsWithNumber) + { + return false; + } + + p++; + + bool hasNumber = startsWithNumber; + + while (p < in_end && (*p >= '0' && *p <= '9')) + { + hasNumber = true; + + p++; + } + + if (hasNumber == false) + { + return false; + } + + bool isFloat = false; + bool isHex = false; + bool isBinary = false; + + if (p < in_end) + { + if (*p == '.') + { + isFloat = true; + + p++; + + while (p < in_end && (*p >= '0' && *p <= '9')) + { + p++; + } + } + else if (*p == 'x' || *p == 'X') + { + // hex formatted integer of the type 0xef80 + + isHex = true; + + p++; + + while (p < in_end && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) + { + p++; + } + } + else if (*p == 'b' || *p == 'B') + { + // binary formatted integer of the type 0b01011101 + + isBinary = true; + + p++; + + while (p < in_end && (*p >= '0' && *p <= '1')) + { + p++; + } + } + } + + if (isHex == false && isBinary == false) + { + // floating point exponent + if (p < in_end && (*p == 'e' || *p == 'E')) + { + isFloat = true; + + p++; + + if (p < in_end && (*p == '+' || *p == '-')) + { + p++; + } + + bool hasDigits = false; + + while (p < in_end && (*p >= '0' && *p <= '9')) + { + hasDigits = true; + + p++; + } + + if (hasDigits == false) + { + return false; + } + } + + // single precision floating point type + if (p < in_end && *p == 'f') + { + p++; + } + } + + if (isFloat == false) + { + // integer size type + while (p < in_end && (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L')) + { + p++; + } + } + + out_begin = in_begin; + out_end = p; + return true; +} + +static bool TokenizeCStylePunctuation(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end) +{ + (void)in_end; + + switch (*in_begin) + { + case '[': + case ']': + case '{': + case '}': + case '!': + case '%': + case '^': + case '&': + case '*': + case '(': + case ')': + case '-': + case '+': + case '=': + case '~': + case '|': + case '<': + case '>': + case '?': + case ':': + case '/': + case ';': + case ',': + case '.': + out_begin = in_begin; + out_end = in_begin + 1; + return true; + } + + return false; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const cppKeywords[] = { + "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", + "char32_t", "class", + "compl", "concept", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", + "false", "float", + "for", "friend", "goto", "if", "import", "inline", "int", "long", "module", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", + "protected", "public", + "register", "reinterpret_cast", "requires", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "synchronized", "template", "this", + "thread_local", + "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" + }; + for (auto& k : cppKeywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", + "isalpha", "isdigit", "isgraph", + "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "printf", "sprintf", "snprintf", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", + "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper", + "std", "string", "vector", "map", "unordered_map", "set", "unordered_set", "min", "max" + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenize = [](const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end, PaletteIndex& paletteIndex) -> bool + { + paletteIndex = PaletteIndex::Max; + + while (in_begin < in_end && isascii(*in_begin) && isblank(*in_begin)) + { + in_begin++; + } + + if (in_begin == in_end) + { + out_begin = in_end; + out_end = in_end; + paletteIndex = PaletteIndex::Default; + } + else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::String; + } + else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::CharLiteral; + } + else if (TokenizeCStyleIdentifier(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::Identifier; + } + else if (TokenizeCStyleNumber(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::Number; + } + else if (TokenizeCStylePunctuation(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::Punctuation; + } + + return paletteIndex != PaletteIndex::Max; + }; + + langDef.mCommentStart = "/*"; + langDef.mCommentEnd = "*/"; + langDef.mSingleLineComment = "//"; + + langDef.mCaseSensitive = true; + langDef.mAutoIndentation = true; + + langDef.mName = "C++"; + + inited = true; + } + return langDef; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::HLSL() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const keywords[] = { + "AppendStructuredBuffer", "asm", "asm_fragment", "BlendState", "bool", "break", "Buffer", "ByteAddressBuffer", "case", "cbuffer", "centroid", "class", "column_major", "compile", + "compile_fragment", + "CompileShader", "const", "continue", "ComputeShader", "ConsumeStructuredBuffer", "default", "DepthStencilState", "DepthStencilView", "discard", "do", "double", "DomainShader", "dword", + "else", + "export", "extern", "false", "float", "for", "fxgroup", "GeometryShader", "groupshared", "half", "Hullshader", "if", "in", "inline", "inout", "InputPatch", "int", "interface", "line", + "lineadj", + "linear", "LineStream", "matrix", "min16float", "min10float", "min16int", "min12int", "min16uint", "namespace", "nointerpolation", "noperspective", "NULL", "out", "OutputPatch", + "packoffset", + "pass", "pixelfragment", "PixelShader", "point", "PointStream", "precise", "RasterizerState", "RenderTargetView", "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer", + "RWStructuredBuffer", + "RWTexture1D", "RWTexture1DArray", "RWTexture2D", "RWTexture2DArray", "RWTexture3D", "sample", "sampler", "SamplerState", "SamplerComparisonState", "shared", "snorm", "stateblock", + "stateblock_state", + "static", "string", "struct", "switch", "StructuredBuffer", "tbuffer", "technique", "technique10", "technique11", "texture", "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray", + "Texture2DMS", + "Texture2DMSArray", "Texture3D", "TextureCube", "TextureCubeArray", "true", "typedef", "triangle", "triangleadj", "TriangleStream", "uint", "uniform", "unorm", "unsigned", "vector", + "vertexfragment", + "VertexShader", "void", "volatile", "while", + "bool1", "bool2", "bool3", "bool4", "double1", "double2", "double3", "double4", "float1", "float2", "float3", "float4", "int1", "int2", "int3", "int4", "in", "out", "inout", + "uint1", "uint2", "uint3", "uint4", "dword1", "dword2", "dword3", "dword4", "half1", "half2", "half3", "half4", + "float1x1", "float2x1", "float3x1", "float4x1", "float1x2", "float2x2", "float3x2", "float4x2", + "float1x3", "float2x3", "float3x3", "float4x3", "float1x4", "float2x4", "float3x4", "float4x4", + "half1x1", "half2x1", "half3x1", "half4x1", "half1x2", "half2x2", "half3x2", "half4x2", + "half1x3", "half2x3", "half3x3", "half4x3", "half1x4", "half2x4", "half3x4", "half4x4", + }; + for (auto& k : keywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "abort", "abs", "acos", "all", "AllMemoryBarrier", "AllMemoryBarrierWithGroupSync", "any", "asdouble", "asfloat", "asin", "asint", "asint", "asuint", + "asuint", "atan", "atan2", "ceil", "CheckAccessFullyMapped", "clamp", "clip", "cos", "cosh", "countbits", "cross", "D3DCOLORtoUBYTE4", "ddx", + "ddx_coarse", "ddx_fine", "ddy", "ddy_coarse", "ddy_fine", "degrees", "determinant", "DeviceMemoryBarrier", "DeviceMemoryBarrierWithGroupSync", + "distance", "dot", "dst", "errorf", "EvaluateAttributeAtCentroid", "EvaluateAttributeAtSample", "EvaluateAttributeSnapped", "exp", "exp2", + "f16tof32", "f32tof16", "faceforward", "firstbithigh", "firstbitlow", "floor", "fma", "fmod", "frac", "frexp", "fwidth", "GetRenderTargetSampleCount", + "GetRenderTargetSamplePosition", "GroupMemoryBarrier", "GroupMemoryBarrierWithGroupSync", "InterlockedAdd", "InterlockedAnd", "InterlockedCompareExchange", + "InterlockedCompareStore", "InterlockedExchange", "InterlockedMax", "InterlockedMin", "InterlockedOr", "InterlockedXor", "isfinite", "isinf", "isnan", + "ldexp", "length", "lerp", "lit", "log", "log10", "log2", "mad", "max", "min", "modf", "msad4", "mul", "noise", "normalize", "pow", "printf", + "Process2DQuadTessFactorsAvg", "Process2DQuadTessFactorsMax", "Process2DQuadTessFactorsMin", "ProcessIsolineTessFactors", "ProcessQuadTessFactorsAvg", + "ProcessQuadTessFactorsMax", "ProcessQuadTessFactorsMin", "ProcessTriTessFactorsAvg", "ProcessTriTessFactorsMax", "ProcessTriTessFactorsMin", + "radians", "rcp", "reflect", "refract", "reversebits", "round", "rsqrt", "saturate", "sign", "sin", "sincos", "sinh", "smoothstep", "sqrt", "step", + "tan", "tanh", "tex1D", "tex1D", "tex1Dbias", "tex1Dgrad", "tex1Dlod", "tex1Dproj", "tex2D", "tex2D", "tex2Dbias", "tex2Dgrad", "tex2Dlod", "tex2Dproj", + "tex3D", "tex3D", "tex3Dbias", "tex3Dgrad", "tex3Dlod", "tex3Dproj", "texCUBE", "texCUBE", "texCUBEbias", "texCUBEgrad", "texCUBElod", "texCUBEproj", "transpose", "trunc" + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenRegexStrings.push_back(std::make_pair("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor)); + langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); + + langDef.mCommentStart = "/*"; + langDef.mCommentEnd = "*/"; + langDef.mSingleLineComment = "//"; + + langDef.mCaseSensitive = true; + langDef.mAutoIndentation = true; + + langDef.mName = "HLSL"; + + inited = true; + } + return langDef; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::GLSL() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const keywords[] = { + "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", + "return", "short", + "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", + "_Imaginary", + "_Noreturn", "_Static_assert", "_Thread_local" + }; + for (auto& k : keywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", + "isalpha", "isdigit", "isgraph", + "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", + "strcmp", "strerror", "time", "tolower", "toupper" + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenRegexStrings.push_back(std::make_pair("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor)); + langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); + + langDef.mCommentStart = "/*"; + langDef.mCommentEnd = "*/"; + langDef.mSingleLineComment = "//"; + + langDef.mCaseSensitive = true; + langDef.mAutoIndentation = true; + + langDef.mName = "GLSL"; + + inited = true; + } + return langDef; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::C() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const keywords[] = { + "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", + "return", "short", + "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", + "_Imaginary", + "_Noreturn", "_Static_assert", "_Thread_local" + }; + for (auto& k : keywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", + "isalpha", "isdigit", "isgraph", + "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", + "strcmp", "strerror", "time", "tolower", "toupper" + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenize = [](const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end, PaletteIndex& paletteIndex) -> bool + { + paletteIndex = PaletteIndex::Max; + + while (in_begin < in_end && isascii(*in_begin) && isblank(*in_begin)) + { + in_begin++; + } + + if (in_begin == in_end) + { + out_begin = in_end; + out_end = in_end; + paletteIndex = PaletteIndex::Default; + } + else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::String; + } + else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::CharLiteral; + } + else if (TokenizeCStyleIdentifier(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::Identifier; + } + else if (TokenizeCStyleNumber(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::Number; + } + else if (TokenizeCStylePunctuation(in_begin, in_end, out_begin, out_end)) + { + paletteIndex = PaletteIndex::Punctuation; + } + + return paletteIndex != PaletteIndex::Max; + }; + + langDef.mCommentStart = "/*"; + langDef.mCommentEnd = "*/"; + langDef.mSingleLineComment = "//"; + + langDef.mCaseSensitive = true; + langDef.mAutoIndentation = true; + + langDef.mName = "C"; + + inited = true; + } + return langDef; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::SQL() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const keywords[] = { + "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", + "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", + "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", + "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", + "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", + "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", + "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", + "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", + "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", + "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT" + }; + + for (auto& k : keywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "ABS", "ACOS", "ADD_MONTHS", "ASCII", "ASCIISTR", "ASIN", "ATAN", "ATAN2", "AVG", "BFILENAME", "BIN_TO_NUM", "BITAND", "CARDINALITY", "CASE", "CAST", "CEIL", + "CHARTOROWID", "CHR", "COALESCE", "COMPOSE", "CONCAT", "CONVERT", "CORR", "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CUME_DIST", "CURRENT_DATE", + "CURRENT_TIMESTAMP", "DBTIMEZONE", "DECODE", "DECOMPOSE", "DENSE_RANK", "DUMP", "EMPTY_BLOB", "EMPTY_CLOB", "EXP", "EXTRACT", "FIRST_VALUE", "FLOOR", "FROM_TZ", "GREATEST", + "GROUP_ID", "HEXTORAW", "INITCAP", "INSTR", "INSTR2", "INSTR4", "INSTRB", "INSTRC", "LAG", "LAST_DAY", "LAST_VALUE", "LEAD", "LEAST", "LENGTH", "LENGTH2", "LENGTH4", + "LENGTHB", "LENGTHC", "LISTAGG", "LN", "LNNVL", "LOCALTIMESTAMP", "LOG", "LOWER", "LPAD", "LTRIM", "MAX", "MEDIAN", "MIN", "MOD", "MONTHS_BETWEEN", "NANVL", "NCHR", + "NEW_TIME", "NEXT_DAY", "NTH_VALUE", "NULLIF", "NUMTODSINTERVAL", "NUMTOYMINTERVAL", "NVL", "NVL2", "POWER", "RANK", "RAWTOHEX", "REGEXP_COUNT", "REGEXP_INSTR", + "REGEXP_REPLACE", "REGEXP_SUBSTR", "REMAINDER", "REPLACE", "ROUND", "ROWNUM", "RPAD", "RTRIM", "SESSIONTIMEZONE", "SIGN", "SIN", "SINH", + "SOUNDEX", "SQRT", "STDDEV", "SUBSTR", "SUM", "SYS_CONTEXT", "SYSDATE", "SYSTIMESTAMP", "TAN", "TANH", "TO_CHAR", "TO_CLOB", "TO_DATE", "TO_DSINTERVAL", "TO_LOB", + "TO_MULTI_BYTE", "TO_NCLOB", "TO_NUMBER", "TO_SINGLE_BYTE", "TO_TIMESTAMP", "TO_TIMESTAMP_TZ", "TO_YMINTERVAL", "TRANSLATE", "TRIM", "TRUNC", "TZ_OFFSET", "UID", "UPPER", + "USER", "USERENV", "VAR_POP", "VAR_SAMP", "VARIANCE", "VSIZE " + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("\\\'[^\\\']*\\\'", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); + + langDef.mCommentStart = "/*"; + langDef.mCommentEnd = "*/"; + langDef.mSingleLineComment = "//"; + + langDef.mCaseSensitive = false; + langDef.mAutoIndentation = false; + + langDef.mName = "SQL"; + + inited = true; + } + return langDef; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::AngelScript() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const keywords[] = { + "and", "abstract", "auto", "bool", "break", "case", "cast", "class", "const", "continue", "default", "do", "double", "else", "enum", "false", "final", "float", "for", + "from", "funcdef", "function", "get", "if", "import", "in", "inout", "int", "interface", "int8", "int16", "int32", "int64", "is", "mixin", "namespace", "not", + "null", "or", "out", "override", "private", "protected", "return", "set", "shared", "super", "switch", "this ", "true", "typedef", "uint", "uint8", "uint16", "uint32", + "uint64", "void", "while", "xor" + }; + + for (auto& k : keywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "cos", "sin", "tab", "acos", "asin", "atan", "atan2", "cosh", "sinh", "tanh", "log", "log10", "pow", "sqrt", "abs", "ceil", "floor", "fraction", "closeTo", "fpFromIEEE", "fpToIEEE", + "complex", "opEquals", "opAddAssign", "opSubAssign", "opMulAssign", "opDivAssign", "opAdd", "opSub", "opMul", "opDiv" + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("\\'\\\\?[^\\']\\'", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); + + langDef.mCommentStart = "/*"; + langDef.mCommentEnd = "*/"; + langDef.mSingleLineComment = "//"; + + langDef.mCaseSensitive = true; + langDef.mAutoIndentation = true; + + langDef.mName = "AngelScript"; + + inited = true; + } + return langDef; +} + +const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::Lua() +{ + static bool inited = false; + static LanguageDefinition langDef; + if (!inited) + { + static const char* const keywords[] = { + "and", "break", "do", "", "else", "elseif", "end", "false", "for", "function", "if", "in", "", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" + }; + + for (auto& k : keywords) + { + langDef.mKeywords.insert(k); + } + + static const char* const identifiers[] = { + "assert", "collectgarbage", "dofile", "error", "getmetatable", "ipairs", "loadfile", "load", "loadstring", "next", "pairs", "pcall", "print", "rawequal", "rawlen", "rawget", "rawset", + "select", "setmetatable", "tonumber", "tostring", "type", "xpcall", "_G", "_VERSION", "arshift", "band", "bnot", "bor", "bxor", "btest", "extract", "lrotate", "lshift", "replace", + "rrotate", "rshift", "create", "resume", "running", "status", "wrap", "yield", "isyieldable", "debug", "getuservalue", "gethook", "getinfo", "getlocal", "getregistry", "getmetatable", + "getupvalue", "upvaluejoin", "upvalueid", "setuservalue", "sethook", "setlocal", "setmetatable", "setupvalue", "traceback", "close", "flush", "input", "lines", "open", "output", "popen", + "read", "tmpfile", "type", "write", "close", "flush", "lines", "read", "seek", "setvbuf", "write", "__gc", "__tostring", "abs", "acos", "asin", "atan", "ceil", "cos", "deg", "exp", + "tointeger", + "floor", "fmod", "ult", "log", "max", "min", "modf", "rad", "random", "randomseed", "sin", "sqrt", "string", "tan", "type", "atan2", "cosh", "sinh", "tanh", + "pow", "frexp", "ldexp", "log10", "pi", "huge", "maxinteger", "mininteger", "loadlib", "searchpath", "seeall", "preload", "cpath", "path", "searchers", "loaded", "module", "require", + "clock", + "date", "difftime", "execute", "exit", "getenv", "remove", "rename", "setlocale", "time", "tmpname", "byte", "char", "dump", "find", "format", "gmatch", "gsub", "len", "lower", "match", + "rep", + "reverse", "sub", "upper", "pack", "packsize", "unpack", "concat", "maxn", "insert", "pack", "unpack", "remove", "move", "sort", "offset", "codepoint", "char", "len", "codes", + "charpattern", + "coroutine", "table", "io", "os", "string", "utf8", "bit32", "math", "debug", "package" + }; + for (auto& k : identifiers) + { + Identifier id; + id.mDeclaration = "Built-in function"; + langDef.mIdentifiers.insert(std::make_pair(std::string(k), id)); + } + + langDef.mTokenRegexStrings.push_back(std::make_pair("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("\\\'[^\\\']*\\\'", PaletteIndex::String)); + langDef.mTokenRegexStrings.push_back(std::make_pair("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier)); + langDef.mTokenRegexStrings.push_back(std::make_pair("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation)); + + langDef.mCommentStart = "--[["; + langDef.mCommentEnd = "]]"; + langDef.mSingleLineComment = "--"; + + langDef.mCaseSensitive = true; + langDef.mAutoIndentation = false; + + langDef.mName = "Lua"; + + inited = true; + } + return langDef; +} + +#pragma warning( pop ) \ No newline at end of file diff --git a/Amalgam/include/ImGui/TextEditor.h b/Amalgam/include/ImGui/TextEditor.h new file mode 100644 index 0000000..7e2b1aa --- /dev/null +++ b/Amalgam/include/ImGui/TextEditor.h @@ -0,0 +1,406 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "imgui.h" + +class TextEditor +{ +public: + enum class PaletteIndex + { + Default, + Keyword, + Number, + String, + CharLiteral, + Punctuation, + Preprocessor, + Identifier, + KnownIdentifier, + PreprocIdentifier, + Comment, + MultiLineComment, + Background, + Cursor, + Selection, + ErrorMarker, + Breakpoint, + LineNumber, + CurrentLineFill, + CurrentLineFillInactive, + CurrentLineEdge, + Max + }; + + enum class SelectionMode + { + Normal, + Word, + Line + }; + + struct Breakpoint + { + int mLine; + bool mEnabled; + std::string mCondition; + + Breakpoint() + : mLine(-1) + , mEnabled(false) + { + } + }; + + // Represents a character coordinate from the user's point of view, + // i. e. consider an uniform grid (assuming fixed-width font) on the + // screen as it is rendered, and each cell has its own coordinate, starting from 0. + // Tabs are counted as [1..mTabSize] count empty spaces, depending on + // how many space is necessary to reach the next tab stop. + // For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4, + // because it is rendered as " ABC" on the screen. + struct Coordinates + { + int mLine, mColumn; + Coordinates() : mLine(0), mColumn(0) {} + + Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn) + { + assert(aLine >= 0); + assert(aColumn >= 0); + } + + static Coordinates Invalid() + { + static Coordinates invalid(-1, -1); + return invalid; + } + + bool operator ==(const Coordinates& o) const + { + return + mLine == o.mLine && + mColumn == o.mColumn; + } + + bool operator !=(const Coordinates& o) const + { + return + mLine != o.mLine || + mColumn != o.mColumn; + } + + bool operator <(const Coordinates& o) const + { + if (mLine != o.mLine) + { + return mLine < o.mLine; + } + return mColumn < o.mColumn; + } + + bool operator >(const Coordinates& o) const + { + if (mLine != o.mLine) + { + return mLine > o.mLine; + } + return mColumn > o.mColumn; + } + + bool operator <=(const Coordinates& o) const + { + if (mLine != o.mLine) + { + return mLine < o.mLine; + } + return mColumn <= o.mColumn; + } + + bool operator >=(const Coordinates& o) const + { + if (mLine != o.mLine) + { + return mLine > o.mLine; + } + return mColumn >= o.mColumn; + } + }; + + struct Identifier + { + Coordinates mLocation; + std::string mDeclaration; + }; + + using String = std::string; + using Identifiers = std::unordered_map; + using Keywords = std::unordered_set; + using ErrorMarkers = std::map; + using Breakpoints = std::unordered_set; + using Palette = std::array(PaletteIndex::Max)>; + using Char = uint8_t; + + struct Glyph + { + Char mChar; + PaletteIndex mColorIndex = PaletteIndex::Default; + bool mComment : 1; + bool mMultiLineComment : 1; + bool mPreprocessor : 1; + + Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex), + mComment(false), mMultiLineComment(false), mPreprocessor(false) + { + } + }; + + using Line = std::vector; + using Lines = std::vector; + + struct LanguageDefinition + { + using TokenRegexString = std::pair; + using TokenRegexStrings = std::vector; + using TokenizeCallback = bool(*)(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end, PaletteIndex& paletteIndex); + + std::string mName; + Keywords mKeywords; + Identifiers mIdentifiers; + Identifiers mPreprocIdentifiers; + std::string mCommentStart, mCommentEnd, mSingleLineComment; + char mPreprocChar; + bool mAutoIndentation; + + TokenizeCallback mTokenize; + + TokenRegexStrings mTokenRegexStrings; + + bool mCaseSensitive; + + LanguageDefinition() + : mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true) + { + } + + static const LanguageDefinition& CPlusPlus(); + static const LanguageDefinition& HLSL(); + static const LanguageDefinition& GLSL(); + static const LanguageDefinition& C(); + static const LanguageDefinition& SQL(); + static const LanguageDefinition& AngelScript(); + static const LanguageDefinition& Lua(); + }; + + TextEditor(); + ~TextEditor(); + + void SetLanguageDefinition(const LanguageDefinition& aLanguageDef); + const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; } + + const Palette& GetPalette() const { return mPaletteBase; } + void SetPalette(const Palette& aValue); + + void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; } + void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; } + + void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false); + void SetText(const std::string& aText); + std::string GetText() const; + + void SetTextLines(const std::vector& aLines); + std::vector GetTextLines() const; + + std::string GetSelectedText() const; + std::string GetCurrentLineText() const; + + int GetTotalLines() const { return static_cast(mLines.size()); } + bool IsOverwrite() const { return mOverwrite; } + + void SetReadOnly(bool aValue); + bool IsReadOnly() const { return mReadOnly; } + bool IsTextChanged() const { return mTextChanged; } + bool IsCursorPositionChanged() const { return mCursorPositionChanged; } + + bool IsColorizerEnabled() const { return mColorizerEnabled; } + void SetColorizerEnable(bool aValue); + + Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); } + void SetCursorPosition(const Coordinates& aPosition); + + void SetHandleMouseInputs(bool aValue) { mHandleMouseInputs = aValue; } + bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; } + + void SetHandleKeyboardInputs(bool aValue) { mHandleKeyboardInputs = aValue; } + bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; } + + void SetImGuiChildIgnored(bool aValue) { mIgnoreImGuiChild = aValue; } + bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; } + + void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; } + bool IsShowingWhitespaces() const { return mShowWhitespaces; } + + void SetTabSize(int aValue); + int GetTabSize() const { return mTabSize; } + + void InsertText(const std::string& aValue); + void InsertText(const char* aValue); + + void MoveUp(int aAmount = 1, bool aSelect = false); + void MoveDown(int aAmount = 1, bool aSelect = false); + void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false); + void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false); + void MoveTop(bool aSelect = false); + void MoveBottom(bool aSelect = false); + void MoveHome(bool aSelect = false); + void MoveEnd(bool aSelect = false); + + void SetSelectionStart(const Coordinates& aPosition); + void SetSelectionEnd(const Coordinates& aPosition); + void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal); + void SelectWordUnderCursor(); + void SelectAll(); + bool HasSelection() const; + + void Copy(); + void Cut(); + void Paste(); + void Delete(); + + bool CanUndo() const; + bool CanRedo() const; + void Undo(int aSteps = 1); + void Redo(int aSteps = 1); + + static const Palette& GetDarkPalette(); + static const Palette& GetLightPalette(); + static const Palette& GetRetroBluePalette(); + +private: + using RegexList = std::vector>; + + struct EditorState + { + Coordinates mSelectionStart; + Coordinates mSelectionEnd; + Coordinates mCursorPosition; + }; + + class UndoRecord + { + public: + UndoRecord() {} + ~UndoRecord() {} + + UndoRecord( + const std::string& aAdded, + Coordinates aAddedStart, + Coordinates aAddedEnd, + + const std::string& aRemoved, + Coordinates aRemovedStart, + Coordinates aRemovedEnd, + + EditorState& aBefore, + EditorState& aAfter); + + void Undo(TextEditor* aEditor); + void Redo(TextEditor* aEditor); + + std::string mAdded; + Coordinates mAddedStart; + Coordinates mAddedEnd; + + std::string mRemoved; + Coordinates mRemovedStart; + Coordinates mRemovedEnd; + + EditorState mBefore; + EditorState mAfter; + }; + + using UndoBuffer = std::vector; + + void ProcessInputs(); + void Colorize(int aFromLine = 0, int aCount = -1); + void ColorizeRange(int aFromLine = 0, int aToLine = 0); + void ColorizeInternal(); + float TextDistanceToLineStart(const Coordinates& aFrom) const; + void EnsureCursorVisible(); + int GetPageSize() const; + std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const; + Coordinates GetActualCursorCoordinates() const; + Coordinates SanitizeCoordinates(const Coordinates& aValue) const; + void Advance(Coordinates& aCoordinates) const; + void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd); + int InsertTextAt(Coordinates& aWhere, const char* aValue); + void AddUndo(UndoRecord& aValue); + Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const; + Coordinates FindWordStart(const Coordinates& aFrom) const; + Coordinates FindWordEnd(const Coordinates& aFrom) const; + Coordinates FindNextWord(const Coordinates& aFrom) const; + int GetCharacterIndex(const Coordinates& aCoordinates) const; + int GetCharacterColumn(int aLine, int aIndex) const; + int GetLineCharacterCount(int aLine) const; + int GetLineMaxColumn(int aLine) const; + bool IsOnWordBoundary(const Coordinates& aAt) const; + void RemoveLine(int aStart, int aEnd); + void RemoveLine(int aIndex); + Line& InsertLine(int aIndex); + void EnterCharacter(ImWchar aChar, bool aShift); + void Backspace(); + void DeleteSelection(); + std::string GetWordUnderCursor() const; + std::string GetWordAt(const Coordinates& aCoords) const; + ImU32 GetGlyphColor(const Glyph& aGlyph) const; + + void HandleKeyboardInputs(); + void HandleMouseInputs(); + void Render(); + + float mLineSpacing; + Lines mLines; + EditorState mState; + UndoBuffer mUndoBuffer; + int mUndoIndex; + + int mTabSize; + bool mOverwrite; + bool mReadOnly; + bool mWithinRender; + bool mScrollToCursor; + bool mScrollToTop; + bool mTextChanged; + bool mColorizerEnabled; + float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor. + int mLeftMargin; + bool mCursorPositionChanged; + int mColorRangeMin, mColorRangeMax; + SelectionMode mSelectionMode; + bool mHandleKeyboardInputs; + bool mHandleMouseInputs; + bool mIgnoreImGuiChild; + bool mShowWhitespaces; + + Palette mPaletteBase{}; + Palette mPalette{}; + LanguageDefinition mLanguageDefinition; + RegexList mRegexList; + + bool mCheckComments; + Breakpoints mBreakpoints; + ErrorMarkers mErrorMarkers; + ImVec2 mCharAdvance; + Coordinates mInteractiveStart, mInteractiveEnd; + std::string mLineBuffer; + uint64_t mStartTime; + + float mLastClick; +}; diff --git a/Amalgam/include/ImGui/imconfig.h b/Amalgam/include/ImGui/imconfig.h new file mode 100644 index 0000000..b56ba49 --- /dev/null +++ b/Amalgam/include/ImGui/imconfig.h @@ -0,0 +1,129 @@ +//----------------------------------------------------------------------------- +// DEAR IMGUI COMPILE-TIME OPTIONS +// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. +// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. +//----------------------------------------------------------------------------- +// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) +// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. +//----------------------------------------------------------------------------- +// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp +// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. +// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. +// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. +//----------------------------------------------------------------------------- + +#pragma once + +//---- Define assertion handler. Defaults to calling assert(). +// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. +//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) +//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts + +//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows +// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. +//#define IMGUI_API __declspec( dllexport ) +//#define IMGUI_API __declspec( dllimport ) + +//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS +//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions. + +//---- Disable all of Dear ImGui or don't implement standard windows/tools. +// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. +//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. +//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. +//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). + +//---- Don't implement some functions to reduce linkage requirements. +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) +//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) +//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). +//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). +//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) +//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. +//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. +//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). +//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available + +//---- Include imgui_user.h at the end of imgui.h as a convenience +//#define IMGUI_INCLUDE_IMGUI_USER_H + +//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) +//#define IMGUI_USE_BGRA_PACKED_COLOR + +//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) +//#define IMGUI_USE_WCHAR32 + +//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version +// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. + +//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) +// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. +//#define IMGUI_USE_STB_SPRINTF + +//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) +// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). +// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. +//#define IMGUI_ENABLE_FREETYPE + +//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) +// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). +// Only works in combination with IMGUI_ENABLE_FREETYPE. +// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) +//#define IMGUI_ENABLE_FREETYPE_LUNASVG + +//---- Use stb_truetype to build and rasterize the font atlas (default) +// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. +//#define IMGUI_ENABLE_STB_TRUETYPE + +//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. +// This will be inlined as part of ImVec2 and ImVec4 class declarations. +/* +#define IM_VEC2_CLASS_EXTRA \ + constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ + operator MyVec2() const { return MyVec2(x,y); } + +#define IM_VEC4_CLASS_EXTRA \ + constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ + operator MyVec4() const { return MyVec4(x,y,z,w); } +*/ +//---- ...Or use Dear ImGui's own very basic math operators. +//#define IMGUI_DEFINE_MATH_OPERATORS + +//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. +// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). +// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. +// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. +//#define ImDrawIdx unsigned int + +//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) +//struct ImDrawList; +//struct ImDrawCmd; +//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); +//#define ImDrawCallback MyImDrawCallback + +//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) +// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) +//#define IM_DEBUG_BREAK IM_ASSERT(0) +//#define IM_DEBUG_BREAK __debugbreak() + +//---- Debug Tools: Enable slower asserts +//#define IMGUI_DEBUG_PARANOID + +//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) +/* +namespace ImGui +{ + void MyFunction(const char* name, MyMatrix44* mtx); +} +*/ diff --git a/Amalgam/include/ImGui/imgui.cpp b/Amalgam/include/ImGui/imgui.cpp new file mode 100644 index 0000000..73d986b --- /dev/null +++ b/Amalgam/include/ImGui/imgui.cpp @@ -0,0 +1,14967 @@ +// dear imgui, v1.89.8 +// (main code and documentation) + +// Help: +// - Read FAQ at http://dearimgui.com/faq +// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.com/faq +// - Homepage https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) +// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Issues & support https://github.com/ocornut/imgui/issues +// - Tests & Automation https://github.com/ocornut/imgui_test_engine + +// Getting Started? +// - Read https://github.com/ocornut/imgui/wiki/Getting-Started +// - For first-time users having issues compiling/linking/running/loading fonts: +// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. + +// Developed by Omar Cornut and every direct or indirect contributors to the GitHub. +// See LICENSE.txt for copyright and licensing details (standard MIT License). +// This library is free but needs your support to sustain development and maintenance. +// Businesses: you can support continued development via B2B invoiced technical support, maintenance and sponsoring contracts. +// PLEASE reach out at contact AT dearimgui DOT com. See https://github.com/ocornut/imgui/wiki/Sponsors +// Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine. + +// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library. +// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without +// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't +// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you +// to a better solution or official support for them. + +/* + +Index of this file: + +DOCUMENTATION + +- MISSION STATEMENT +- CONTROLS GUIDE +- PROGRAMMER GUIDE + - READ FIRST + - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + - HOW A SIMPLE APPLICATION MAY LOOK LIKE + - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE +- API BREAKING CHANGES (read me when you update!) +- FREQUENTLY ASKED QUESTIONS (FAQ) + - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer) + +CODE +(search for "[SECTION]" in the code to find them) + +// [SECTION] INCLUDES +// [SECTION] FORWARD DECLARATIONS +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +// [SECTION] MISC HELPERS/UTILITIES (File functions) +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// [SECTION] ImGuiStorage +// [SECTION] ImGuiTextFilter +// [SECTION] ImGuiTextBuffer, ImGuiTextIndex +// [SECTION] ImGuiListClipper +// [SECTION] STYLING +// [SECTION] RENDER HELPERS +// [SECTION] INITIALIZATION, SHUTDOWN +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] INPUTS +// [SECTION] ERROR CHECKING +// [SECTION] LAYOUT +// [SECTION] SCROLLING +// [SECTION] TOOLTIPS +// [SECTION] POPUPS +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +// [SECTION] DRAG AND DROP +// [SECTION] LOGGING/CAPTURING +// [SECTION] SETTINGS +// [SECTION] LOCALIZATION +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +// [SECTION] PLATFORM DEPENDENT HELPERS +// [SECTION] METRICS/DEBUGGER WINDOW +// [SECTION] DEBUG LOG WINDOW +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) + +*/ + +//----------------------------------------------------------------------------- +// DOCUMENTATION +//----------------------------------------------------------------------------- + +/* + + MISSION STATEMENT + ================= + + - Easy to use to create code-driven and data-driven tools. + - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools. + - Easy to hack and improve. + - Minimize setup and maintenance. + - Minimize state storage on user side. + - Minimize state synchronization. + - Portable, minimize dependencies, run on target (consoles, phones, etc.). + - Efficient runtime and memory consumption. + + Designed primarily for developers and content-creators, not the typical end-user! + Some of the current weaknesses (which we aim to address in the future) includes: + + - Doesn't look fancy. + - Limited layout features, intricate layouts are typically crafted in code. + + + CONTROLS GUIDE + ============== + + - MOUSE CONTROLS + - Mouse wheel: Scroll vertically. + - SHIFT+Mouse wheel: Scroll horizontally. + - Click [X]: Close a window, available when 'bool* p_open' is passed to ImGui::Begin(). + - Click ^, Double-Click title: Collapse window. + - Drag on corner/border: Resize window (double-click to auto fit window to its contents). + - Drag on any empty space: Move window (unless io.ConfigWindowsMoveFromTitleBarOnly = true). + - Left-click outside popup: Close popup stack (right-click over underlying popup: Partially close popup stack). + + - TEXT EDITOR + - Hold SHIFT or Drag Mouse: Select text. + - CTRL+Left/Right: Word jump. + - CTRL+Shift+Left/Right: Select words. + - CTRL+A or Double-Click: Select All. + - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard. + - CTRL+Z, CTRL+Y: Undo, Redo. + - ESCAPE: Revert text to its original value. + - On OSX, controls are automatically adjusted to match standard OSX text editing shortcuts and behaviors. + + - KEYBOARD CONTROLS + - Basic: + - Tab, SHIFT+Tab Cycle through text editable fields. + - CTRL+Tab, CTRL+Shift+Tab Cycle through windows. + - CTRL+Click Input text into a Slider or Drag widget. + - Extended features with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`: + - Tab, SHIFT+Tab: Cycle through every items. + - Arrow keys Move through items using directional navigation. Tweak value. + - Arrow keys + Alt, Shift Tweak slower, tweak faster (when using arrow keys). + - Enter Activate item (prefer text input when possible). + - Space Activate item (prefer tweaking with arrows when possible). + - Escape Deactivate item, leave child window, close popup. + - Page Up, Page Down Previous page, next page. + - Home, End Scroll to top, scroll to bottom. + - Alt Toggle between scrolling layer and menu layer. + - CTRL+Tab then Ctrl+Arrows Move window. Hold SHIFT to resize instead of moving. + - Output when ImGuiConfigFlags_NavEnableKeyboard set, + - io.WantCaptureKeyboard flag is set when keyboard is claimed. + - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set. + - io.NavVisible: true when the navigation cursor is visible (usually goes to back false when mouse is used). + + - GAMEPAD CONTROLS + - Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. + - Particularly useful to use Dear ImGui on a console system (e.g. PlayStation, Switch, Xbox) without a mouse! + - Download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets + - Backend support: backend needs to: + - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys. + - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly. + Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead! + - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing, + with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. + + - REMOTE INPUTS SHARING & MOUSE EMULATION + - PS4/PS5 users: Consider emulating a mouse cursor with DualShock touch pad or a spare analog stick as a mouse-emulation fallback. + - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app) + in order to share your PC mouse/keyboard. + - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements. + When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. + When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. + (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!) + (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want + to set a boolean to ignore your other external mouse positions until the external source is moved again.) + + + PROGRAMMER GUIDE + ================ + + READ FIRST + ---------- + - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki) + - Your code creates the UI every frame of your application loop, if your code doesn't run the UI is gone! + The UI can be highly dynamic, there are no construction or destruction steps, less superfluous + data retention on your side, less state duplication, less state synchronization, fewer bugs. + - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. + Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version. + - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. + - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). + You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. + - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances. + For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI, + where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches. + - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right. + - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected). + If you get an assert, read the messages and comments around the assert. + - This codebase aims to be highly optimized: + - A typical idle frame should never call malloc/free. + - We rely on a maximum of constant-time or O(N) algorithms. Limiting searches/scans as much as possible. + - We put particular energy in making sure performances are decent with typical "Debug" build settings as well. + Which mean we tend to avoid over-relying on "zero-cost abstraction" as they aren't zero-cost at all. + - This codebase aims to be both highly opinionated and highly flexible: + - This code works because of the things it choose to solve or not solve. + - C++: this is a pragmatic C-ish codebase: we don't use fancy C++ features, we don't include C++ headers, + and ImGui:: is a namespace. We rarely use member functions (and when we did, I am mostly regretting it now). + This is to increase compatibility, increase maintainability and facilitate use from other languages. + - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. + See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. + We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. + - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction + (so don't use ImVector in your code or at our own risk!). + - Building: We don't use nor mandate a build system for the main library. + This is in an effort to ensure that it works in the real world aka with any esoteric build setup. + This is also because providing a build system for the main library would be of little-value. + The build problems are almost never coming from the main library but from specific backends. + + + HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI + ---------------------------------------------- + - Update submodule or copy/overwrite every file. + - About imconfig.h: + - You may modify your copy of imconfig.h, in this case don't overwrite it. + - or you may locally branch to modify imconfig.h and merge/rebase latest. + - or you may '#define IMGUI_USER_CONFIG "my_config_file.h"' globally from your build system to + specify a custom path for your imconfig.h file and instead not have to modify the default one. + + - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h) + - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master". + - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file. + - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes. + If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed + from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will + likely be a comment about it. Please report any issue to the GitHub page! + - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file. + - Try to keep your copy of Dear ImGui reasonably up to date! + + + GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE + --------------------------------------------------------------- + - See https://github.com/ocornut/imgui/wiki/Getting-Started. + - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library. + - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder. + - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system. + It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL). + - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types. + - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them. + - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide. + Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" + phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render(). + - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code. + - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder. + + + HOW A SIMPLE APPLICATION MAY LOOK LIKE + -------------------------------------- + EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder). + The sub-folders in examples/ contain examples applications following this structure. + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp) + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + // Application main loop + while (true) + { + // Feed inputs to dear imgui, start new frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + // Any application code here + ImGui::Text("Hello, world!"); + + // Render dear imgui into screen + ImGui::Render(); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + g_pSwapChain->Present(1, 0); + } + + // Shutdown + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE + + // Application init: create a dear imgui context, setup some options, load fonts + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. + // TODO: Fill optional fields of the io structure later. + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + + // Build and load the texture atlas into a texture + // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) + int width, height; + unsigned char* pixels = nullptr; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + + // At this point you've got the texture data and you need to upload that to your graphic system: + // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. + // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. + MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) + io.Fonts->SetTexID((void*)texture); + + // Application main loop + while (true) + { + // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. + // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends) + io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds) + io.DisplaySize.x = 1920.0f; // set the current display width + io.DisplaySize.y = 1280.0f; // set the current display height here + io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position + io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states + io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states + + // Call NewFrame(), after this point you can use ImGui::* functions anytime + // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere) + ImGui::NewFrame(); + + // Most of your application code here + ImGui::Text("Hello, world!"); + MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); + MyGameRender(); // may use any Dear ImGui functions as well! + + // Render dear imgui, swap buffers + // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) + ImGui::EndFrame(); + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + MyImGuiRenderFunction(draw_data); + SwapBuffers(); + } + + // Shutdown + ImGui::DestroyContext(); + + To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application, + you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + Please read the FAQ and example applications for details about this! + + + HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + --------------------------------------------- + The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. + + void MyImGuiRenderFunction(ImDrawData* draw_data) + { + // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled + // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. + // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + ImVec2 clip_off = draw_data->DisplayPos; + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); + ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // We are using scissoring to clip some objects. All low-level graphics API should support it. + // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches + // (some elements visible outside their bounds) but you can fix that once everything else works! + // - Clipping coordinates are provided in imgui coordinates space: + // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size + // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values. + // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) + MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y); + + // The texture for the draw call is specified by pcmd->GetTexID(). + // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); + + // Render 'pcmd->ElemCount/3' indexed triangles. + // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset); + } + } + } + } + + + API BREAKING CHANGES + ==================== + + Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. + Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. + When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. + You can read releases logs https://github.com/ocornut/imgui/releases for more details. + + - 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878) + - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15). + - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). + - 2023/06/28 (1.89.7) - overlapping items: IsItemHovered() now by default return false when querying an item using AllowOverlap mode which is being overlapped. Use ImGuiHoveredFlags_AllowWhenOverlappedByItem to revert to old behavior. + - 2023/06/28 (1.89.7) - overlapping items: Selectable and TreeNode don't allow overlap when active so overlapping widgets won't appear as hovered. While this fixes a common small visual issue, it also means that calling IsItemHovered() after a non-reactive elements - e.g. Text() - overlapping an active one may fail if you don't use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem). (#6610) + - 2023/06/20 (1.89.7) - moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only tweaked once during app initialization, we are exceptionally accepting the breakage. + - 2023/05/30 (1.89.6) - backends: renamed "imgui_impl_sdlrenderer.cpp" to "imgui_impl_sdlrenderer2.cpp" and "imgui_impl_sdlrenderer.h" to "imgui_impl_sdlrenderer2.h". This is in prevision for the future release of SDL3. + - 2023/05/22 (1.89.6) - listbox: commented out obsolete/redirecting functions that were marked obsolete more than two years ago: + - ListBoxHeader() -> use BeginListBox() (note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference) + - ListBoxFooter() -> use EndListBox() + - 2023/05/15 (1.89.6) - clipper: commented out obsolete redirection constructor 'ImGuiListClipper(int items_count, float items_height = -1.0f)' that was marked obsolete in 1.79. Use default constructor + clipper.Begin(). + - 2023/05/15 (1.89.6) - clipper: renamed ImGuiListClipper::ForceDisplayRangeByIndices() to ImGuiListClipper::IncludeRangeByIndices(). + - 2023/03/14 (1.89.4) - commented out redirecting enums/functions names that were marked obsolete two years ago: + - ImGuiSliderFlags_ClampOnInput -> use ImGuiSliderFlags_AlwaysClamp + - ImGuiInputTextFlags_AlwaysInsertMode -> use ImGuiInputTextFlags_AlwaysOverwrite + - ImDrawList::AddBezierCurve() -> use ImDrawList::AddBezierCubic() + - ImDrawList::PathBezierCurveTo() -> use ImDrawList::PathBezierCubicCurveTo() + - 2023/03/09 (1.89.4) - renamed PushAllowKeyboardFocus()/PopAllowKeyboardFocus() to PushTabStop()/PopTabStop(). Kept inline redirection functions (will obsolete). + - 2023/03/09 (1.89.4) - tooltips: Added 'bool' return value to BeginTooltip() for API consistency. Please only submit contents and call EndTooltip() if BeginTooltip() returns true. In reality the function will _currently_ always return true, but further changes down the line may change this, best to clarify API sooner. + - 2023/02/15 (1.89.4) - moved the optional "courtesy maths operators" implementation from imgui_internal.h in imgui.h. + Even though we encourage using your own maths types and operators by setting up IM_VEC2_CLASS_EXTRA, + it has been frequently requested by people to use our own. We had an opt-in define which was + previously fulfilled in imgui_internal.h. It is now fulfilled in imgui.h. (#6164) + - OK: #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui.h" / #include "imgui_internal.h" + - Error: #include "imgui.h" / #define IMGUI_DEFINE_MATH_OPERATORS / #include "imgui_internal.h" + - 2023/02/07 (1.89.3) - backends: renamed "imgui_impl_sdl.cpp" to "imgui_impl_sdl2.cpp" and "imgui_impl_sdl.h" to "imgui_impl_sdl2.h". (#6146) This is in prevision for the future release of SDL3. + - 2022/10/26 (1.89) - commented out redirecting OpenPopupContextItem() which was briefly the name of OpenPopupOnItemClick() from 1.77 to 1.79. + - 2022/10/12 (1.89) - removed runtime patching of invalid "%f"/"%0.f" format strings for DragInt()/SliderInt(). This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details. + - 2022/09/26 (1.89) - renamed and merged keyboard modifiers key enums and flags into a same set. Kept inline redirection enums (will obsolete). + - ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl + - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift + - ImGuiKey_ModAlt and ImGuiModFlags_Alt -> ImGuiMod_Alt + - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super + the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends. + the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions. + exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway. + - 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. + this will require uses of legacy backend-dependent indices to be casted, e.g. + - with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A); + - with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A') + - etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now! + - 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr); + - 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020): + - DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f. + - SliderScalar(), SliderScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f. + - BeginPopupContextWindow(const char*, ImGuiMouseButton, bool) -> use BeginPopupContextWindow(const char*, ImGuiPopupFlags) + - 2022/09/02 (1.89) - obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries. + this relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item. + - previously this would make the window content size ~200x200: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); + - instead, please submit an item: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); + - alternative: + Begin(...) + Dummy(ImVec2(200,200)) + End(); + - content size is now only extended when submitting an item! + - with '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert. + - without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it. + - 2022/08/03 (1.89) - changed signature of ImageButton() function. Kept redirection function (will obsolete). + - added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter. + - old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1)); + - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values. + - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer. + - new signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1)); + - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier. + - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this. + - 2022/07/08 (1.89) - inputs: removed io.NavInputs[] and ImGuiNavInput enum (following 1.87 changes). + - Official backends from 1.87+ -> no issue. + - Official backends from 1.60 to 1.86 -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating! + - Custom backends not writing to io.NavInputs[] -> no issue. + - Custom backends writing to io.NavInputs[] -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing! + - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[]. + - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete). + - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary. + - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO. + - 2022/01/20 (1.87) - inputs: reworded gamepad IO. + - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values. + - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used). + - 2022/01/17 (1.87) - inputs: reworked mouse IO. + - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent() + - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent() + - Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent() + - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only] + note: for all calls to IO new functions, the Dear ImGui context should be bound/current. + read https://github.com/ocornut/imgui/issues/4921 for details. + - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. + - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX) + - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX) + - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes). + - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.* + - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert. + - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper. + - 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. + - 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'. + - 2022/01/01 (1.87) - commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019) + - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen() + - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x + - ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing()); + - ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect + - ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex + - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example. Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings + - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges. Please open an issue if you think you really need this function. + - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inline redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful. + - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019): + - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroundDrawList() + - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBuilder + - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID(). + - if you are using official backends from the source tree: you have nothing to do. + - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID(). + - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags. + - ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft + - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight + - ImDrawCornerFlags_None -> use ImDrawFlags_RoundCornersNone etc. + flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API. + breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners": + - rounding == 0.0f + flags == 0 --> meant no rounding --> unchanged (common use) + - rounding > 0.0f + flags != 0 --> meant rounding --> unchanged (common use) + - rounding == 0.0f + flags != 0 --> meant no rounding --> unchanged (unlikely use) + - rounding > 0.0f + flags == 0 --> meant no rounding --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f. + this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok. + the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts. + legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise). + - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018): + - ImGui::SetScrollHere() -> use ImGui::SetScrollHereY() + - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing. + - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future. + - 2021/02/22 (1.82) - (*undone in 1.84*) win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'. + - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed. + - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete). + - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete). + - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete). + - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. + - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. + - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. + - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018): + - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit(). + - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg + - ImGuiInputTextCallback -> use ImGuiTextEditCallback + - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData + - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete). + - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added! + - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API. + - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures + - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/. + - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018): + - io.RenderDrawListsFn pointer -> use ImGui::GetDrawData() value and call the render function of your backend + - ImGui::IsAnyWindowFocused() -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow) + - ImGui::IsAnyWindowHovered() -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) + - ImGuiStyleVar_Count_ -> use ImGuiStyleVar_COUNT + - ImGuiMouseCursor_Count_ -> use ImGuiMouseCursor_COUNT + - removed redirecting functions names that were marked obsolete in 1.61 (May 2018): + - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision. + - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter. + - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed). + - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently). + - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton. + - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory. + - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result. + - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now! + - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar(). + replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags). + worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions: + - if you omitted the 'power' parameter (likely!), you are not affected. + - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct. + - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f. + see https://github.com/ocornut/imgui/issues/3361 for all details. + kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used. + for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`. + - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime. + - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems. + - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79] + - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017. + - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular(). + - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more. + - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead. + - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value. + - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017): + - ShowTestWindow() -> use ShowDemoWindow() + - IsRootWindowFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow) + - IsRootWindowOrAnyChildFocused() -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) + - SetNextWindowContentWidth(w) -> use SetNextWindowContentSize(ImVec2(w, 0.0f) + - GetItemsLineHeightWithSpacing() -> use GetFrameHeightWithSpacing() + - ImGuiCol_ChildWindowBg -> use ImGuiCol_ChildBg + - ImGuiStyleVar_ChildWindowRounding -> use ImGuiStyleVar_ChildRounding + - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap + - IMGUI_DISABLE_TEST_WINDOWS -> use IMGUI_DISABLE_DEMO_WINDOWS + - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API. + - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it). + - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency. + - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency. + - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017): + - Begin() [old 5 args version] -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed + - IsRootWindowOrAnyChildHovered() -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) + - AlignFirstTextHeightToWidgets() -> use AlignTextToFramePadding() + - SetNextWindowPosCenter() -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f) + - ImFont::Glyph -> use ImFontGlyph + - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function. + if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix. + The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay). + If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you. + - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete). + - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete). + - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71. + - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have + overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering. + This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows. + Please reach out if you are affected. + - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete). + - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c). + - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now. + - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete). + - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete). + - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete). + - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value! + - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). + - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! + - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). + - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects. + - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags. + - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files. + - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete). + - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h. + If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths. + - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427) + - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp. + NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED. + Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions. + - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent). + - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete). + - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly). + - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature. + - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency. + - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time. + - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). + - 2018/06/08 (1.62) - examples: the imgui_impl_XXX files have been split to separate platform (Win32, GLFW, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.). + old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports. + when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call. + in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function. + - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. + - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. + - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more. + If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. + To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. + If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them. + - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", + consistent with other functions. Kept redirection functions (will obsolete). + - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. + - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some backend ahead of merging the Nav branch). + - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now. + - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. + - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums. + - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment. + - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display. + - 2018/02/07 (1.60) - reorganized context handling to be more explicit, + - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. + - removed Shutdown() function, as DestroyContext() serve this purpose. + - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. + - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. + - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. + - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths. + - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete). + - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData. + - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side. + - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete). + - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags + - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame. + - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. + - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete). + - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete). + - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete). + - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete). + - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete). + - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed. + - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up. + Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions. + - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. + - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. + - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. + - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); + - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency. + - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. + - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details. + removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting. + IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly) + IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow) + IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior] + - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead! + - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete). + - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). + - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete). + - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)". + - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)! + - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). + - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). + - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. + - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. + - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type. + - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. + - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete). + - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete). + - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton(). + - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu. + - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options. + - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0))' + - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse + - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. + - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity. + - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetID() and use it instead of passing string to BeginChild(). + - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it. + - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. + - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully, breakage should be minimal. + - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore. + If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color: + ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a); } + If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color. + - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext(). + - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection. + - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen). + - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer. + - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref GitHub issue #337). + - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337) + - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). + - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert. + - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you. + - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis. + - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete. + - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position. + GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side. + GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out! + - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize + - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project. + - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason + - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure. + you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text. + - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost. + this necessary change will break your rendering function! the fix should be very easy. sorry for that :( + - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest. + - the signature of the io.RenderDrawListsFn handler has changed! + old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count) + new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data). + parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount' + ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new. + ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'. + - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer. + - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering! + - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade! + - 2015/07/10 (1.43) - changed SameLine() parameters from int to float. + - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete). + - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount. + - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence + - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry! + - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete). + - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete). + - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons. + - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened. + - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). + - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50. + - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API + - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive. + - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead. + - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50. + - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing + - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50. + - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing) + - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50. + - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once. + - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now. + - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior + - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing() + - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused) + - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions. + - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. + - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. + - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; + - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier); + you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. + - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID() + - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) + - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets + - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) + - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph) + - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility + - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered() + - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly) + - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity) + - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale() + - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn + - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically) + - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite + - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes + + + FREQUENTLY ASKED QUESTIONS (FAQ) + ================================ + + Read all answers online: + https://www.dearimgui.com/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url) + Read all answers locally (with a text editor or ideally a Markdown viewer): + docs/FAQ.md + Some answers are copied down here to facilitate searching in code. + + Q&A: Basics + =========== + + Q: Where is the documentation? + A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++. + - Run the examples/ applications and explore them. + - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide. + - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. + - The demo covers most features of Dear ImGui, so you can read the code and see its output. + - See documentation and comments at the top of imgui.cpp + effectively imgui.h. + - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the + examples/ folder to explain how to integrate Dear ImGui with your own engine/application. + - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links. + - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful. + - Your programming IDE is your friend, find the type or function declaration to find comments + associated with it. + + Q: What is this library called? + Q: Which version should I get? + >> This library is called "Dear ImGui", please don't call it "ImGui" :) + >> See https://www.dearimgui.com/faq for details. + + Q&A: Integration + ================ + + Q: How to get started? + A: Read https://github.com/ocornut/imgui/wiki/Getting-Started. Read 'PROGRAMMER GUIDE' above. Read examples/README.txt. + + Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application? + A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + >> See https://www.dearimgui.com/faq for a fully detailed answer. You really want to read this. + + Q. How can I enable keyboard or gamepad controls? + Q: How can I use this on a machine without mouse, keyboard or screen? (input share, remote display) + Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... + Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around... + Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries... + >> See https://www.dearimgui.com/faq + + Q&A: Usage + ---------- + + Q: About the ID Stack system.. + - Why is my widget not reacting when I click on it? + - How can I have widgets with an empty label? + - How can I have multiple widgets with the same label? + - How can I have multiple windows with the same label? + Q: How can I display an image? What is ImTextureID, how does it work? + Q: How can I use my own math types instead of ImVec2? + Q: How can I interact with standard C++ types (such as std::string and std::vector)? + Q: How can I display custom shapes? (using low-level ImDrawList API) + >> See https://www.dearimgui.com/faq + + Q&A: Fonts, Text + ================ + + Q: How should I handle DPI in my application? + Q: How can I load a different font than the default? + Q: How can I easily use icons in my application? + Q: How can I load multiple fonts? + Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? + >> See https://www.dearimgui.com/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md + + Q&A: Concerns + ============= + + Q: Who uses Dear ImGui? + Q: Can you create elaborate/serious tools with Dear ImGui? + Q: Can you reskin the look of Dear ImGui? + Q: Why using C++ (as opposed to C)? + >> See https://www.dearimgui.com/faq + + Q&A: Community + ============== + + Q: How can I help? + A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui! + We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts. + This is among the most useful thing you can do for Dear ImGui. With increased funding, we sustain and grow work on this project. + Also see https://github.com/ocornut/imgui/wiki/Sponsors + - Businesses: you can also purchase licenses for the Dear ImGui Automation/Test Engine. + - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, and see how you want to help and can help! + - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc. + You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers. + But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions. + - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on GitHub or privately). + +*/ + +//------------------------------------------------------------------------- +// [SECTION] INCLUDES +//------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_internal.h" + +// System includes +#include // vsnprintf, sscanf, printf +#include // intptr_t + +// [Windows] On non-Visual Studio compilers, we default to IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS unless explicitly enabled +#if defined(_WIN32) && !defined(_MSC_VER) && !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif + +// [Windows] OS specific includes (optional) +#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#define IMGUI_DISABLE_WIN32_FUNCTIONS +#endif +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef __MINGW32__ +#include // _wfopen, OpenClipboard +#else +#include +#endif +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions +#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS +#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +#endif +#endif + +// [Apple] OS specific includes +#if defined(__APPLE__) +#include +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to an 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. +#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int' +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +// We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association. +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// Debug options +#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL +#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window + +// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. +static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in +static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear + +// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend) +static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow(). +static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. +static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. + +// Tooltip offset +static const ImVec2 TOOLTIP_DEFAULT_OFFSET = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale + +//------------------------------------------------------------------------- +// [SECTION] FORWARD DECLARATIONS +//------------------------------------------------------------------------- + +static void SetCurrentWindow(ImGuiWindow* window); +static void FindHoveredWindow(); +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags); +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window); + +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window); + +// Settings +static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*); +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); +static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); +static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); + +// Platform Dependents default implementation for IO functions +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); +static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data); + +namespace ImGui +{ +// Navigation +static void NavUpdate(); +static void NavUpdateWindowing(); +static void NavUpdateWindowingOverlay(); +static void NavUpdateCancelRequest(); +static void NavUpdateCreateMoveRequest(); +static void NavUpdateCreateTabbingRequest(); +static float NavUpdatePageUpPageDown(); +static inline void NavUpdateAnyRequestFlag(); +static void NavUpdateCreateWrappingRequest(); +static void NavEndFrame(); +static bool NavScoreItem(ImGuiNavItemData* result); +static void NavApplyItemToResult(ImGuiNavItemData* result); +static void NavProcessItem(); +static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags); +static ImVec2 NavCalcPreferredRefPos(); +static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); +static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); +static void NavRestoreLayer(ImGuiNavLayer layer); +static void NavRestoreHighlightAfterMove(); +static int FindWindowFocusIndex(ImGuiWindow* window); + +// Error Checking and Debug Tools +static void ErrorCheckNewFrameSanityChecks(); +static void ErrorCheckEndFrameSanityChecks(); +static void UpdateDebugToolItemPicker(); +static void UpdateDebugToolStackQueries(); + +// Inputs +static void UpdateKeyboardInputs(); +static void UpdateMouseInputs(); +static void UpdateMouseWheel(); +static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); + +// Misc +static void UpdateSettings(); +static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); +static void RenderWindowOuterBorders(ImGuiWindow* window); +static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); +static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); +static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); +static void RenderDimmedBackgrounds(); + +// Viewports +static void UpdateViewportsNewFrame(); + +} + +//----------------------------------------------------------------------------- +// [SECTION] CONTEXT AND MEMORY ALLOCATORS +//----------------------------------------------------------------------------- + +// DLL users: +// - Heaps and globals are not shared across DLL boundaries! +// - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from. +// - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL). +// - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in). + +// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL. +// - ImGui::CreateContext() will automatically set this pointer if it is NULL. +// Change to a different context by calling ImGui::SetCurrentContext(). +// - Important: Dear ImGui functions are not thread-safe because of this pointer. +// If you want thread-safety to allow N threads to access N different contexts: +// - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h: +// struct ImGuiContext; +// extern thread_local ImGuiContext* MyImGuiTLS; +// #define GImGui MyImGuiTLS +// And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword. +// - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586 +// - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace. +// - DLL users: read comments above. +#ifndef GImGui +ImGuiContext* GImGui = NULL; +#endif + +// Memory Allocator functions. Use SetAllocatorFunctions() to change them. +// - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction. +// - DLL users: read comments above. +#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); return malloc(size); } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); free(ptr); } +#else +static void* MallocWrapper(size_t size, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; } +static void FreeWrapper(void* ptr, void* user_data) { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); } +#endif +static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper; +static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper; +static void* GImAllocatorUserData = NULL; + +//----------------------------------------------------------------------------- +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) +//----------------------------------------------------------------------------- + +ImGuiStyle::ImGuiStyle() +{ + Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. + DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. + WindowPadding = ImVec2(8,8); // Padding within a window + WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. + WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. + WindowMinSize = ImVec2(32,32); // Minimum window size + WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text + WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left. + ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows + ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested. + PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows + PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested. + FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets) + FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets). + FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. + ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines + ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) + CellPadding = ImVec2(4,2); // Padding within a table cell + TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar + ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar + GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar + GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabBorderSize = 0.0f; // Thickness of border around tabs. + TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. + SelectableRounding = 0.0f; // Radius of selectable / menuitem corners rounding. Set to 0.0f to have rectangular selection. + SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText() + SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. + DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. + DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. + MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. + AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). + AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.). + CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + + // Behaviors + HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary. + HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay. + HoverDelayNormal = 0.40f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " + HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. + HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. + + // Default theme + ImGui::StyleColorsDark(this); +} + +// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you. +// Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. +void ImGuiStyle::ScaleAllSizes(float scale_factor) +{ + WindowPadding = ImFloor(WindowPadding * scale_factor); + WindowRounding = ImFloor(WindowRounding * scale_factor); + WindowMinSize = ImFloor(WindowMinSize * scale_factor); + ChildRounding = ImFloor(ChildRounding * scale_factor); + PopupRounding = ImFloor(PopupRounding * scale_factor); + FramePadding = ImFloor(FramePadding * scale_factor); + FrameRounding = ImFloor(FrameRounding * scale_factor); + ItemSpacing = ImFloor(ItemSpacing * scale_factor); + ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); + CellPadding = ImFloor(CellPadding * scale_factor); + TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); + IndentSpacing = ImFloor(IndentSpacing * scale_factor); + ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor); + ScrollbarSize = ImFloor(ScrollbarSize * scale_factor); + ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); + GrabMinSize = ImFloor(GrabMinSize * scale_factor); + GrabRounding = ImFloor(GrabRounding * scale_factor); + LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); + SelectableRounding = ImFloor(SelectableRounding * scale_factor); + TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + SeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor); + DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); + DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); + MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); +} + +ImGuiIO::ImGuiIO() +{ + // Most fields are initialized with zero + memset(this, 0, sizeof(*this)); + IM_STATIC_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); + + // Settings + ConfigFlags = ImGuiConfigFlags_None; + BackendFlags = ImGuiBackendFlags_None; + DisplaySize = ImVec2(-1.0f, -1.0f); + DeltaTime = 1.0f / 60.0f; + IniSavingRate = 5.0f; + IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables). + LogFilename = "imgui_log.txt"; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + for (int i = 0; i < ImGuiKey_COUNT; i++) + KeyMap[i] = -1; +#endif + UserData = NULL; + + Fonts = NULL; + FontGlobalScale = 1.0f; + FontDefault = NULL; + FontAllowUserScaling = false; + DisplayFramebufferScale = ImVec2(1.0f, 1.0f); + + MouseDoubleClickTime = 0.30f; + MouseDoubleClickMaxDist = 6.0f; + MouseDragThreshold = 6.0f; + KeyRepeatDelay = 0.275f; + KeyRepeatRate = 0.050f; + + // Miscellaneous options + MouseDrawCursor = false; +#ifdef __APPLE__ + ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag +#else + ConfigMacOSXBehaviors = false; +#endif + ConfigInputTrickleEventQueue = true; + ConfigInputTextCursorBlink = true; + ConfigInputTextEnterKeepActive = false; + ConfigDragClickToInputText = false; + ConfigWindowsResizeFromEdges = true; + ConfigWindowsMoveFromTitleBarOnly = false; + ConfigMemoryCompactTimer = 60.0f; + ConfigDebugBeginReturnValueOnce = false; + ConfigDebugBeginReturnValueLoop = false; + + // Platform Functions + // Note: Initialize() will setup default clipboard/ime handlers. + BackendPlatformName = BackendRendererName = NULL; + BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + + // Input (NB: we already have memset zero the entire structure!) + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); + MouseSource = ImGuiMouseSource_Mouse; + for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; + for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; } + AppAcceptingEvents = true; + BackendUsingLegacyKeyArrays = (ImS8)-1; + BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong +} + +// Pass in translated ASCII characters for text input. +// - with glfw you can get those from the callback set in glfwSetCharCallback() +// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message +// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API +void ImGuiIO::AddInputCharacter(unsigned int c) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + if (c == 0 || !AppAcceptingEvents) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_Text; + e.Source = ImGuiInputSource_Keyboard; + e.EventId = g.InputEventsNextEventId++; + e.Text.Char = c; + g.InputEventsQueue.push_back(e); +} + +// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so +// we should save the high surrogate. +void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) +{ + if ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents) + return; + + if ((c & 0xFC00) == 0xD800) // High surrogate, must save + { + if (InputQueueSurrogate != 0) + AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID); + InputQueueSurrogate = c; + return; + } + + ImWchar cp = c; + if (InputQueueSurrogate != 0) + { + if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate + { + AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID); + } + else + { +#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF + cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar +#else + cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); +#endif + } + + InputQueueSurrogate = 0; + } + AddInputCharacter((unsigned)cp); +} + +void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) +{ + if (!AppAcceptingEvents) + return; + while (*utf8_chars != 0) + { + unsigned int c = 0; + utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); + AddInputCharacter(c); + } +} + +// Clear all incoming events. +void ImGuiIO::ClearEventsQueue() +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + g.InputEventsQueue.clear(); +} + +// Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. +void ImGuiIO::ClearInputKeys() +{ +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + memset(KeysDown, 0, sizeof(KeysDown)); +#endif + for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++) + { + KeysData[n].Down = false; + KeysData[n].DownDuration = -1.0f; + KeysData[n].DownDurationPrev = -1.0f; + } + KeyCtrl = KeyShift = KeyAlt = KeySuper = false; + KeyMods = ImGuiMod_None; + MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++) + { + MouseDown[n] = false; + MouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f; + } + MouseWheel = MouseWheelH = 0.0f; + InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters(). +} + +// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue. +// Current frame character buffer is now also cleared by ClearInputKeys(). +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +void ImGuiIO::ClearInputCharacters() +{ + InputQueueCharacters.resize(0); +} +#endif + +static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventType type, int arg = -1) +{ + ImGuiContext& g = *ctx; + for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--) + { + ImGuiInputEvent* e = &g.InputEventsQueue[n]; + if (e->Type != type) + continue; + if (type == ImGuiInputEventType_Key && e->Key.Key != arg) + continue; + if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg) + continue; + return e; + } + return NULL; +} + +// Queue a new key down/up event. +// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) +// - bool down: Is the key down? use false to signify a key release. +// - float analog_value: 0.0f..1.0f +// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE. +// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULLFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT. +void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) +{ + //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); } + IM_ASSERT(Ctx != NULL); + if (key == ImGuiKey_None || !AppAcceptingEvents) + return; + ImGuiContext& g = *Ctx; + IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API. + IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events. + IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself) + + // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + if (BackendUsingLegacyKeyArrays == -1) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + BackendUsingLegacyKeyArrays = 0; +#endif + if (ImGui::IsGamepadKey(key)) + BackendUsingLegacyNavInputArray = false; + + // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); + const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key); + const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down; + const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue; + if (latest_key_down == down && latest_key_analog == analog_value) + return; + + // Add event + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_Key; + e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputSource_Keyboard; + e.EventId = g.InputEventsNextEventId++; + e.Key.Key = key; + e.Key.Down = down; + e.Key.AnalogValue = analog_value; + g.InputEventsQueue.push_back(e); +} + +void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down) +{ + if (!AppAcceptingEvents) + return; + AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f); +} + +// [Optional] Call after AddKeyEvent(). +// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices. +// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this. +void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index) +{ + if (key == ImGuiKey_None) + return; + IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512 + IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511 + IM_UNUSED(native_keycode); // Yet unused + IM_UNUSED(native_scancode); // Yet unused + + // Build native->imgui map so old user code can still call key functions with native 0..511 values. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode; + if (!ImGui::IsLegacyKey((ImGuiKey)legacy_key)) + return; + KeyMap[legacy_key] = key; + KeyMap[key] = legacy_key; +#else + IM_UNUSED(key); + IM_UNUSED(native_legacy_index); +#endif +} + +// Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. +void ImGuiIO::SetAppAcceptingEvents(bool accepting_events) +{ + AppAcceptingEvents = accepting_events; +} + +// Queue a mouse move event +void ImGuiIO::AddMousePosEvent(float x, float y) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + if (!AppAcceptingEvents) + return; + + // Apply same flooring as UpdateMouseInputs() + ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y); + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MousePos); + const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos; + if (latest_pos.x == pos.x && latest_pos.y == pos.y) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MousePos; + e.Source = ImGuiInputSource_Mouse; + e.EventId = g.InputEventsNextEventId++; + e.MousePos.PosX = pos.x; + e.MousePos.PosY = pos.y; + e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + g.InputEventsQueue.push_back(e); +} + +void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); + if (!AppAcceptingEvents) + return; + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button); + const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button]; + if (latest_button_down == down) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MouseButton; + e.Source = ImGuiInputSource_Mouse; + e.EventId = g.InputEventsNextEventId++; + e.MouseButton.Button = mouse_button; + e.MouseButton.Down = down; + e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + g.InputEventsQueue.push_back(e); +} + +// Queue a mouse wheel event (some mouse/API may only have a Y component) +void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + + // Filter duplicate (unlike most events, wheel values are relative and easy to filter) + if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f)) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_MouseWheel; + e.Source = ImGuiInputSource_Mouse; + e.EventId = g.InputEventsNextEventId++; + e.MouseWheel.WheelX = wheel_x; + e.MouseWheel.WheelY = wheel_y; + e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + g.InputEventsQueue.push_back(e); +} + +// This is not a real event, the data is latched in order to be stored in actual Mouse events. +// This is so that duplicate events (e.g. Windows sending extraneous WM_MOUSEMOVE) gets filtered and are not leading to actual source changes. +void ImGuiIO::AddMouseSourceEvent(ImGuiMouseSource source) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + g.InputEventsNextMouseSource = source; +} + +void ImGuiIO::AddFocusEvent(bool focused) +{ + IM_ASSERT(Ctx != NULL); + ImGuiContext& g = *Ctx; + + // Filter duplicate + const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Focus); + const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost; + if (latest_focused == focused || (ConfigDebugIgnoreFocusLoss && !focused)) + return; + + ImGuiInputEvent e; + e.Type = ImGuiInputEventType_Focus; + e.EventId = g.InputEventsNextEventId++; + e.AppFocused.Focused = focused; + g.InputEventsQueue.push_back(e); +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) +//----------------------------------------------------------------------------- + +ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) +{ + IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau() + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + { + ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + return p_closest; +} + +// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp +static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = ((x2 - x4) * dy - (y2 - y4) * dx); + float d3 = ((x3 - x4) * dy - (y3 - y4) * dx); + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + { + ImVec2 p_current(x4, y4); + ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p); + float dist2 = ImLengthSqr(p - p_line); + if (dist2 < p_closest_dist2) + { + p_closest = p_line; + p_closest_dist2 = dist2; + } + p_last = p_current; + } + else if (level < 10) + { + float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f; + float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f; + float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f; + float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f; + float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f; + float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol +// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically. +ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol) +{ + IM_ASSERT(tess_tol > 0.0f); + ImVec2 p_last = p1; + ImVec2 p_closest; + float p_closest_dist2 = FLT_MAX; + ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0); + return p_closest; +} + +ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p) +{ + ImVec2 ap = p - a; + ImVec2 ab_dir = b - a; + float dot = ap.x * ab_dir.x + ap.y * ab_dir.y; + if (dot < 0.0f) + return a; + float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y; + if (dot > ab_len_sqr) + return b; + return a + ab_dir * dot / ab_len_sqr; +} + +bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; + bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; + bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; + return ((b1 == b2) && (b2 == b3)); +} + +void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) +{ + ImVec2 v0 = b - a; + ImVec2 v1 = c - a; + ImVec2 v2 = p - a; + const float denom = v0.x * v1.y - v1.x * v0.y; + out_v = (v2.x * v1.y - v1.x * v2.y) / denom; + out_w = (v0.x * v2.y - v2.x * v0.y) / denom; + out_u = 1.0f - out_v - out_w; +} + +ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p) +{ + ImVec2 proj_ab = ImLineClosestPoint(a, b, p); + ImVec2 proj_bc = ImLineClosestPoint(b, c, p); + ImVec2 proj_ca = ImLineClosestPoint(c, a, p); + float dist2_ab = ImLengthSqr(p - proj_ab); + float dist2_bc = ImLengthSqr(p - proj_bc); + float dist2_ca = ImLengthSqr(p - proj_ca); + float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca)); + if (m == dist2_ab) + return proj_ab; + if (m == dist2_bc) + return proj_bc; + return proj_ca; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) +//----------------------------------------------------------------------------- + +// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more. +int ImStricmp(const char* str1, const char* str2) +{ + int d; + while ((d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; } + return d; +} + +int ImStrnicmp(const char* str1, const char* str2, size_t count) +{ + int d = 0; + while (count > 0 && (d = ImToUpper(*str2) - ImToUpper(*str1)) == 0 && *str1) { str1++; str2++; count--; } + return d; +} + +void ImStrncpy(char* dst, const char* src, size_t count) +{ + if (count < 1) + return; + if (count > 1) + strncpy(dst, src, count - 1); + dst[count - 1] = 0; +} + +char* ImStrdup(const char* str) +{ + size_t len = strlen(str); + void* buf = IM_ALLOC(len + 1); + return (char*)memcpy(buf, (const void*)str, len + 1); +} + +char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) +{ + size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; + size_t src_size = strlen(src) + 1; + if (dst_buf_size < src_size) + { + IM_FREE(dst); + dst = (char*)IM_ALLOC(src_size); + if (p_dst_size) + *p_dst_size = src_size; + } + return (char*)memcpy(dst, (const void*)src, src_size); +} + +const char* ImStrchrRange(const char* str, const char* str_end, char c) +{ + const char* p = (const char*)memchr(str, (int)c, str_end - str); + return p; +} + +int ImStrlenW(const ImWchar* str) +{ + //return (int)wcslen((const wchar_t*)str); // FIXME-OPT: Could use this when wchar_t are 16-bit + int n = 0; + while (*str++) n++; + return n; +} + +// Find end-of-line. Return pointer will point to either first \n, either str_end. +const char* ImStreolRange(const char* str, const char* str_end) +{ + const char* p = (const char*)memchr(str, '\n', str_end - str); + return p ? p : str_end; +} + +const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line +{ + while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') + buf_mid_line--; + return buf_mid_line; +} + +const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) +{ + if (!needle_end) + needle_end = needle + strlen(needle); + + const char un0 = (char)ImToUpper(*needle); + while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) + { + if (ImToUpper(*haystack) == un0) + { + const char* b = needle + 1; + for (const char* a = haystack + 1; b < needle_end; a++, b++) + if (ImToUpper(*a) != ImToUpper(*b)) + break; + if (b == needle_end) + return haystack; + } + haystack++; + } + return NULL; +} + +// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible. +void ImStrTrimBlanks(char* buf) +{ + char* p = buf; + while (p[0] == ' ' || p[0] == '\t') // Leading blanks + p++; + char* p_start = p; + while (*p != 0) // Find end of string + p++; + while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks + p--; + if (p_start != buf) // Copy memory if we had leading blanks + memmove(buf, p_start, p - p_start); + buf[p - p_start] = 0; // Zero terminate +} + +const char* ImStrSkipBlank(const char* str) +{ + while (str[0] == ' ' || str[0] == '\t') + str++; + return str; +} + +// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size). +// Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. +// B) When buf==NULL vsnprintf() will return the output size. +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h) +// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are +// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.) +#ifdef IMGUI_USE_STB_SPRINTF +#ifndef IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION +#define STB_SPRINTF_IMPLEMENTATION +#endif +#ifdef IMGUI_STB_SPRINTF_FILENAME +#include IMGUI_STB_SPRINTF_FILENAME +#else +#include "stb_sprintf.h" +#endif +#endif // #ifdef IMGUI_USE_STB_SPRINTF + +#if defined(_MSC_VER) && !defined(vsnprintf) +#define vsnprintf _vsnprintf +#endif + +int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + va_end(args); + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} + +int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) +{ +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else + int w = vsnprintf(buf, buf_size, fmt, args); +#endif + if (buf == NULL) + return w; + if (w == -1 || w >= (int)buf_size) + w = (int)buf_size - 1; + buf[w] = 0; + return w; +} +#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS + +void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + va_list args; + va_start(args, fmt); + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + { + const char* buf = va_arg(args, const char*); // Skip formatting when using "%s" + *out_buf = buf; + if (out_buf_end) { *out_buf_end = buf + strlen(buf); } + } + else + { + int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + *out_buf = g.TempBuffer.Data; + if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } + } + va_end(args); +} + +void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0) + { + const char* buf = va_arg(args, const char*); // Skip formatting when using "%s" + *out_buf = buf; + if (out_buf_end) { *out_buf_end = buf + strlen(buf); } + } + else + { + int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args); + *out_buf = g.TempBuffer.Data; + if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; } + } +} + +// CRC32 needs a 1KB lookup table (not cache friendly) +// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: +// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. +static const ImU32 GCrc32LookupTable[256] = +{ + 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, +}; + +// Known size hash +// It is ok to call ImHashData on a string with known length but the ### operator won't be supported. +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) +{ + ImU32 crc = ~seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + while (data_size-- != 0) + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; + return ~crc; +} + +// Zero-terminated string hash, with support for ### to reset back to seed value +// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed. +// Because this syntax is rarely used we are optimizing for the common case. +// - If we reach ### in the string we discard the hash so far and reset to the seed. +// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build) +// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. +ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) +{ + seed = ~seed; + ImU32 crc = seed; + const unsigned char* data = (const unsigned char*)data_p; + const ImU32* crc32_lut = GCrc32LookupTable; + if (data_size != 0) + { + while (data_size-- != 0) + { + unsigned char c = *data++; + if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + else + { + while (unsigned char c = *data++) + { + if (c == '#' && data[0] == '#' && data[1] == '#') + crc = seed; + crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; + } + } + return ~crc; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (File functions) +//----------------------------------------------------------------------------- + +// Default file functions +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +ImFileHandle ImFileOpen(const char* filename, const char* mode) +{ +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. + // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! + const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); + const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); + ImVector buf; + buf.resize(filename_wsize + mode_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); + return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]); +#else + return fopen(filename, mode); +#endif +} + +// We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way. +bool ImFileClose(ImFileHandle f) { return fclose(f) == 0; } +ImU64 ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; } +ImU64 ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fread(data, (size_t)sz, (size_t)count, f); } +ImU64 ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f) { return fwrite(data, (size_t)sz, (size_t)count, f); } +#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + +// Helper: Load file content into memory +// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() +// This can't really be used with "rt" because fseek size won't match read size. +void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) +{ + IM_ASSERT(filename && mode); + if (out_file_size) + *out_file_size = 0; + + ImFileHandle f; + if ((f = ImFileOpen(filename, mode)) == NULL) + return NULL; + + size_t file_size = (size_t)ImFileGetSize(f); + if (file_size == (size_t)-1) + { + ImFileClose(f); + return NULL; + } + + void* file_data = IM_ALLOC(file_size + padding_bytes); + if (file_data == NULL) + { + ImFileClose(f); + return NULL; + } + if (ImFileRead(file_data, 1, file_size, f) != file_size) + { + ImFileClose(f); + IM_FREE(file_data); + return NULL; + } + if (padding_bytes > 0) + memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); + + ImFileClose(f); + if (out_file_size) + *out_file_size = file_size; + + return file_data; +} + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) +//----------------------------------------------------------------------------- + +IM_MSVC_RUNTIME_CHECKS_OFF + +// Convert UTF-8 to 32-bit character, process single character input. +// A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8). +// We handle UTF-8 decoding error by skipping forward. +int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end) +{ + static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 }; + static const int masks[] = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 }; + static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 }; + static const int shiftc[] = { 0, 18, 12, 6, 0 }; + static const int shifte[] = { 0, 6, 4, 2, 0 }; + int len = lengths[*(const unsigned char*)in_text >> 3]; + int wanted = len + (len ? 0 : 1); + + if (in_text_end == NULL) + in_text_end = in_text + wanted; // Max length, nulls will be taken into account. + + // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here, + // so it is fast even with excessive branching. + unsigned char s[4]; + s[0] = in_text + 0 < in_text_end ? in_text[0] : 0; + s[1] = in_text + 1 < in_text_end ? in_text[1] : 0; + s[2] = in_text + 2 < in_text_end ? in_text[2] : 0; + s[3] = in_text + 3 < in_text_end ? in_text[3] : 0; + + // Assume a four-byte character and load four bytes. Unused bits are shifted out. + *out_char = (uint32_t)(s[0] & masks[len]) << 18; + *out_char |= (uint32_t)(s[1] & 0x3f) << 12; + *out_char |= (uint32_t)(s[2] & 0x3f) << 6; + *out_char |= (uint32_t)(s[3] & 0x3f) << 0; + *out_char >>= shiftc[len]; + + // Accumulate the various error conditions. + int e = 0; + e = (*out_char < mins[len]) << 6; // non-canonical encoding + e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half? + e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range? + e |= (s[1] & 0xc0) >> 2; + e |= (s[2] & 0xc0) >> 4; + e |= (s[3] ) >> 6; + e ^= 0x2a; // top two bits of each tail byte correct? + e >>= shifte[len]; + + if (e) + { + // No bytes are consumed when *in_text == 0 || in_text == in_text_end. + // One byte is consumed in case of invalid first byte of in_text. + // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes. + // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s. + wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]); + *out_char = IM_UNICODE_CODEPOINT_INVALID; + } + + return wanted; +} + +int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining) +{ + ImWchar* buf_out = buf; + ImWchar* buf_end = buf + buf_size; + while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + *buf_out++ = (ImWchar)c; + } + *buf_out = 0; + if (in_text_remaining) + *in_text_remaining = in_text; + return (int)(buf_out - buf); +} + +int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end) +{ + int char_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c; + in_text += ImTextCharFromUtf8(&c, in_text, in_text_end); + char_count++; + } + return char_count; +} + +// Based on stb_to_utf8() from github.com/nothings/stb/ +static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c) +{ + if (c < 0x80) + { + buf[0] = (char)c; + return 1; + } + if (c < 0x800) + { + if (buf_size < 2) return 0; + buf[0] = (char)(0xc0 + (c >> 6)); + buf[1] = (char)(0x80 + (c & 0x3f)); + return 2; + } + if (c < 0x10000) + { + if (buf_size < 3) return 0; + buf[0] = (char)(0xe0 + (c >> 12)); + buf[1] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[2] = (char)(0x80 + ((c ) & 0x3f)); + return 3; + } + if (c <= 0x10FFFF) + { + if (buf_size < 4) return 0; + buf[0] = (char)(0xf0 + (c >> 18)); + buf[1] = (char)(0x80 + ((c >> 12) & 0x3f)); + buf[2] = (char)(0x80 + ((c >> 6) & 0x3f)); + buf[3] = (char)(0x80 + ((c ) & 0x3f)); + return 4; + } + // Invalid code point, the max unicode is 0x10FFFF + return 0; +} + +const char* ImTextCharToUtf8(char out_buf[5], unsigned int c) +{ + int count = ImTextCharToUtf8_inline(out_buf, 5, c); + out_buf[count] = 0; + return out_buf; +} + +// Not optimal but we very rarely use this function. +int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end) +{ + unsigned int unused = 0; + return ImTextCharFromUtf8(&unused, in_text, in_text_end); +} + +static inline int ImTextCountUtf8BytesFromChar(unsigned int c) +{ + if (c < 0x80) return 1; + if (c < 0x800) return 2; + if (c < 0x10000) return 3; + if (c <= 0x10FFFF) return 4; + return 3; +} + +int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end) +{ + char* buf_p = out_buf; + const char* buf_end = out_buf + out_buf_size; + while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + *buf_p++ = (char)c; + else + buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c); + } + *buf_p = 0; + return (int)(buf_p - out_buf); +} + +int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end) +{ + int bytes_count = 0; + while ((!in_text_end || in_text < in_text_end) && *in_text) + { + unsigned int c = (unsigned int)(*in_text++); + if (c < 0x80) + bytes_count++; + else + bytes_count += ImTextCountUtf8BytesFromChar(c); + } + return bytes_count; +} +IM_MSVC_RUNTIME_CHECKS_RESTORE + +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (Color functions) +// Note: The Convert functions are early design which are not consistent with other API. +//----------------------------------------------------------------------------- + +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b) +{ + float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f; + int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t); + int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t); + int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t); + return IM_COL32(r, g, b, 0xFF); +} + +ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in) +{ + float s = 1.0f / 255.0f; + return ImVec4( + ((in >> IM_COL32_R_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_G_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_B_SHIFT) & 0xFF) * s, + ((in >> IM_COL32_A_SHIFT) & 0xFF) * s); +} + +ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) +{ + ImU32 out; + out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT; + out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT; + return out; +} + +// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 +// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv +void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) +{ + float K = 0.f; + if (g < b) + { + ImSwap(g, b); + K = -1.f; + } + if (r < g) + { + ImSwap(r, g); + K = -2.f / 6.f - K; + } + + const float chroma = r - (g < b ? g : b); + out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f)); + out_s = chroma / (r + 1e-20f); + out_v = r; +} + +// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 +// also http://en.wikipedia.org/wiki/HSL_and_HSV +void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) +{ + if (s == 0.0f) + { + // gray + out_r = out_g = out_b = v; + return; + } + + h = ImFmod(h, 1.0f) / (60.0f / 360.0f); + int i = (int)h; + float f = h - (float)i; + float p = v * (1.0f - s); + float q = v * (1.0f - s * f); + float t = v * (1.0f - s * (1.0f - f)); + + switch (i) + { + case 0: out_r = v; out_g = t; out_b = p; break; + case 1: out_r = q; out_g = v; out_b = p; break; + case 2: out_r = p; out_g = v; out_b = t; break; + case 3: out_r = p; out_g = q; out_b = v; break; + case 4: out_r = t; out_g = p; out_b = v; break; + case 5: default: out_r = v; out_g = p; out_b = q; break; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStorage +// Helper: Key->value storage +//----------------------------------------------------------------------------- + +// std::lower_bound but without the bullshit +static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector& data, ImGuiID key) +{ + ImGuiStorage::ImGuiStoragePair* first = data.Data; + ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size; + size_t count = (size_t)(last - first); + while (count > 0) + { + size_t count2 = count >> 1; + ImGuiStorage::ImGuiStoragePair* mid = first + count2; + if (mid->key < key) + { + first = ++mid; + count -= count2 + 1; + } + else + { + count = count2; + } + } + return first; +} + +// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. +void ImGuiStorage::BuildSortByKey() +{ + struct StaticFunc + { + static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs) + { + // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. + if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; + if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1; + return 0; + } + }; + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID); +} + +int ImGuiStorage::GetInt(ImGuiID key, int default_val) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_i; +} + +bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const +{ + return GetInt(key, default_val ? 1 : 0) != 0; +} + +float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return default_val; + return it->val_f; +} + +void* ImGuiStorage::GetVoidPtr(ImGuiID key) const +{ + ImGuiStoragePair* it = LowerBound(const_cast&>(Data), key); + if (it == Data.end() || it->key != key) + return NULL; + return it->val_p; +} + +// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. +int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_i; +} + +bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) +{ + return (bool*)GetIntRef(key, default_val ? 1 : 0); +} + +float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_f; +} + +void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + it = Data.insert(it, ImGuiStoragePair(key, default_val)); + return &it->val_p; +} + +// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) +void ImGuiStorage::SetInt(ImGuiID key, int val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_i = val; +} + +void ImGuiStorage::SetBool(ImGuiID key, bool val) +{ + SetInt(key, val ? 1 : 0); +} + +void ImGuiStorage::SetFloat(ImGuiID key, float val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_f = val; +} + +void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) +{ + ImGuiStoragePair* it = LowerBound(Data, key); + if (it == Data.end() || it->key != key) + { + Data.insert(it, ImGuiStoragePair(key, val)); + return; + } + it->val_p = val; +} + +void ImGuiStorage::SetAllInt(int v) +{ + for (int i = 0; i < Data.Size; i++) + Data[i].val_i = v; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextFilter +//----------------------------------------------------------------------------- + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077 +{ + InputBuf[0] = 0; + CountGrep = 0; + if (default_filter) + { + ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf)); + Build(); + } +} + +bool ImGuiTextFilter::Draw(const char* label, float width) +{ + if (width != 0.0f) + ImGui::SetNextItemWidth(width); + bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); + if (value_changed) + Build(); + return value_changed; +} + +void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector* out) const +{ + out->resize(0); + const char* wb = b; + const char* we = wb; + while (we < e) + { + if (*we == separator) + { + out->push_back(ImGuiTextRange(wb, we)); + wb = we + 1; + } + we++; + } + if (wb != we) + out->push_back(ImGuiTextRange(wb, we)); +} + +void ImGuiTextFilter::Build() +{ + Filters.resize(0); + ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf)); + input_range.split(',', &Filters); + + CountGrep = 0; + for (int i = 0; i != Filters.Size; i++) + { + ImGuiTextRange& f = Filters[i]; + while (f.b < f.e && ImCharIsBlankA(f.b[0])) + f.b++; + while (f.e > f.b && ImCharIsBlankA(f.e[-1])) + f.e--; + if (f.empty()) + continue; + if (Filters[i].b[0] != '-') + CountGrep += 1; + } +} + +bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const +{ + if (Filters.empty()) + return true; + + if (text == NULL) + text = ""; + + for (int i = 0; i != Filters.Size; i++) + { + const ImGuiTextRange& f = Filters[i]; + if (f.empty()) + continue; + if (f.b[0] == '-') + { + // Subtract + if (ImStristr(text, text_end, f.b + 1, f.e) != NULL) + return false; + } + else + { + // Grep + if (ImStristr(text, text_end, f.b, f.e) != NULL) + return true; + } + } + + // Implicit * grep + if (CountGrep == 0) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiTextBuffer, ImGuiTextIndex +//----------------------------------------------------------------------------- + +// On some platform vsnprintf() takes va_list by reference and modifies it. +// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it. +#ifndef va_copy +#if defined(__GNUC__) || defined(__clang__) +#define va_copy(dest, src) __builtin_va_copy(dest, src) +#else +#define va_copy(dest, src) (dest = src) +#endif +#endif + +char ImGuiTextBuffer::EmptyString[1] = { 0 }; + +void ImGuiTextBuffer::append(const char* str, const char* str_end) +{ + int len = str_end ? (int)(str_end - str) : (int)strlen(str); + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + memcpy(&Buf[write_off - 1], str, (size_t)len); + Buf[write_off - 1 + len] = 0; +} + +void ImGuiTextBuffer::appendf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + appendfv(fmt, args); + va_end(args); +} + +// Helper: Text buffer for logging/accumulating text +void ImGuiTextBuffer::appendfv(const char* fmt, va_list args) +{ + va_list args_copy; + va_copy(args_copy, args); + + int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass. + if (len <= 0) + { + va_end(args_copy); + return; + } + + // Add zero-terminator the first time + const int write_off = (Buf.Size != 0) ? Buf.Size : 1; + const int needed_sz = write_off + len; + if (write_off + len >= Buf.Capacity) + { + int new_capacity = Buf.Capacity * 2; + Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity); + } + + Buf.resize(needed_sz); + ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy); + va_end(args_copy); +} + +void ImGuiTextIndex::append(const char* base, int old_size, int new_size) +{ + IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset); + if (old_size == new_size) + return; + if (EndOffset == 0 || base[EndOffset - 1] == '\n') + LineOffsets.push_back(EndOffset); + const char* base_end = base + new_size; + for (const char* p = base + old_size; (p = (const char*)memchr(p, '\n', base_end - p)) != 0; ) + if (++p < base_end) // Don't push a trailing offset on last \n + LineOffsets.push_back((int)(intptr_t)(p - base)); + EndOffset = ImMax(EndOffset, new_size); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiListClipper +// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed +// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO) +//----------------------------------------------------------------------------- + +// FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell. +// The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous. +static bool GetSkipItemForListClipping() +{ + ImGuiContext& g = *GImGui; + return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy helper to calculate coarse clipping of large list of evenly sized items. +// This legacy API is not ideal because it assumes we will return a single contiguous rectangle. +// Prefer using ImGuiListClipper which can returns non-contiguous ranges. +void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + *out_items_display_start = 0; + *out_items_display_end = items_count; + return; + } + if (GetSkipItemForListClipping()) + { + *out_items_display_start = *out_items_display_end = 0; + return; + } + + // We create the union of the ClipRect and the scoring rect which at worst should be 1 page away from ClipRect + // We don't include g.NavId's rectangle in there (unless g.NavJustMovedToId is set) because the rectangle enlargement can get costly. + ImRect rect = window->ClipRect; + if (g.NavMoveScoringItems) + rect.Add(g.NavScoringNoClipRect); + if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId) + rect.Add(WindowRectRelToAbs(window, window->NavRectRel[0])); // Could store and use NavJustMovedToRectRel + + const ImVec2 pos = window->DC.CursorPos; + int start = (int)((rect.Min.y - pos.y) / items_height); + int end = (int)((rect.Max.y - pos.y) / items_height); + + // When performing a navigation request, ensure we have one item extra in the direction we are moving to + // FIXME: Verify this works with tabbing + const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) + start--; + if (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) + end++; + + start = ImClamp(start, 0, items_count); + end = ImClamp(end + 1, start, items_count); + *out_items_display_start = start; + *out_items_display_end = end; +} +#endif + +static void ImGuiListClipper_SortAndFuseRanges(ImVector& ranges, int offset = 0) +{ + if (ranges.Size - offset <= 1) + return; + + // Helper to order ranges and fuse them together if possible (bubble sort is fine as we are only sorting 2-3 entries) + for (int sort_end = ranges.Size - offset - 1; sort_end > 0; --sort_end) + for (int i = offset; i < sort_end + offset; ++i) + if (ranges[i].Min > ranges[i + 1].Min) + ImSwap(ranges[i], ranges[i + 1]); + + // Now fuse ranges together as much as possible. + for (int i = 1 + offset; i < ranges.Size; i++) + { + IM_ASSERT(!ranges[i].PosToIndexConvert && !ranges[i - 1].PosToIndexConvert); + if (ranges[i - 1].Max < ranges[i].Min) + continue; + ranges[i - 1].Min = ImMin(ranges[i - 1].Min, ranges[i].Min); + ranges[i - 1].Max = ImMax(ranges[i - 1].Max, ranges[i].Max); + ranges.erase(ranges.Data + i); + i--; + } +} + +static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_height) +{ + // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor. + // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. + // The clipper should probably have a final step to display the last item in a regular manner, maybe with an opt-out flag for data sets which may have costly seek? + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float off_y = pos_y - window->DC.CursorPos.y; + window->DC.CursorPos.y = pos_y; + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y - g.Style.ItemSpacing.y); + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage. + window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list. + if (ImGuiOldColumns* columns = window->DC.CurrentColumns) + columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly + if (ImGuiTable* table = g.CurrentTable) + { + if (table->IsInsideRow) + ImGui::TableEndRow(table); + table->RowPosY2 = window->DC.CursorPos.y; + const int row_increase = (int)((off_y / line_height) + 0.5f); + //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow() + table->RowBgColorCounter += row_increase; + } +} + +static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n) +{ + // StartPosY starts from ItemsFrozen hence the subtraction + // Perform the add and multiply with double to allow seeking through larger ranges + ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; + float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight); + ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight); +} + +ImGuiListClipper::ImGuiListClipper() +{ + memset(this, 0, sizeof(*this)); +} + +ImGuiListClipper::~ImGuiListClipper() +{ + End(); +} + +void ImGuiListClipper::Begin(int items_count, float items_height) +{ + if (Ctx == NULL) + Ctx = ImGui::GetCurrentContext(); + + ImGuiContext& g = *Ctx; + ImGuiWindow* window = g.CurrentWindow; + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name); + + if (ImGuiTable* table = g.CurrentTable) + if (table->IsInsideRow) + ImGui::TableEndRow(table); + + StartPosY = window->DC.CursorPos.y; + ItemsHeight = items_height; + ItemsCount = items_count; + DisplayStart = -1; + DisplayEnd = 0; + + // Acquire temporary buffer + if (++g.ClipperTempDataStacked > g.ClipperTempData.Size) + g.ClipperTempData.resize(g.ClipperTempDataStacked, ImGuiListClipperData()); + ImGuiListClipperData* data = &g.ClipperTempData[g.ClipperTempDataStacked - 1]; + data->Reset(this); + data->LossynessOffset = window->DC.CursorStartPosLossyness.y; + TempData = data; +} + +void ImGuiListClipper::End() +{ + if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData) + { + // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user. + ImGuiContext& g = *Ctx; + IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name); + if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0) + ImGuiListClipper_SeekCursorForItem(this, ItemsCount); + + // Restore temporary buffer and fix back pointers which may be invalidated when nesting + IM_ASSERT(data->ListClipper == this); + data->StepNo = data->Ranges.Size; + if (--g.ClipperTempDataStacked > 0) + { + data = &g.ClipperTempData[g.ClipperTempDataStacked - 1]; + data->ListClipper->TempData = data; + } + TempData = NULL; + } + ItemsCount = -1; +} + +void ImGuiListClipper::IncludeRangeByIndices(int item_begin, int item_end) +{ + ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; + IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet. + IM_ASSERT(item_begin <= item_end); + if (item_begin < item_end) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end)); +} + +static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) +{ + ImGuiContext& g = *clipper->Ctx; + ImGuiWindow* window = g.CurrentWindow; + ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; + IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?"); + + ImGuiTable* table = g.CurrentTable; + if (table && table->IsInsideRow) + ImGui::TableEndRow(table); + + // No items + if (clipper->ItemsCount == 0 || GetSkipItemForListClipping()) + return false; + + // While we are in frozen row state, keep displaying items one by one, unclipped + // FIXME: Could be stored as a table-agnostic state. + if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows) + { + clipper->DisplayStart = data->ItemsFrozen; + clipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount); + if (clipper->DisplayStart < clipper->DisplayEnd) + data->ItemsFrozen++; + return true; + } + + // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height) + bool calc_clipping = false; + if (data->StepNo == 0) + { + clipper->StartPosY = window->DC.CursorPos.y; + if (clipper->ItemsHeight <= 0.0f) + { + // Submit the first item (or range) so we can measure its height (generally the first range is 0..1) + data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1)); + clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen); + clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount); + data->StepNo = 1; + return true; + } + calc_clipping = true; // If on the first step with known item height, calculate clipping. + } + + // Step 1: Let the clipper infer height from first range + if (clipper->ItemsHeight <= 0.0f) + { + IM_ASSERT(data->StepNo == 1); + if (table) + IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y); + + clipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart); + bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); + if (affected_by_floating_point_precision) + clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. + + IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); + calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. + } + + // Step 0 or 1: Calculate the actual ranges of visible elements. + const int already_submitted = clipper->DisplayEnd; + if (calc_clipping) + { + if (g.LogEnabled) + { + // If logging is active, do not perform any clipping + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, clipper->ItemsCount)); + } + else + { + // Add range selected to be included for navigation + const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (is_nav_request) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0)); + if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1) + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); + + // Add focused/active item + ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]); + if (g.NavId != 0 && window->NavLastIds[0] == g.NavId) + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0)); + + // Add visible range + const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0; + const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0; + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max)); + } + + // Convert position ranges to item index ranges + // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping. + // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list, + // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted. + for (int i = 0; i < data->Ranges.Size; i++) + if (data->Ranges[i].PosToIndexConvert) + { + int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight); + int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f); + data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1); + data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, clipper->ItemsCount); + data->Ranges[i].PosToIndexConvert = false; + } + ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo); + } + + // Step 0+ (if item height is given in advance) or 1+: Display the next range in line. + if (data->StepNo < data->Ranges.Size) + { + clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); + clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount); + if (clipper->DisplayStart > already_submitted) //-V1051 + ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart); + data->StepNo++; + return true; + } + + // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), + // Advance the cursor to the end of the list and then returns 'false' to end the loop. + if (clipper->ItemsCount < INT_MAX) + ImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount); + + return false; +} + +bool ImGuiListClipper::Step() +{ + ImGuiContext& g = *Ctx; + bool need_items_height = (ItemsHeight <= 0.0f); + bool ret = ImGuiListClipper_StepInternal(this); + if (ret && (DisplayStart == DisplayEnd)) + ret = false; + if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n"); + if (need_items_height && ItemsHeight > 0.0f) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight); + if (ret) + { + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd); + } + else + { + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n"); + End(); + } + return ret; +} + +//----------------------------------------------------------------------------- +// [SECTION] STYLING +//----------------------------------------------------------------------------- + +ImGuiStyle& ImGui::GetStyle() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->Style; +} + +ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = style.Colors[idx]; + c.w *= style.Alpha * alpha_mul; + return ColorConvertFloat4ToU32(c); +} + +ImU32 ImGui::GetColorU32(const ImVec4& col) +{ + ImGuiStyle& style = GImGui->Style; + ImVec4 c = col; + c.w *= style.Alpha; + return ColorConvertFloat4ToU32(c); +} + +const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx) +{ + ImGuiStyle& style = GImGui->Style; + return style.Colors[idx]; +} + +ImU32 ImGui::GetColorU32(ImU32 col) +{ + ImGuiStyle& style = GImGui->Style; + if (style.Alpha >= 1.0f) + return col; + ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT; + a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range. + return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT); +} + +// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32 +void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorStack.push_back(backup); + g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); +} + +void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) +{ + ImGuiContext& g = *GImGui; + ImGuiColorMod backup; + backup.Col = idx; + backup.BackupValue = g.Style.Colors[idx]; + g.ColorStack.push_back(backup); + g.Style.Colors[idx] = col; +} + +void ImGui::PopStyleColor(int count) +{ + ImGuiContext& g = *GImGui; + if (g.ColorStack.Size < count) + { + IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times: stack underflow."); + count = g.ColorStack.Size; + } + while (count > 0) + { + ImGuiColorMod& backup = g.ColorStack.back(); + g.Style.Colors[backup.Col] = backup.BackupValue; + g.ColorStack.pop_back(); + count--; + } +} + +static const ImGuiDataVarInfo GStyleVarInfo[] = +{ + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableRounding) }, // ImGuiStyleVar_SelectableRounding + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding +}; + +const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) +{ + IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); + IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarInfo[idx]; +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) +{ + ImGuiContext& g = *GImGui; + const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) + { + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!"); +} + +void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) +{ + ImGuiContext& g = *GImGui; + const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) + { + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; + return; + } + IM_ASSERT_USER_ERROR(0, "Called PushStyleVar() variant with wrong type!"); +} + +void ImGui::PopStyleVar(int count) +{ + ImGuiContext& g = *GImGui; + if (g.StyleVarStack.Size < count) + { + IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times: stack underflow."); + count = g.StyleVarStack.Size; + } + while (count > 0) + { + // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. + ImGuiStyleMod& backup = g.StyleVarStack.back(); + const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx); + void* data = info->GetVarPtr(&g.Style); + if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + g.StyleVarStack.pop_back(); + count--; + } +} + +const char* ImGui::GetStyleColorName(ImGuiCol idx) +{ + // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1"; + switch (idx) + { + case ImGuiCol_Text: return "Text"; + case ImGuiCol_TextDisabled: return "TextDisabled"; + case ImGuiCol_WindowBg: return "WindowBg"; + case ImGuiCol_ChildBg: return "ChildBg"; + case ImGuiCol_PopupBg: return "PopupBg"; + case ImGuiCol_Border: return "Border"; + case ImGuiCol_BorderShadow: return "BorderShadow"; + case ImGuiCol_FrameBg: return "FrameBg"; + case ImGuiCol_FrameBgHovered: return "FrameBgHovered"; + case ImGuiCol_FrameBgActive: return "FrameBgActive"; + case ImGuiCol_TitleBg: return "TitleBg"; + case ImGuiCol_TitleBgActive: return "TitleBgActive"; + case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_MenuBarBg: return "MenuBarBg"; + case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; + case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; + case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered"; + case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive"; + case ImGuiCol_CheckMark: return "CheckMark"; + case ImGuiCol_SliderGrab: return "SliderGrab"; + case ImGuiCol_SliderGrabActive: return "SliderGrabActive"; + case ImGuiCol_Button: return "Button"; + case ImGuiCol_ButtonHovered: return "ButtonHovered"; + case ImGuiCol_ButtonActive: return "ButtonActive"; + case ImGuiCol_Header: return "Header"; + case ImGuiCol_HeaderHovered: return "HeaderHovered"; + case ImGuiCol_HeaderActive: return "HeaderActive"; + case ImGuiCol_Separator: return "Separator"; + case ImGuiCol_SeparatorHovered: return "SeparatorHovered"; + case ImGuiCol_SeparatorActive: return "SeparatorActive"; + case ImGuiCol_ResizeGrip: return "ResizeGrip"; + case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; + case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_Tab: return "Tab"; + case ImGuiCol_TabHovered: return "TabHovered"; + case ImGuiCol_TabActive: return "TabActive"; + case ImGuiCol_TabUnfocused: return "TabUnfocused"; + case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive"; + case ImGuiCol_PlotLines: return "PlotLines"; + case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered"; + case ImGuiCol_PlotHistogram: return "PlotHistogram"; + case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; + case ImGuiCol_TableHeaderBg: return "TableHeaderBg"; + case ImGuiCol_TableBorderStrong: return "TableBorderStrong"; + case ImGuiCol_TableBorderLight: return "TableBorderLight"; + case ImGuiCol_TableRowBg: return "TableRowBg"; + case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt"; + case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; + case ImGuiCol_DragDropTarget: return "DragDropTarget"; + case ImGuiCol_NavHighlight: return "NavHighlight"; + case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; + case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; + case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; + } + IM_ASSERT(0); + return "Unknown"; +} + + +//----------------------------------------------------------------------------- +// [SECTION] RENDER HELPERS +// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, +// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context. +// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context. +//----------------------------------------------------------------------------- + +const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end) +{ + const char* text_display_end = text; + if (!text_end) + text_end = (const char*)-1; + + while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#')) + text_display_end++; + return text_display_end; +} + +// Internal ImGui functions to render text +// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText() +void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Hide anything after a '##' string + const char* text_display_end; + if (hide_text_after_hash) + { + text_display_end = FindRenderedTextEnd(text, text_end); + } + else + { + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + text_display_end = text_end; + } + + if (text != text_display_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_display_end); + } +} + +void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!text_end) + text_end = text + strlen(text); // FIXME-OPT + + if (text != text_end) + { + window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width); + if (g.LogEnabled) + LogRenderedText(&pos, text, text_end); + } +} + +// Default clip_rect uses (pos_min,pos_max) +// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) +// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList. +// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take +// better advantage of the render function taking size into account for coarse clipping. +void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Perform CPU side clipping for single clipped element to avoid using scissor state + ImVec2 pos = pos_min; + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f); + + const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min; + const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max; + bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y); + if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min + need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y); + + // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment. + if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x); + if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y); + + // Render + if (need_clipping) + { + ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y); + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect); + } + else + { + draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL); + } +} + +void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) +{ + // Hide anything after a '##' string + const char* text_display_end = FindRenderedTextEnd(text, text_end); + const int text_len = (int)(text_display_end - text); + if (text_len == 0) + return; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect); + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_display_end); +} + +// Another overly complex function until we reorganize everything into a nice all-in-one helper. +// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. +// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. +void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) +{ + ImGuiContext& g = *GImGui; + if (text_end_full == NULL) + text_end_full = FindRenderedTextEnd(text); + const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); + + //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); + //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); + //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); + // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. + if (text_size.x > pos_max.x - pos_min.x) + { + // Hello wo... + // | | | + // min max ellipsis_max + // <-> this is generally some padding value + + const ImFont* font = draw_list->_Data->Font; + const float font_size = draw_list->_Data->FontSize; + const float font_scale = font_size / font->FontSize; + const char* text_end_ellipsis = NULL; + const float ellipsis_width = font->EllipsisWidth * font_scale; + + // We can now claim the space between pos_max.x and ellipsis_max.x + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); + float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; + if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) + { + // Always display at least 1 character if there's no room for character + ellipsis + text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); + text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; + } + while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) + { + // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) + text_end_ellipsis--; + text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte + } + + // Render text, render ellipsis + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + ImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); + if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x) + for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) + font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar); + } + else + { + RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + } + + if (g.LogEnabled) + LogRenderedText(&pos_min, text, text_end_full); +} + +// Render a rectangle shaped with optional rounding and borders +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); + const float border_size = g.Style.FrameBorderSize; + if (border && border_size > 0.0f) + { + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + } +} + +void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const float border_size = g.Style.FrameBorderSize; + if (border_size > 0.0f) + { + window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); + window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + } +} + +void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) +{ + ImGuiContext& g = *GImGui; + if (id != g.NavId) + return; + if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) + return; + ImGuiWindow* window = g.CurrentWindow; + if (window->DC.NavHideHighlightOneFrame) + return; + + float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + ImRect display_rect = bb; + display_rect.ClipWith(window->ClipRect); + if (flags & ImGuiNavHighlightFlags_TypeDefault) + { + const float THICKNESS = 2.0f; + const float DISTANCE = 3.0f + THICKNESS * 0.5f; + display_rect.Expand(ImVec2(DISTANCE, DISTANCE)); + bool fully_visible = window->ClipRect.Contains(display_rect); + if (!fully_visible) + window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); + window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, 0, THICKNESS); + if (!fully_visible) + window->DrawList->PopClipRect(); + } + if (flags & ImGuiNavHighlightFlags_TypeThin) + { + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f); + } +} + +void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); + ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; + for (int n = 0; n < g.Viewports.Size; n++) + { + // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. + ImVec2 offset, size, uv[4]; + if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + continue; + ImGuiViewportP* viewport = g.Viewports[n]; + const ImVec2 pos = base_pos - offset; + const float scale = base_scale; + if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale))) + continue; + ImDrawList* draw_list = GetForegroundDrawList(viewport); + ImTextureID tex_id = font_atlas->TexID; + draw_list->PushTextureID(tex_id); + draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); + draw_list->PopTextureID(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] INITIALIZATION, SHUTDOWN +//----------------------------------------------------------------------------- + +// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself +// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module +ImGuiContext* ImGui::GetCurrentContext() +{ + return GImGui; +} + +void ImGui::SetCurrentContext(ImGuiContext* ctx) +{ +#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC + IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this. +#else + GImGui = ctx; +#endif +} + +void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data) +{ + GImAllocatorAllocFunc = alloc_func; + GImAllocatorFreeFunc = free_func; + GImAllocatorUserData = user_data; +} + +// This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space) +void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data) +{ + *p_alloc_func = GImAllocatorAllocFunc; + *p_free_func = GImAllocatorFreeFunc; + *p_user_data = GImAllocatorUserData; +} + +ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas) +{ + ImGuiContext* prev_ctx = GetCurrentContext(); + ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas); + SetCurrentContext(ctx); + Initialize(); + if (prev_ctx != NULL) + SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one. + return ctx; +} + +void ImGui::DestroyContext(ImGuiContext* ctx) +{ + ImGuiContext* prev_ctx = GetCurrentContext(); + if (ctx == NULL) //-V1051 + ctx = prev_ctx; + SetCurrentContext(ctx); + Shutdown(); + SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL); + IM_DELETE(ctx); +} + +// IMPORTANT: ###xxx suffixes must be same in ALL languages +static const ImGuiLocEntry GLocalizationEntriesEnUS[] = +{ + { ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" }, + { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" }, + { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" }, + { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" }, + { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" }, + { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, + { ImGuiLocKey_WindowingPopup, "(Popup)" }, + { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, +}; + +void ImGui::Initialize() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(!g.Initialized && !g.SettingsLoaded); + + // Add .ini handle for ImGuiWindow and ImGuiTable types + { + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Window"; + ini_handler.TypeHash = ImHashStr("Window"); + ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll; + AddSettingsHandler(&ini_handler); + } + TableSettingsAddSettingsHandler(); + + // Setup default localization table + LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS)); + + // Setup default platform clipboard/IME handlers. + g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) + g.IO.SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl; + + // Create default viewport + ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); + g.Viewports.push_back(viewport); + g.TempBuffer.resize(1024 * 3 + 1, 0); + +#ifdef IMGUI_HAS_DOCK +#endif + + g.Initialized = true; +} + +// This function is merely here to free heap allocations. +void ImGui::Shutdown() +{ + // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) + ImGuiContext& g = *GImGui; + if (g.IO.Fonts && g.FontAtlasOwnedByContext) + { + g.IO.Fonts->Locked = false; + IM_DELETE(g.IO.Fonts); + } + g.IO.Fonts = NULL; + g.DrawListSharedData.TempBuffer.clear(); + + // Cleanup of other data are conditional on actually having initialized Dear ImGui. + if (!g.Initialized) + return; + + // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file) + if (g.SettingsLoaded && g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + + CallContextHooks(&g, ImGuiContextHookType_Shutdown); + + // Clear everything else + g.Windows.clear_delete(); + g.WindowsFocusOrder.clear(); + g.WindowsTempSortBuffer.clear(); + g.CurrentWindow = NULL; + g.CurrentWindowStack.clear(); + g.WindowsById.Clear(); + g.NavWindow = NULL; + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.MovingWindow = NULL; + + g.KeysRoutingTable.Clear(); + + g.ColorStack.clear(); + g.StyleVarStack.clear(); + g.FontStack.clear(); + g.OpenPopupStack.clear(); + g.BeginPopupStack.clear(); + + g.Viewports.clear_delete(); + + g.TabBars.Clear(); + g.CurrentTabBarStack.clear(); + g.ShrinkWidthBuffer.clear(); + + g.ClipperTempData.clear_destruct(); + + g.Tables.Clear(); + g.TablesTempData.clear_destruct(); + g.DrawChannelsTempMergeBuffer.clear(); + + g.ClipboardHandlerData.clear(); + g.MenusIdSubmittedThisFrame.clear(); + g.InputTextState.ClearFreeMemory(); + g.InputTextDeactivatedState.ClearFreeMemory(); + + g.SettingsWindows.clear(); + g.SettingsHandlers.clear(); + + if (g.LogFile) + { +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); + g.LogFile = NULL; + } + g.LogBuffer.clear(); + g.DebugLogBuf.clear(); + g.DebugLogIndex.clear(); + + g.Initialized = false; +} + +// No specific ordering/dependency support, will see as needed +ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_); + g.Hooks.push_back(*hook); + g.Hooks.back().HookId = ++g.HookIdNext; + return g.HookIdNext; +} + +// Deferred removal, avoiding issue with changing vector while iterating it +void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) +{ + ImGuiContext& g = *ctx; + IM_ASSERT(hook_id != 0); + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].HookId == hook_id) + g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; +} + +// Call context hooks (used by e.g. test engine) +// We assume a small number of hooks so all stored in same array +void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) +{ + ImGuiContext& g = *ctx; + for (int n = 0; n < g.Hooks.Size; n++) + if (g.Hooks[n].Type == hook_type) + g.Hooks[n].Callback(&g, &g.Hooks[n]); +} + + +//----------------------------------------------------------------------------- +// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +//----------------------------------------------------------------------------- + +// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods +ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL) +{ + memset(this, 0, sizeof(*this)); + Ctx = ctx; + Name = ImStrdup(name); + NameBufLen = (int)strlen(name) + 1; + ID = ImHashStr(name); + IDStack.push_back(ID); + MoveId = GetID("#MOVE"); + ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); + AutoFitFramesX = AutoFitFramesY = -1; + AutoPosLastDirection = ImGuiDir_None; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = 0; + SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + LastFrameActive = -1; + LastTimeActive = -1.0f; + FontWindowScale = 1.0f; + SettingsOffset = -1; + DrawList = &DrawListInst; + DrawList->_Data = &Ctx->DrawListSharedData; + DrawList->_OwnerName = Name; + NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX); +} + +ImGuiWindow::~ImGuiWindow() +{ + IM_ASSERT(DrawList == &DrawListInst); + IM_DELETE(Name); + ColumnsStorage.clear_destruct(); +} + +ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *Ctx; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +ImGuiID ImGuiWindow::GetID(const void* ptr) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); + ImGuiContext& g = *Ctx; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL); + return id; +} + +ImGuiID ImGuiWindow::GetID(int n) +{ + ImGuiID seed = IDStack.back(); + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGuiContext& g = *Ctx; + if (g.DebugHookIdInfo == id) + ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; +} + +// This is only used in rare/specific situations to manufacture an ID out of nowhere. +ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) +{ + ImGuiID seed = IDStack.back(); + ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs); + ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); + return id; +} + +static void SetCurrentWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow = window; + g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; + if (window) + { + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); + ImGui::NavUpdateCurrentWindowIsScrollPushableX(); + } +} + +void ImGui::GcCompactTransientMiscBuffers() +{ + ImGuiContext& g = *GImGui; + g.ItemFlagsStack.clear(); + g.GroupStack.clear(); + TableGcCompactSettings(); +} + +// Free up/compact internal window buffers, we can use this when a window becomes unused. +// Not freed: +// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data) +// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. +void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) +{ + window->MemoryCompacted = true; + window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; + window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; + window->IDStack.clear(); + window->DrawList->_ClearFreeMemory(); + window->DC.ChildWindows.clear(); + window->DC.ItemWidthStack.clear(); + window->DC.TextWrapPosStack.clear(); +} + +void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) +{ + // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening. + // The other buffers tends to amortize much faster. + window->MemoryCompacted = false; + window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity); + window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity); + window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0; +} + +void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + // Clear previous active id + if (g.ActiveId != 0) + { + // While most behaved code would make an effort to not steal active id during window move/drag operations, + // we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch + // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that. + if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId) + { + IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n"); + g.MovingWindow = NULL; + } + + // This could be written in a more general way (e.g associate a hook to ActiveId), + // but since this is currently quite an exception we'll leave it as is. + // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId() + if (g.InputTextState.ID == g.ActiveId) + InputTextDeactivateHook(g.ActiveId); + } + + // Set active id + g.ActiveIdIsJustActivated = (g.ActiveId != id); + if (g.ActiveIdIsJustActivated) + { + IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : ""); + g.ActiveIdTimer = 0.0f; + g.ActiveIdHasBeenPressedBefore = false; + g.ActiveIdHasBeenEditedBefore = false; + g.ActiveIdMouseButton = -1; + if (id != 0) + { + g.LastActiveId = id; + g.LastActiveIdTimer = 0.0f; + } + } + g.ActiveId = id; + g.ActiveIdAllowOverlap = false; + g.ActiveIdNoClearOnFocusLoss = false; + g.ActiveIdWindow = window; + g.ActiveIdHasBeenEditedThisFrame = false; + if (id) + { + g.ActiveIdIsAlive = id; + g.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? g.NavInputSource : ImGuiInputSource_Mouse; + IM_ASSERT(g.ActiveIdSource != ImGuiInputSource_None); + } + + // Clear declaration of inputs claimed by the widget + // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + g.ActiveIdUsingNavInputMask = 0x00; +#endif +} + +void ImGui::ClearActiveID() +{ + SetActiveID(0, NULL); // g.ActiveId = 0; +} + +void ImGui::SetHoveredID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.HoveredId = id; + g.HoveredIdAllowOverlap = false; + if (id != 0 && g.HoveredIdPreviousFrame != id) + g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f; +} + +ImGuiID ImGui::GetHoveredID() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame; +} + +// This is called by ItemAdd(). +// Code not using ItemAdd() may need to call this manually otherwise ActiveId will be cleared. In IMGUI_VERSION_NUM < 18717 this was called by GetID(). +void ImGui::KeepAliveID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + g.ActiveIdIsAlive = id; + if (g.ActiveIdPreviousFrame == id) + g.ActiveIdPreviousFrameIsAlive = true; +} + +void ImGui::MarkItemEdited(ImGuiID id) +{ + // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). + // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. + ImGuiContext& g = *GImGui; + if (g.ActiveId == id || g.ActiveId == 0) + { + g.ActiveIdHasBeenEditedThisFrame = true; + g.ActiveIdHasBeenEditedBefore = true; + } + + // We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343) + // We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714) + IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id); + + //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id); + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; +} + +bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags) +{ + // An active popup disable hovering on other windows (apart from its own children) + // FIXME-OPT: This could be cached/stored within the window. + ImGuiContext& g = *GImGui; + if (g.NavWindow) + if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow) + if (focused_root_window->WasActive && focused_root_window != window->RootWindow) + { + // For the purpose of those flags we differentiate "standard popup" from "modal popup" + // NB: The 'else' is important because Modal windows are also Popups. + bool want_inhibit = false; + if (focused_root_window->Flags & ImGuiWindowFlags_Modal) + want_inhibit = true; + else if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + want_inhibit = true; + + // Inhibit hover unless the window is within the stack of our modal/popup + if (want_inhibit) + if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window)) + return false; + } + return true; +} + +static inline float CalcDelayFromHoveredFlags(ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + if (flags & ImGuiHoveredFlags_DelayShort) + return g.Style.HoverDelayShort; + if (flags & ImGuiHoveredFlags_DelayNormal) + return g.Style.HoverDelayNormal; + return 0.0f; +} + +// This is roughly matching the behavior of internal-facing ItemHoverable() +// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered() +// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId +bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0 && "Invalid flags for IsItemHovered()!"); + + if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride)) + { + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + if (!IsItemFocused()) + return false; + + if (flags & ImGuiHoveredFlags_ForTooltip) + flags |= g.Style.HoverFlagsForTooltipNav; + } + else + { + // Test for bounding box overlap, as updated as ItemAdd() + ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags; + if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) + return false; + + if (flags & ImGuiHoveredFlags_ForTooltip) + flags |= g.Style.HoverFlagsForTooltipMouse; + + IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0); // Flags not supported by this function + + // Done with rectangle culling so we can perform heavier checks now + // Test if we are hovering the right window (our window could be behind another window) + // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable + // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was + // the test that has been running for a long while. + if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByWindow) == 0) + return false; + + // Test if another item is active (e.g. being dragged) + const ImGuiID id = g.LastItemData.ID; + if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + + // Test if interactions on this window are blocked by an active popup or modal. + // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. + if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck)) + return false; + + // Test if the item is disabled + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + + // Special handling for calling after Begin() which represent the title bar or tab. + // When the window is skipped/collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (id == window->MoveId && window->WriteAccessed) + return false; + + // Test if using AllowOverlap and overlapped + if ((g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap) && id != 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) + if (g.HoveredIdPreviousFrame != g.LastItemData.ID) + return false; + } + + // Handle hover delay + // (some ideas: https://www.nngroup.com/articles/timing-exposing-content) + const float delay = CalcDelayFromHoveredFlags(flags); + if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary)) + { + ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect); + if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id)) + g.HoverItemDelayTimer = 0.0f; + g.HoverItemDelayId = hover_delay_id; + + // When changing hovered item we requires a bit of stationary delay before activating hover timer, + // but once unlocked on a given item we also moving. + //if (g.HoverDelayTimer >= delay && (g.HoverDelayTimer - g.IO.DeltaTime < delay || g.MouseStationaryTimer - g.IO.DeltaTime < g.Style.HoverStationaryDelay)) { IMGUI_DEBUG_LOG("HoverDelayTimer = %f/%f, MouseStationaryTimer = %f\n", g.HoverDelayTimer, delay, g.MouseStationaryTimer); } + if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverItemUnlockedStationaryId != hover_delay_id) + return false; + + if (g.HoverItemDelayTimer < delay) + return false; + } + + return true; +} + +// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). +// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) +// FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28. +// If you used this in your legacy/custom widgets code: +// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.InFlags'. +// - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable. +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.HoveredWindow != window) + return false; + if (!IsMouseHoveringRect(bb.Min, bb.Max)) + return false; + + if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap) + return false; + if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap) + return false; + + // Done with rectangle culling so we can perform heavier checks now. + if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) + { + g.HoveredIdDisabled = true; + return false; + } + + // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level + // hover test in widgets code. We could also decide to split this function is two. + if (id != 0) + { + // Drag source doesn't report as hovered + if (g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover)) + return false; + + SetHoveredID(id); + + // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. + // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test. + if (item_flags & ImGuiItemflags_AllowOverlap) + { + g.HoveredIdAllowOverlap = true; + if (g.HoveredIdPreviousFrame != id) + return false; + } + } + + // When disabled we'll return false but still set HoveredId + if (item_flags & ImGuiItemFlags_Disabled) + { + // Release active id if turning disabled + if (g.ActiveId == id && id != 0) + ClearActiveID(); + g.HoveredIdDisabled = true; + return false; + } + + if (id != 0) + { + // [DEBUG] Item Picker tool! + // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making + // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered + // items if we performed the test in ItemAdd(), but that would incur a small runtime cost. + if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id) + GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255)); + if (g.DebugItemPickerBreakId == id) + IM_DEBUG_BREAK(); + } + + if (g.NavDisableMouseHover) + return false; + + return true; +} + +// FIXME: This is inlined/duplicated in ItemAdd() +bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!bb.Overlaps(window->ClipRect)) + if (id == 0 || (id != g.ActiveId && id != g.NavId)) + if (!g.LogEnabled) + return true; + return false; +} + +// This is also inlined in ItemAdd() +// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect. +void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) +{ + ImGuiContext& g = *GImGui; + g.LastItemData.ID = item_id; + g.LastItemData.InFlags = in_flags; + g.LastItemData.StatusFlags = item_flags; + g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; +} + +float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) +{ + if (wrap_pos_x < 0.0f) + return 0.0f; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (wrap_pos_x == 0.0f) + { + // We could decide to setup a default wrapping max point for auto-resizing windows, + // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function? + //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) + // wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x); + //else + wrap_pos_x = window->WorkRect.Max.x; + } + else if (wrap_pos_x > 0.0f) + { + wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space + } + + return ImMax(wrap_pos_x - pos.x, 1.0f); +} + +// IM_ALLOC() == ImGui::MemAlloc() +void* ImGui::MemAlloc(size_t size) +{ + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations++; + return (*GImAllocatorAllocFunc)(size, GImAllocatorUserData); +} + +// IM_FREE() == ImGui::MemFree() +void ImGui::MemFree(void* ptr) +{ + if (ptr) + if (ImGuiContext* ctx = GImGui) + ctx->IO.MetricsActiveAllocations--; + return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData); +} + +const char* ImGui::GetClipboardText() +{ + ImGuiContext& g = *GImGui; + return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : ""; +} + +void ImGui::SetClipboardText(const char* text) +{ + ImGuiContext& g = *GImGui; + if (g.IO.SetClipboardTextFn) + g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text); +} + +const char* ImGui::GetVersion() +{ + return IMGUI_VERSION; +} + +ImGuiIO& ImGui::GetIO() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + return GImGui->IO; +} + +// Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame() +ImDrawData* ImGui::GetDrawData() +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; + return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL; +} + +double ImGui::GetTime() +{ + return GImGui->Time; +} + +int ImGui::GetFrameCount() +{ + return GImGui->FrameCount; +} + +static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) +{ + // Create the draw list on demand, because they are not frequently used for all viewports + ImGuiContext& g = *GImGui; + IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); + ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; + if (draw_list == NULL) + { + draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); + draw_list->_OwnerName = drawlist_name; + viewport->DrawLists[drawlist_no] = draw_list; + } + + // Our ImDrawList system requires that there is always a command + if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount) + { + draw_list->_ResetForNewFrame(); + draw_list->PushTextureID(g.IO.Fonts->TexID); + draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); + viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount; + } + return draw_list; +} + +ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); +} + +ImDrawList* ImGui::GetBackgroundDrawList() +{ + ImGuiContext& g = *GImGui; + return GetBackgroundDrawList(g.Viewports[0]); +} + +ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) +{ + return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); +} + +ImDrawList* ImGui::GetForegroundDrawList() +{ + ImGuiContext& g = *GImGui; + return GetForegroundDrawList(g.Viewports[0]); +} + +ImDrawListSharedData* ImGui::GetDrawListSharedData() +{ + return &GImGui->DrawListSharedData; +} + +void ImGui::StartMouseMovingWindow(ImGuiWindow* window) +{ + // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows. + // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward. + // This is because we want ActiveId to be set even when the window is not permitted to move. + ImGuiContext& g = *GImGui; + FocusWindow(window); + SetActiveID(window->MoveId, window); + g.NavDisableHighlight = true; + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; + g.ActiveIdNoClearOnFocusLoss = true; + SetActiveIdUsingAllKeyboardKeys(); + + bool can_move_window = true; + if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove)) + can_move_window = false; + if (can_move_window) + g.MovingWindow = window; +} + +// Handle mouse moving window +// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() +// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId. +// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs, +// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other. +void ImGui::UpdateMouseMovingWindowNewFrame() +{ + ImGuiContext& g = *GImGui; + if (g.MovingWindow != NULL) + { + // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window). + // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency. + KeepAliveID(g.ActiveId); + IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow); + ImGuiWindow* moving_window = g.MovingWindow->RootWindow; + if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos)) + { + ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset; + SetWindowPos(moving_window, pos, ImGuiCond_Always); + FocusWindow(g.MovingWindow); + } + else + { + g.MovingWindow = NULL; + ClearActiveID(); + } + } + else + { + // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others. + if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId) + { + KeepAliveID(g.ActiveId); + if (!g.IO.MouseDown[0]) + ClearActiveID(); + } + } +} + +// Initiate moving window when clicking on empty space or title bar. +// Handle left-click and right-click focus. +void ImGui::UpdateMouseMovingWindowEndFrame() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId != 0 || g.HoveredId != 0) + return; + + // Unless we just made a window/popup appear + if (g.NavWindow && g.NavWindow->Appearing) + return; + + // Click on empty space to focus window and start moving + // (after we're done with all our widgets) + if (g.IO.MouseClicked[0]) + { + // Handle the edge case of a popup being closed while clicking in its empty space. + // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more. + ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL; + const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel); + + if (root_window != NULL && !is_closed_popup) + { + StartMouseMovingWindow(g.HoveredWindow); //-V595 + + // Cancel moving if clicked outside of title bar + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar)) + if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) + g.MovingWindow = NULL; + + // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) + if (g.HoveredIdDisabled) + g.MovingWindow = NULL; + } + else if (root_window == NULL && g.NavWindow != NULL) + { + // Clicking on void disable focus + FocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal); + } + } + + // With right mouse button we close popups without changing focus based on where the mouse is aimed + // Instead, focus will be restored to the window under the bottom-most closed popup. + // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) + if (g.IO.MouseClicked[1]) + { + // Find the top-most window between HoveredWindow and the top-most Modal Window. + // This is where we can trim the popup stack. + ImGuiWindow* modal = GetTopMostPopupModal(); + bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal)); + ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); + } +} + +static bool IsWindowActiveAndVisible(ImGuiWindow* window) +{ + return (window->Active) && (!window->Hidden); +} + +// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) +void ImGui::UpdateHoveredWindowAndCaptureFlags() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); + + // Find the window hovered by mouse: + // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. + // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. + // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. + bool clear_hovered_windows = false; + FindHoveredWindow(); + + // Modal windows prevents mouse from hovering behind them. + ImGuiWindow* modal_window = GetTopMostPopupModal(); + if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) + clear_hovered_windows = true; + + // Disabled mouse? + if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) + clear_hovered_windows = true; + + // We track click ownership. When clicked outside of a window the click is owned by the application and + // won't report hovering nor request capture even while dragging over our windows afterward. + const bool has_open_popup = (g.OpenPopupStack.Size > 0); + const bool has_open_modal = (modal_window != NULL); + int mouse_earliest_down = -1; + bool mouse_any_down = false; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + if (io.MouseClicked[i]) + { + io.MouseDownOwned[i] = (g.HoveredWindow != NULL) || has_open_popup; + io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal; + } + mouse_any_down |= io.MouseDown[i]; + if (io.MouseDown[i]) + if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down]) + mouse_earliest_down = i; + } + const bool mouse_avail = (mouse_earliest_down == -1) || io.MouseDownOwned[mouse_earliest_down]; + const bool mouse_avail_unless_popup_close = (mouse_earliest_down == -1) || io.MouseDownOwnedUnlessPopupClose[mouse_earliest_down]; + + // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. + // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02) + const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0; + if (!mouse_avail && !mouse_dragging_extern_payload) + clear_hovered_windows = true; + + if (clear_hovered_windows) + g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; + + // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to Dear ImGui only, false = dispatch mouse to Dear ImGui + underlying app) + // Update io.WantCaptureMouseAllowPopupClose (experimental) to give a chance for app to react to popup closure with a drag + if (g.WantCaptureMouseNextFrame != -1) + { + io.WantCaptureMouse = io.WantCaptureMouseUnlessPopupClose = (g.WantCaptureMouseNextFrame != 0); + } + else + { + io.WantCaptureMouse = (mouse_avail && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_popup; + io.WantCaptureMouseUnlessPopupClose = (mouse_avail_unless_popup_close && (g.HoveredWindow != NULL || mouse_any_down)) || has_open_modal; + } + + // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app) + if (g.WantCaptureKeyboardNextFrame != -1) + io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); + else + io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + io.WantCaptureKeyboard = true; + + // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible + io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; +} + +void ImGui::NewFrame() +{ + IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?"); + ImGuiContext& g = *GImGui; + + // Remove pending delete hooks before frame start. + // This deferred removal avoid issues of removal while iterating the hook vector + for (int n = g.Hooks.Size - 1; n >= 0; n--) + if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_) + g.Hooks.erase(&g.Hooks[n]); + + CallContextHooks(&g, ImGuiContextHookType_NewFramePre); + + // Check and assert for various common IO and Configuration mistakes + ErrorCheckNewFrameSanityChecks(); + + // Load settings on first frame, save settings when modified (after a delay) + UpdateSettings(); + + g.Time += g.IO.DeltaTime; + g.WithinFrameScope = true; + g.FrameCount += 1; + g.TooltipOverrideCount = 0; + g.WindowsActiveCount = 0; + g.MenusIdSubmittedThisFrame.resize(0); + + // Calculate frame-rate for the user, as a purely luxurious feature + g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx]; + g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime; + g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame); + g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame)); + g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX; + + // Process input queue (trickle as many events as possible), turn events into writes to IO structure + g.InputEventsTrail.resize(0); + UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue); + + // Update viewports (after processing input queue, so io.MouseHoveredViewport is set) + UpdateViewportsNewFrame(); + + // Setup current font and draw list shared data + g.IO.Fonts->Locked = true; + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); + ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + virtual_space.Add(g.Viewports[n]->GetMainRect()); + g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); + g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; + g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError); + g.DrawListSharedData.InitialFlags = ImDrawListFlags_None; + if (g.Style.AntiAliasedLines) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines; + if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex; + if (g.Style.AntiAliasedFill) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; + if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) + g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; + + // Mark rendering data as invalid to prevent user who may have a handle on it to use it. + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + viewport->DrawDataP.Clear(); + } + + // Drag and drop keep the source ID alive so even if the source disappear our state is consistent + if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) + KeepAliveID(g.DragDropPayload.SourceId); + + // Update HoveredId data + if (!g.HoveredIdPreviousFrame) + g.HoveredIdTimer = 0.0f; + if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) + g.HoveredIdNotActiveTimer = 0.0f; + if (g.HoveredId) + g.HoveredIdTimer += g.IO.DeltaTime; + if (g.HoveredId && g.ActiveId != g.HoveredId) + g.HoveredIdNotActiveTimer += g.IO.DeltaTime; + g.HoveredIdPreviousFrame = g.HoveredId; + g.HoveredId = 0; + g.HoveredIdAllowOverlap = false; + g.HoveredIdDisabled = false; + + // Clear ActiveID if the item is not alive anymore. + // In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd(). + // As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves. + if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId) + { + IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n"); + ClearActiveID(); + } + + // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore) + if (g.ActiveId) + g.ActiveIdTimer += g.IO.DeltaTime; + g.LastActiveIdTimer += g.IO.DeltaTime; + g.ActiveIdPreviousFrame = g.ActiveId; + g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; + g.ActiveIdIsAlive = 0; + g.ActiveIdHasBeenEditedThisFrame = false; + g.ActiveIdPreviousFrameIsAlive = false; + g.ActiveIdIsJustActivated = false; + if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) + g.TempInputId = 0; + if (g.ActiveId == 0) + { + g.ActiveIdUsingNavDirMask = 0x00; + g.ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + g.ActiveIdUsingNavInputMask = 0x00; +#endif + } + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (g.ActiveId == 0) + g.ActiveIdUsingNavInputMask = 0; + else if (g.ActiveIdUsingNavInputMask != 0) + { + // If your custom widget code used: { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); } + // Since IMGUI_VERSION_NUM >= 18804 it should be: { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); } + if (g.ActiveIdUsingNavInputMask & (1 << ImGuiNavInput_Cancel)) + SetKeyOwner(ImGuiKey_Escape, g.ActiveId); + if (g.ActiveIdUsingNavInputMask & ~(1 << ImGuiNavInput_Cancel)) + IM_ASSERT(0); // Other values unsupported + } +#endif + + // Record when we have been stationary as this state is preserved while over same item. + // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values. + // To allow this we should store HoverItemMaxStationaryTime+ID and perform the >= check in IsItemHovered() function. + if (g.HoverItemDelayId != 0 && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay) + g.HoverItemUnlockedStationaryId = g.HoverItemDelayId; + else if (g.HoverItemDelayId == 0) + g.HoverItemUnlockedStationaryId = 0; + if (g.HoveredWindow != NULL && g.MouseStationaryTimer >= g.Style.HoverStationaryDelay) + g.HoverWindowUnlockedStationaryId = g.HoveredWindow->ID; + else if (g.HoveredWindow == NULL) + g.HoverWindowUnlockedStationaryId = 0; + + // Update hover delay for IsItemHovered() with delays and tooltips + g.HoverItemDelayIdPreviousFrame = g.HoverItemDelayId; + if (g.HoverItemDelayId != 0) + { + g.HoverItemDelayTimer += g.IO.DeltaTime; + g.HoverItemDelayClearTimer = 0.0f; + g.HoverItemDelayId = 0; + } + else if (g.HoverItemDelayTimer > 0.0f) + { + // This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps + // We could expose 0.25f as style.HoverClearDelay but I am not sure of the logic yet, this is particularly subtle. + g.HoverItemDelayClearTimer += g.IO.DeltaTime; + if (g.HoverItemDelayClearTimer >= ImMax(0.25f, g.IO.DeltaTime * 2.0f)) // ~7 frames at 30 Hz + allow for low framerate + g.HoverItemDelayTimer = g.HoverItemDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer. + } + + // Drag and drop + g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; + g.DragDropAcceptIdCurr = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropWithinSource = false; + g.DragDropWithinTarget = false; + g.DragDropHoldJustPressedId = 0; + + // Close popups on focus lost (currently wip/opt-in) + //if (g.IO.AppFocusLost) + // ClosePopupsExceptModals(); + + // Update keyboard input state + UpdateKeyboardInputs(); + + //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiKey_RightCtrl)); + //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGuiKey_RightShift)); + //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt)); + //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper)); + + // Update gamepad/keyboard navigation + NavUpdate(); + + // Update mouse input state + UpdateMouseInputs(); + + // Find hovered window + // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) + UpdateHoveredWindowAndCaptureFlags(); + + // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) + UpdateMouseMovingWindowNewFrame(); + + // Background darkening/whitening + if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f)) + g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); + else + g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); + + g.MouseCursor = ImGuiMouseCursor_Arrow; + g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; + + // Platform IME data: reset for the frame + g.PlatformImeDataPrev = g.PlatformImeData; + g.PlatformImeData.WantVisible = false; + + // Mouse wheel scrolling, scale + UpdateMouseWheel(); + + // Mark all windows as not visible and compact unused memory. + IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); + const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + window->WasActive = window->Active; + window->Active = false; + window->WriteAccessed = false; + window->BeginCountPreviousFrame = window->BeginCount; + window->BeginCount = 0; + + // Garbage collect transient buffers of recently unused windows + if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) + GcCompactTransientWindowBuffers(window); + } + + // Garbage collect transient buffers of recently unused tables + for (int i = 0; i < g.TablesLastTimeActive.Size; i++) + if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) + TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); + for (int i = 0; i < g.TablesTempData.Size; i++) + if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time) + TableGcCompactTransientBuffers(&g.TablesTempData[i]); + if (g.GcCompactAll) + GcCompactTransientMiscBuffers(); + g.GcCompactAll = false; + + // Closing the focused window restore focus to the first active root window in descending z-order + if (g.NavWindow && !g.NavWindow->WasActive) + FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); + + // No window should be open at the beginning of the frame. + // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. + g.CurrentWindowStack.resize(0); + g.BeginPopupStack.resize(0); + g.ItemFlagsStack.resize(0); + g.ItemFlagsStack.push_back(ImGuiItemFlags_None); + g.GroupStack.resize(0); + + // [DEBUG] Update debug features + UpdateDebugToolItemPicker(); + UpdateDebugToolStackQueries(); + if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0) + g.DebugLocateId = 0; + if (g.DebugLogClipperAutoDisableFrames > 0 && --g.DebugLogClipperAutoDisableFrames == 0) + { + DebugLog("(Auto-disabled ImGuiDebugLogFlags_EventClipper to avoid spamming)\n"); + g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper; + } + + // Create implicit/fallback window - which we will only render it if the user has added something to it. + // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. + // This fallback is particularly important as it prevents ImGui:: calls from crashing. + g.WithinFrameScopeWithImplicitWindow = true; + SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); + Begin("Debug##Default"); + IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + + // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack, + // allowing to validate correct Begin/End behavior in user code. + if (g.IO.ConfigDebugBeginReturnValueLoop) + g.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10); + else + g.DebugBeginReturnValueCullDepth = -1; + + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); +} + +// FIXME: Add a more explicit sort order in the window structure. +static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs) +{ + const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs; + const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs; + if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) + return d; + if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) + return d; + return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); +} + +static void AddWindowToSortBuffer(ImVector* out_sorted_windows, ImGuiWindow* window) +{ + out_sorted_windows->push_back(window); + if (window->Active) + { + int count = window->DC.ChildWindows.Size; + ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); + for (int i = 0; i < count; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (child->Active) + AddWindowToSortBuffer(out_sorted_windows, child); + } + } +} + +static void AddWindowToDrawData(ImGuiWindow* window, int layer) +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = g.Viewports[0]; + g.IO.MetricsRenderWindows++; + ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList); + for (int i = 0; i < window->DC.ChildWindows.Size; i++) + { + ImGuiWindow* child = window->DC.ChildWindows[i]; + if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active + AddWindowToDrawData(child, layer); + } +} + +static inline int GetWindowDisplayLayer(ImGuiWindow* window) +{ + return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; +} + +// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) +static inline void AddRootWindowToDrawData(ImGuiWindow* window) +{ + AddWindowToDrawData(window, GetWindowDisplayLayer(window)); +} + +static void FlattenDrawDataIntoSingleLayer(ImDrawDataBuilder* builder) +{ + int n = builder->Layers[0]->Size; + int full_size = n; + for (int i = 1; i < IM_ARRAYSIZE(builder->Layers); i++) + full_size += builder->Layers[i]->Size; + builder->Layers[0]->resize(full_size); + for (int layer_n = 1; layer_n < IM_ARRAYSIZE(builder->Layers); layer_n++) + { + ImVector* layer = builder->Layers[layer_n]; + if (layer->empty()) + continue; + memcpy(builder->Layers[0]->Data + n, layer->Data, layer->Size * sizeof(ImDrawList*)); + n += layer->Size; + layer->resize(0); + } +} + +static void InitViewportDrawData(ImGuiViewportP* viewport) +{ + ImGuiIO& io = ImGui::GetIO(); + ImDrawData* draw_data = &viewport->DrawDataP; + + viewport->DrawDataBuilder.Layers[0] = &draw_data->CmdLists; + viewport->DrawDataBuilder.Layers[1] = &viewport->DrawDataBuilder.LayerData1; + viewport->DrawDataBuilder.Layers[0]->resize(0); + viewport->DrawDataBuilder.Layers[1]->resize(0); + + draw_data->Valid = true; + draw_data->CmdListsCount = 0; + draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; + draw_data->DisplayPos = viewport->Pos; + draw_data->DisplaySize = viewport->Size; + draw_data->FramebufferScale = io.DisplayFramebufferScale; + draw_data->OwnerViewport = viewport; +} + +// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. +// - When using this function it is sane to ensure that float are perfectly rounded to integer values, +// so that e.g. (int)(max.x-min.x) in user's render produce correct result. +// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): +// some frequently called functions which to modify both channels and clipping simultaneously tend to use the +// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. +void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +void ImGui::PopClipRect() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DrawList->PopClipRect(); + window->ClipRect = window->DrawList->_ClipRectStack.back(); +} + +static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport(); + ImRect viewport_rect = viewport->GetMainRect(); + + // Draw behind window by moving the draw command at the FRONT of the draw list + { + // We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows, + // and draw list have been trimmed already, hence the explicit recreation of a draw command if missing. + // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order. + ImDrawList* draw_list = window->RootWindow->DrawList; + if (draw_list->CmdBuffer.Size == 0) + draw_list->AddDrawCmd(); + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) + draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); + ImDrawCmd cmd = draw_list->CmdBuffer.back(); + IM_ASSERT(cmd.ElemCount == 6); + draw_list->CmdBuffer.pop_back(); + draw_list->CmdBuffer.push_front(cmd); + draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.back().IdxOffset won't be correct if we append to same command. + draw_list->PopClipRect(); + } +} + +ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* parent_window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* bottom_most_visible_window = parent_window; + for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + if (!IsWindowWithinBeginStackOf(window, parent_window)) + break; + if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window)) + bottom_most_visible_window = window; + } + return bottom_most_visible_window; +} + +static void ImGui::RenderDimmedBackgrounds() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal(); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + return; + const bool dim_bg_for_modal = (modal_window != NULL); + const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active); + if (!dim_bg_for_modal && !dim_bg_for_window_list) + return; + + if (dim_bg_for_modal) + { + // Draw dimming behind modal or a begin stack child, whichever comes first in draw order. + ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginStack(modal_window); + RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio)); + } + else if (dim_bg_for_window_list) + { + // Draw dimming behind CTRL+Tab target window + RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio)); + + // Draw border around CTRL+Tab target window + ImGuiWindow* window = g.NavWindowingTargetAnim; + ImGuiViewport* viewport = GetMainViewport(); + float distance = g.FontSize; + ImRect bb = window->Rect(); + bb.Expand(distance); + if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y) + bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward + if (window->DrawList->CmdBuffer.Size == 0) + window->DrawList->AddDrawCmd(); + window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); + window->DrawList->PopClipRect(); + } +} + +// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. +void ImGui::EndFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + // Don't process EndFrame() multiple times. + if (g.FrameCountEnded == g.FrameCount) + return; + IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePre); + + ErrorCheckEndFrameSanityChecks(); + + // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) + ImGuiPlatformImeData* ime_data = &g.PlatformImeData; + if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) + { + IMGUI_DEBUG_LOG_IO("[io] Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); + ImGuiViewport* viewport = GetMainViewport(); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (viewport->PlatformHandleRaw == NULL && g.IO.ImeWindowHandle != NULL) + { + viewport->PlatformHandleRaw = g.IO.ImeWindowHandle; + g.IO.SetPlatformImeDataFn(viewport, ime_data); + viewport->PlatformHandleRaw = NULL; + } + else +#endif + { + g.IO.SetPlatformImeDataFn(viewport, ime_data); + } + } + + // Hide implicit/fallback "Debug" window if it hasn't been used + g.WithinFrameScopeWithImplicitWindow = false; + if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) + g.CurrentWindow->Active = false; + End(); + + // Update navigation: CTRL+Tab, wrap-around requests + NavEndFrame(); + + // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted) + if (g.DragDropActive) + { + bool is_delivered = g.DragDropPayload.Delivery; + bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton)); + if (is_delivered || is_elapsed) + ClearDragDrop(); + } + + // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing. + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + g.DragDropWithinSource = true; + SetTooltip("..."); + g.DragDropWithinSource = false; + } + + // End frame + g.WithinFrameScope = false; + g.FrameCountEnded = g.FrameCount; + + // Initiate moving window + handle left-click and right-click focus + UpdateMouseMovingWindowEndFrame(); + + // Sort the window list so that all child windows are after their parent + // We cannot do that on FocusWindow() because children may not exist yet + g.WindowsTempSortBuffer.resize(0); + g.WindowsTempSortBuffer.reserve(g.Windows.Size); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it + continue; + AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); + } + + // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. + IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size); + g.Windows.swap(g.WindowsTempSortBuffer); + g.IO.MetricsActiveWindows = g.WindowsActiveCount; + + // Unlock font atlas + g.IO.Fonts->Locked = false; + + // Clear Input data for next frame + g.IO.AppFocusLost = false; + g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f; + g.IO.InputQueueCharacters.resize(0); + + CallContextHooks(&g, ImGuiContextHookType_EndFramePost); +} + +// Prepare the data for rendering so you can call GetDrawData() +// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all: +// it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend) +void ImGui::Render() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + + if (g.FrameCountEnded != g.FrameCount) + EndFrame(); + const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount); + g.FrameCountRendered = g.FrameCount; + g.IO.MetricsRenderWindows = 0; + + CallContextHooks(&g, ImGuiContextHookType_RenderPre); + + // Add background ImDrawList (for each active viewport) + for (int n = 0; n != g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + InitViewportDrawData(viewport); + if (viewport->DrawLists[0] != NULL) + AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); + } + + // Draw modal/window whitening backgrounds + if (first_render_of_frame) + RenderDimmedBackgrounds(); + + // Add ImDrawList to render + ImGuiWindow* windows_to_render_top_most[2]; + windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; + windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL); + for (int n = 0; n != g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) + AddRootWindowToDrawData(window); + } + for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++) + if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window + AddRootWindowToDrawData(windows_to_render_top_most[n]); + + // Draw software mouse cursor if requested by io.MouseDrawCursor flag + if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None) + RenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); + + // Setup ImDrawData structures for end-user + g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder); + + // Add foreground ImDrawList (for each active viewport) + if (viewport->DrawLists[1] != NULL) + AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); + + // We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch). + ImDrawData* draw_data = &viewport->DrawDataP; + IM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount); + for (int draw_list_n = 0; draw_list_n < draw_data->CmdLists.Size; draw_list_n++) + draw_data->CmdLists[draw_list_n]->_PopUnusedDrawCmd(); + + g.IO.MetricsRenderVertices += draw_data->TotalVtxCount; + g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; + } + + CallContextHooks(&g, ImGuiContextHookType_RenderPost); +} + +// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker. +// CalcTextSize("") should return ImVec2(0.0f, g.FontSize) +ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) +{ + ImGuiContext& g = *GImGui; + + const char* text_display_end; + if (hide_text_after_double_hash) + text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string + else + text_display_end = text_end; + + ImFont* font = g.Font; + const float font_size = g.FontSize; + if (text == text_display_end) + return ImVec2(0.0f, font_size); + ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); + + // Round + // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. + // FIXME: Investigate using ceilf or e.g. + // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c + // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html + text_size.x = IM_FLOOR(text_size.x + 0.99999f); + + return text_size; +} + +// Find window given position, search front-to-back +// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically +// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is +// called, aka before the next Begin(). Moving window isn't affected. +static void FindHoveredWindow() +{ + ImGuiContext& g = *GImGui; + + ImGuiWindow* hovered_window = NULL; + ImGuiWindow* hovered_window_ignoring_moving_window = NULL; + if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs)) + hovered_window = g.MovingWindow; + + ImVec2 padding_regular = g.Style.TouchExtraPadding; + ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular; + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* window = g.Windows[i]; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. + if (!window->Active || window->Hidden) + continue; + if (window->Flags & ImGuiWindowFlags_NoMouseInputs) + continue; + + // Using the clipped AABB, a child window will typically be clipped by its parent (not always) + ImRect bb(window->OuterRectClipped); + if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) + bb.Expand(padding_regular); + else + bb.Expand(padding_for_resize); + if (!bb.Contains(g.IO.MousePos)) + continue; + + // Support for one rectangular hole in any given window + // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512) + if (window->HitTestHoleSize.x != 0) + { + ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y); + ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y); + if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos)) + continue; + } + + if (hovered_window == NULL) + hovered_window = window; + IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. + if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) + hovered_window_ignoring_moving_window = window; + if (hovered_window && hovered_window_ignoring_moving_window) + break; + } + + g.HoveredWindow = hovered_window; + g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; +} + +bool ImGui::IsItemActive() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + return g.ActiveId == g.LastItemData.ID; + return false; +} + +bool ImGui::IsItemActivated() +{ + ImGuiContext& g = *GImGui; + if (g.ActiveId) + if (g.ActiveId == g.LastItemData.ID && g.ActiveIdPreviousFrame != g.LastItemData.ID) + return true; + return false; +} + +bool ImGui::IsItemDeactivated() +{ + ImGuiContext& g = *GImGui; + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated) + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; + return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID); +} + +bool ImGui::IsItemDeactivatedAfterEdit() +{ + ImGuiContext& g = *GImGui; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); +} + +// == GetItemID() == GetFocusID() +bool ImGui::IsItemFocused() +{ + ImGuiContext& g = *GImGui; + if (g.NavId != g.LastItemData.ID || g.NavId == 0) + return false; + return true; +} + +// Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()! +// Most widgets have specific reactions based on mouse-up/down state, mouse position etc. +bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button) +{ + return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); +} + +bool ImGui::IsItemToggledOpen() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false; +} + +bool ImGui::IsItemToggledSelection() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false; +} + +bool ImGui::IsAnyItemHovered() +{ + ImGuiContext& g = *GImGui; + return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0; +} + +bool ImGui::IsAnyItemActive() +{ + ImGuiContext& g = *GImGui; + return g.ActiveId != 0; +} + +bool ImGui::IsAnyItemFocused() +{ + ImGuiContext& g = *GImGui; + return g.NavId != 0 && !g.NavDisableHighlight; +} + +bool ImGui::IsItemVisible() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) != 0; +} + +bool ImGui::IsItemEdited() +{ + ImGuiContext& g = *GImGui; + return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Edited) != 0; +} + +// Allow next item to be overlapped by subsequent items. +// This works by requiring HoveredId to match for two subsequent frames, +// so if a following items overwrite it our interactions will naturally be disabled. +void ImGui::SetNextItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + g.NextItemData.ItemFlags |= ImGuiItemflags_AllowOverlap; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority. +// FIXME-LEGACY: Use SetNextItemAllowOverlap() *before* your item instead. +void ImGui::SetItemAllowOverlap() +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.LastItemData.ID; + if (g.HoveredId == id) + g.HoveredIdAllowOverlap = true; + if (g.ActiveId == id) // Before we made this obsolete, most calls to SetItemAllowOverlap() used to avoid this path by testing g.ActiveId != id. + g.ActiveIdAllowOverlap = true; +} +#endif + +// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function. +void ImGui::SetActiveIdUsingAllKeyboardKeys() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ActiveId != 0); + g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_COUNT) - 1; + g.ActiveIdUsingAllKeyboardKeys = true; + NavMoveRequestCancel(); +} + +ImGuiID ImGui::GetItemID() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.ID; +} + +ImVec2 ImGui::GetItemRectMin() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.Min; +} + +ImVec2 ImGui::GetItemRectMax() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.Max; +} + +ImVec2 ImGui::GetItemRectSize() +{ + ImGuiContext& g = *GImGui; + return g.LastItemData.Rect.GetSize(); +} + +bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + + flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow; + flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove); // Inherit the NoMove flag + + // Size + const ImVec2 content_avail = GetContentRegionAvail(); + ImVec2 size = ImFloor(size_arg); + const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00); + if (size.x <= 0.0f) + size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too many issues) + if (size.y <= 0.0f) + size.y = ImMax(content_avail.y + size.y, 4.0f); + SetNextWindowSize(size); + + // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. + const char* temp_window_name; + if (name) + ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s_%08X", parent_window->Name, name, id); + else + ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id); + + const float backup_border_size = g.Style.ChildBorderSize; + if (!border) + g.Style.ChildBorderSize = 0.0f; + bool ret = Begin(temp_window_name, NULL, flags); + g.Style.ChildBorderSize = backup_border_size; + + ImGuiWindow* child_window = g.CurrentWindow; + child_window->ChildId = id; + child_window->AutoFitChildAxises = (ImS8)auto_fit_axises; + + // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually. + // While this is not really documented/defined, it seems that the expected thing to do. + if (child_window->BeginCount == 1) + parent_window->DC.CursorPos = child_window->Pos; + + // Process navigation-in immediately so NavInit can run on first frame + // Can enter a child if (A) it has navigatable items or (B) it can be scrolled. + const ImGuiID temp_id_for_activation = ImHashStr("##Child", 0, id); + if (g.ActiveId == temp_id_for_activation) + ClearActiveID(); + if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY)) + { + FocusWindow(child_window); + NavInitWindow(child_window, false); + SetActiveID(temp_id_for_activation, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item + g.ActiveIdSource = g.NavInputSource; + } + return ret; +} + +bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags); +} + +bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) +{ + IM_ASSERT(id != 0); + return BeginChildEx(NULL, id, size_arg, border, extra_flags); +} + +void ImGui::EndChild() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + IM_ASSERT(g.WithinEndChild == false); + IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls + + g.WithinEndChild = true; + if (window->BeginCount > 1) + { + End(); + } + else + { + ImVec2 sz = window->Size; + if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f + sz.x = ImMax(4.0f, sz.x); + if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y)) + sz.y = ImMax(4.0f, sz.y); + End(); + + ImGuiWindow* parent_window = g.CurrentWindow; + ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz); + ItemSize(sz); + if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavWindowHasScrollY) && !(window->Flags & ImGuiWindowFlags_NavFlattened)) + { + ItemAdd(bb, window->ChildId); + RenderNavHighlight(bb, window->ChildId); + + // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying) + if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow) + RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin); + } + else + { + // Not navigable into + ItemAdd(bb, 0); + + // But when flattened we directly reach items, adjust active layer mask accordingly + if (window->Flags & ImGuiWindowFlags_NavFlattened) + parent_window->DC.NavLayersActiveMaskNext |= window->DC.NavLayersActiveMaskNext; + } + if (g.HoveredWindow == window) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + } + g.WithinEndChild = false; + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return +} + +// Helper to create a child window / scrolling region that looks like a normal widget frame. +bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); + bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags); + PopStyleVar(3); + PopStyleColor(); + return ret; +} + +void ImGui::EndChildFrame() +{ + EndChild(); +} + +static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled) +{ + window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags & ~flags); + window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags & ~flags); + window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags); +} + +ImGuiWindow* ImGui::FindWindowByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id); +} + +ImGuiWindow* ImGui::FindWindowByName(const char* name) +{ + ImGuiID id = ImHashStr(name); + return FindWindowByID(id); +} + +static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +{ + window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y)); + if (settings->Size.x > 0 && settings->Size.y > 0) + window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y)); + window->Collapsed = settings->Collapsed; +} + +static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) +{ + ImGuiContext& g = *GImGui; + + const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0); + const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; + if ((just_created || child_flag_changed) && !new_is_explicit_child) + { + IM_ASSERT(!g.WindowsFocusOrder.contains(window)); + g.WindowsFocusOrder.push_back(window); + window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); + } + else if (!just_created && child_flag_changed && new_is_explicit_child) + { + IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); + for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) + g.WindowsFocusOrder[n]->FocusOrder--; + g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); + window->FocusOrder = -1; + } + window->IsExplicitChild = new_is_explicit_child; +} + +static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) +{ + // Initial window state with e.g. default/arbitrary window position + // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + window->Pos = main_viewport->Pos + ImVec2(60, 60); + window->SetWindowPosAllowFlags = window->SetWindowSizeAllowFlags = window->SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + + if (settings != NULL) + { + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } + window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values + + if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + { + window->AutoFitFramesX = window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = false; + } + else + { + if (window->Size.x <= 0.0f) + window->AutoFitFramesX = 2; + if (window->Size.y <= 0.0f) + window->AutoFitFramesY = 2; + window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); + } +} + +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +{ + // Create window the first time + //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + ImGuiWindowSettings* settings = NULL; + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0) + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + + InitOrLoadWindowSettings(window, settings); + + if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) + g.Windows.push_front(window); // Quite slow but rare and only once + else + g.Windows.push_back(window); + + return window; +} + +static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired) +{ + ImGuiContext& g = *GImGui; + ImVec2 new_size = size_desired; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + { + // Using -1,-1 on either X/Y axis to preserve the current size. + ImRect cr = g.NextWindowData.SizeConstraintRect; + new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x; + new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y; + if (g.NextWindowData.SizeCallback) + { + ImGuiSizeCallbackData data; + data.UserData = g.NextWindowData.SizeCallbackUserData; + data.Pos = window->Pos; + data.CurrentSize = window->SizeFull; + data.DesiredSize = new_size; + g.NextWindowData.SizeCallback(&data); + new_size = data.DesiredSize; + } + new_size.x = IM_FLOOR(new_size.x); + new_size.y = IM_FLOOR(new_size.y); + } + + // Minimum size + if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + { + ImGuiWindow* window_for_height = window; + new_size = ImMax(new_size, g.Style.WindowMinSize); + const float minimum_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f); + new_size.y = ImMax(new_size.y, minimum_height); // Reduce artifacts with very small windows + } + return new_size; +} + +static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal) +{ + bool preserve_old_content_sizes = false; + if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) + preserve_old_content_sizes = true; + else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0) + preserve_old_content_sizes = true; + if (preserve_old_content_sizes) + { + *content_size_current = window->ContentSize; + *content_size_ideal = window->ContentSizeIdeal; + return; + } + + content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x); + content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y); +} + +static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + const float decoration_w_without_scrollbars = window->DecoOuterSizeX1 + window->DecoOuterSizeX2 - window->ScrollbarSizes.x; + const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y; + ImVec2 size_pad = window->WindowPadding * 2.0f; + ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars); + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Tooltip always resize + return size_desired; + } + else + { + // Maximum window size is determined by the viewport size or monitor size + const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0; + const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0; + ImVec2 size_min = style.WindowMinSize; + if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups) + size_min = ImMin(size_min, ImVec2(4.0f, 4.0f)); + + ImVec2 avail_size = ImGui::GetMainViewport()->WorkSize; + ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f)); + + // When the window cannot fit all contents (either because of constraints, either because screen is too small), + // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. + ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); + bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); + bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); + if (will_have_scrollbar_x) + size_auto_fit.y += style.ScrollbarSize; + if (will_have_scrollbar_y) + size_auto_fit.x += style.ScrollbarSize; + return size_auto_fit; + } +} + +ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window) +{ + ImVec2 size_contents_current; + ImVec2 size_contents_ideal; + CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal); + ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal); + ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit); + return size_final; +} + +static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window) +{ + if (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + return ImGuiCol_PopupBg; + if (window->Flags & ImGuiWindowFlags_ChildWindow) + return ImGuiCol_ChildBg; + return ImGuiCol_WindowBg; +} + +static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) +{ + ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left + ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right + ImVec2 size_expected = pos_max - pos_min; + ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected); + *out_pos = pos_min; + if (corner_norm.x == 0.0f) + out_pos->x -= (size_constrained.x - size_expected.x); + if (corner_norm.y == 0.0f) + out_pos->y -= (size_constrained.y - size_expected.y); + *out_size = size_constrained; +} + +// Data for resizing from corner +struct ImGuiResizeGripDef +{ + ImVec2 CornerPosN; + ImVec2 InnerDir; + int AngleMin12, AngleMax12; +}; +static const ImGuiResizeGripDef resize_grip_def[4] = +{ + { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right + { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left + { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused) + { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused) +}; + +// Data for resizing from borders +struct ImGuiResizeBorderDef +{ + ImVec2 InnerDir; + ImVec2 SegmentN1, SegmentN2; + float OuterAngle; +}; +static const ImGuiResizeBorderDef resize_border_def[4] = +{ + { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left + { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right + { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up + { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down +}; + +static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness) +{ + ImRect rect = window->Rect(); + if (thickness == 0.0f) + rect.Max -= ImVec2(1, 1); + if (border_n == ImGuiDir_Left) { return ImRect(rect.Min.x - thickness, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x + thickness, rect.Max.y - perp_padding); } + if (border_n == ImGuiDir_Up) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness, rect.Max.x - perp_padding, rect.Min.y + thickness); } + if (border_n == ImGuiDir_Down) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y + thickness); } + IM_ASSERT(0); + return ImRect(); +} + +// 0..3: corners (Lower-right, Lower-left, Unused, Unused) +ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n) +{ + IM_ASSERT(n >= 0 && n < 4); + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Borders (Left, Right, Up, Down) +ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir) +{ + IM_ASSERT(dir >= 0 && dir < 4); + int n = (int)dir + 4; + ImGuiID id = window->ID; + id = ImHashStr("#RESIZE", 0, id); + id = ImHashData(&n, sizeof(int), id); + return id; +} + +// Handle resize for: Resize Grips, Borders, Gamepad +// Return true when using auto-fit (double-click on resize grip) +static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect) +{ + ImGuiContext& g = *GImGui; + ImGuiWindowFlags flags = window->Flags; + + if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + return false; + if (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window. + return false; + + bool ret_auto_fit = false; + const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0; + const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f); + const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; + + ImRect clamp_rect = visibility_rect; + const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar); + if (window_move_from_title_bar) + clamp_rect.Min.y -= window->TitleBarHeight(); + + ImVec2 pos_target(FLT_MAX, FLT_MAX); + ImVec2 size_target(FLT_MAX, FLT_MAX); + + // Resize grips and borders are on layer 1 + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + + // Manual resize grips + PushID("#RESIZE"); + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN); + + // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window + bool hovered, held; + ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size); + if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x); + if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y); + ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID() + ItemAdd(resize_rect, resize_grip_id, NULL, ImGuiItemFlags_NoNav); + ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); + if (hovered || held) + g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; + + if (held && g.IO.MouseClickedCount[0] == 2 && resize_grip_n == 0) + { + // Manual auto-fit when double-clicking + size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); + ret_auto_fit = true; + ClearActiveID(); + } + else if (held) + { + // Resize from any of the four corners + // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position + ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? clamp_rect.Min.x : -FLT_MAX, (def.CornerPosN.y == 1.0f || (def.CornerPosN.y == 0.0f && window_move_from_title_bar)) ? clamp_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? clamp_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? clamp_rect.Max.y : +FLT_MAX); + ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip + corner_target = ImClamp(corner_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target); + } + + // Only lower-left grip is visible before hovering/activating + if (resize_grip_n == 0 || held || hovered) + resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + } + for (int border_n = 0; border_n < resize_border_count; border_n++) + { + const ImGuiResizeBorderDef& def = resize_border_def[border_n]; + const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; + + bool hovered, held; + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID() + ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav); + ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); + //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255)); + if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held) + { + g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; + if (held) + *border_held = border_n; + } + if (held) + { + ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX); + ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX); + ImVec2 border_target = window->Pos; + border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; + border_target = ImClamp(border_target, clamp_min, clamp_max); + CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); + } + } + PopID(); + + // Restore nav layer + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + + // Navigation resize (keyboard/gamepad) + // FIXME: This cannot be moved to NavUpdateWindowing() because CalcWindowSizeAfterConstraint() need to callback into user. + // Not even sure the callback works here. + if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) + { + ImVec2 nav_resize_dir; + if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift) + nav_resize_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); + if (g.NavInputSource == ImGuiInputSource_Gamepad) + nav_resize_dir = GetKeyMagnitude2d(ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown); + if (nav_resize_dir.x != 0.0f || nav_resize_dir.y != 0.0f) + { + const float NAV_RESIZE_SPEED = 600.0f; + const float resize_step = NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y); + g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step; + g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size + g.NavWindowingToggleLayer = false; + g.NavDisableMouseHover = true; + resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); + ImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaSize); + if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) + { + // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck. + size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + accum_floored); + g.NavWindowingAccumDeltaSize -= accum_floored; + } + } + } + + // Apply back modified position/size to window + if (size_target.x != FLT_MAX) + { + window->SizeFull = size_target; + MarkIniSettingsDirty(window); + } + if (pos_target.x != FLT_MAX) + { + window->Pos = ImFloor(pos_target); + MarkIniSettingsDirty(window); + } + + window->Size = window->SizeFull; + return ret_auto_fit; +} + +static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_rect) +{ + ImGuiContext& g = *GImGui; + ImVec2 size_for_clamping = window->Size; + if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + size_for_clamping.y = window->TitleBarHeight(); + window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max); +} + +static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + float rounding = window->WindowRounding; + float border_size = window->WindowBorderSize; + if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground)) + window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); + + int border_held = window->ResizeBorderHeld; + if (border_held != -1) + { + const ImGuiResizeBorderDef& def = resize_border_def[border_held]; + ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle); + window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual + } + if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + { + float y = window->Pos.y + window->TitleBarHeight() - 1; + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize); + } +} + +// Draw background and borders +// Draw and handle scrollbars +void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, bool handle_borders_and_resize_grips, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + // Ensure that ScrollBar doesn't read last frame's SkipItems + IM_ASSERT(window->BeginCount == 0); + window->SkipItems = false; + + // Draw window + handle manual resize + // As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame. + const float window_rounding = window->WindowRounding; + const float window_border_size = window->WindowBorderSize; + if (window->Collapsed) + { + // Title bar only + const float backup_border_size = style.FrameBorderSize; + g.Style.FrameBorderSize = window->WindowBorderSize; + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); + g.Style.FrameBorderSize = backup_border_size; + } + else + { + // Window background + if (!(flags & ImGuiWindowFlags_NoBackground)) + { + ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window)); + bool override_alpha = false; + float alpha = 1.0f; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) + { + alpha = g.NextWindowData.BgAlphaVal; + override_alpha = true; + } + if (override_alpha) + bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT); + window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom); + } + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); + window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop); + } + + // Menu bar + if (flags & ImGuiWindowFlags_MenuBar) + { + ImRect menu_bar_rect = window->MenuBarRect(); + menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); + if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + } + + // Scrollbars + if (window->ScrollbarX) + Scrollbar(ImGuiAxis_X); + if (window->ScrollbarY) + Scrollbar(ImGuiAxis_Y); + + // Render resize grips (after their input handling so we don't have a frame of latency) + if (handle_borders_and_resize_grips && !(flags & ImGuiWindowFlags_NoResize)) + { + for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++) + { + const ImU32 col = resize_grip_col[resize_grip_n]; + if ((col & IM_COL32_A_MASK) == 0) + continue; + const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; + const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); + window->DrawList->PathFillConvex(col); + } + } + + // Borders + if (handle_borders_and_resize_grips) + RenderWindowOuterBorders(window); + } +} + +// Render title text, collapse button, close button +void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) +{ + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImGuiWindowFlags flags = window->Flags; + + const bool has_close_button = (p_open != NULL); + const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None); + + // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) + // FIXME-NAV: Might want (or not?) to set the equivalent of ImGuiButtonFlags_NoNavFocus so that mouse clicks on standard title bar items don't necessarily set nav/keyboard ref? + const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + + // Layout buttons + // FIXME: Would be nice to generalize the subtleties expressed here into reusable code. + float pad_l = style.FramePadding.x; + float pad_r = style.FramePadding.x; + float button_sz = g.FontSize; + ImVec2 close_button_pos; + ImVec2 collapse_button_pos; + if (has_close_button) + { + pad_r += button_sz; + close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + } + if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) + { + pad_r += button_sz; + collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + } + if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left) + { + collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y); + pad_l += button_sz; + } + + // Collapse button (submitting first so it gets priority when choosing a navigation init fallback) + if (has_collapse_button) + if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos)) + window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function + + // Close button + if (has_close_button) + if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) + *p_open = false; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + g.CurrentItemFlags = item_flags_backup; + + // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker) + // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code.. + const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? button_sz * 0.80f : 0.0f; + const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f); + + // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button, + // while uncentered title text will still reach edges correctly. + if (pad_l > style.FramePadding.x) + pad_l += g.Style.ItemInnerSpacing.x; + if (pad_r > style.FramePadding.x) + pad_r += g.Style.ItemInnerSpacing.x; + if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f) + { + float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center + float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x); + pad_l = ImMax(pad_l, pad_extend * centerness); + pad_r = ImMax(pad_r, pad_extend * centerness); + } + + ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y); + ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y); + if (flags & ImGuiWindowFlags_UnsavedDocument) + { + ImVec2 marker_pos; + marker_pos.x = ImClamp(layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x + text_size.x, layout_r.Min.x, layout_r.Max.x); + marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f; + if (marker_pos.x > layout_r.Min.x) + { + RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text)); + clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f)); + } + } + //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG] + RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r); +} + +void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window) +{ + window->ParentWindow = parent_window; + window->RootWindow = window->RootWindowPopupTree = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window; + if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + window->RootWindow = parent_window->RootWindow; + if (parent_window && (flags & ImGuiWindowFlags_Popup)) + window->RootWindowPopupTree = parent_window->RootWindowPopupTree; + if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) + window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; + while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened) + { + IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL); + window->RootWindowForNav = window->RootWindowForNav->ParentWindow; + } +} + +// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) +// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. +// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. +// - WindowA // FindBlockingModal() returns Modal1 +// - WindowB // .. returns Modal1 +// - Modal1 // .. returns Modal2 +// - WindowC // .. returns Modal2 +// - WindowD // .. returns Modal2 +// - Modal2 // .. returns Modal2 +// - WindowE // .. returns NULL +// Notes: +// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. +// Only difference is here we check for ->Active/WasActive but it may be unecessary. +ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= 0) + return NULL; + + // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; + if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) + continue; + if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. + continue; + if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. + return popup_window; + if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal + continue; + return popup_window; // Place window right below first block modal + } + return NULL; +} + +// Push a new Dear ImGui window to add widgets to. +// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. +// - Begin/End can be called multiple times during the frame with the same window name to append content. +// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file). +// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file. +// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. +// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. +bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + IM_ASSERT(name != NULL && name[0] != '\0'); // Window name required + IM_ASSERT(g.WithinFrameScope); // Forgot to call ImGui::NewFrame() + IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet + + // Find or create + ImGuiWindow* window = FindWindowByName(name); + const bool window_just_created = (window == NULL); + if (window_just_created) + window = CreateNewWindow(name, flags); + + // Automatically disable manual moving/resizing when NoInputs is set + if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs) + flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize; + + if (flags & ImGuiWindowFlags_NavFlattened) + IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow); + + const int current_frame = g.FrameCount; + const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); + window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow); + + // Update the Appearing flag + bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed + window_just_activated_by_user |= (window != popup_ref.Window); + } + window->Appearing = window_just_activated_by_user; + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); + + // Update Flags, LastFrameActive, BeginOrderXXX fields + if (first_begin_of_the_frame) + { + UpdateWindowInFocusOrderList(window, window_just_created, flags); + window->Flags = (ImGuiWindowFlags)flags; + window->LastFrameActive = current_frame; + window->LastTimeActive = (float)g.Time; + window->BeginOrderWithinParent = 0; + window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++); + } + else + { + flags = window->Flags; + } + + // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack + ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window; + ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; + IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); + + // We allow window memory to be compacted so recreate the base stack when needed. + if (window->IDStack.Size == 0) + window->IDStack.push_back(window->ID); + + // Add to stack + // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() + g.CurrentWindow = window; + ImGuiWindowStackData window_stack_data; + window_stack_data.Window = window; + window_stack_data.ParentLastItemDataBackup = g.LastItemData; + window_stack_data.StackSizesOnBegin.SetToContextState(&g); + g.CurrentWindowStack.push_back(window_stack_data); + if (flags & ImGuiWindowFlags_ChildMenu) + g.BeginMenuCount++; + + // Update ->RootWindow and others pointers (before any possible call to FocusWindow) + if (first_begin_of_the_frame) + { + UpdateWindowParentAndRootLinks(window, flags, parent_window); + window->ParentWindowInBeginStack = parent_window_in_stack; + } + + // Add to focus scope stack + PushFocusScope(window->ID); + window->NavRootFocusScopeId = g.CurrentFocusScopeId; + g.CurrentWindow = NULL; + + // Add to popup stack + if (flags & ImGuiWindowFlags_Popup) + { + ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; + popup_ref.Window = window; + popup_ref.ParentNavLayer = parent_window_in_stack->DC.NavLayerCurrent; + g.BeginPopupStack.push_back(popup_ref); + window->PopupId = popup_ref.PopupId; + } + + // Process SetNextWindow***() calls + // (FIXME: Consider splitting the HasXXX flags into X/Y components + bool window_pos_set_by_api = false; + bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) + { + window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; + if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) + { + // May be processed on the next frame if this is our first frame and we are measuring size + // FIXME: Look into removing the branch so everything can go through this same code path for consistency. + window->SetWindowPosVal = g.NextWindowData.PosVal; + window->SetWindowPosPivot = g.NextWindowData.PosPivotVal; + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + } + else + { + SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); + } + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) + { + window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); + window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); + SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) + { + if (g.NextWindowData.ScrollVal.x >= 0.0f) + { + window->ScrollTarget.x = g.NextWindowData.ScrollVal.x; + window->ScrollTargetCenterRatio.x = 0.0f; + } + if (g.NextWindowData.ScrollVal.y >= 0.0f) + { + window->ScrollTarget.y = g.NextWindowData.ScrollVal.y; + window->ScrollTargetCenterRatio.y = 0.0f; + } + } + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) + window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; + else if (first_begin_of_the_frame) + window->ContentSizeExplicit = ImVec2(0.0f, 0.0f); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) + SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) + FocusWindow(window); + if (window->Appearing) + SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); + + // When reusing window again multiple times a frame, just append content (don't need to setup again) + if (first_begin_of_the_frame) + { + // Initialize + const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) + const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0); + window->Active = true; + window->HasCloseButton = (p_open != NULL); + window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX); + window->IDStack.resize(1); + window->DrawList->_ResetForNewFrame(); + window->DC.CurrentTableIdx = -1; + + // Restore buffer capacity when woken from a compacted state, to avoid + if (window->MemoryCompacted) + GcAwakeTransientWindowBuffers(window); + + // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). + // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. + bool window_title_visible_elsewhere = false; + if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) + { + size_t buf_len = (size_t)window->NameBufLen; + window->Name = ImStrdupcpy(window->Name, &buf_len, name); + window->NameBufLen = (int)buf_len; + } + + // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS + + // Update contents size from last frame for auto-fitting (or use explicit size) + CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal); + if (window->HiddenFramesCanSkipItems > 0) + window->HiddenFramesCanSkipItems--; + if (window->HiddenFramesCannotSkipItems > 0) + window->HiddenFramesCannotSkipItems--; + if (window->HiddenFramesForRenderOnly > 0) + window->HiddenFramesForRenderOnly--; + + // Hide new windows for one frame until they calculate their size + if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) + window->HiddenFramesCannotSkipItems = 1; + + // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows) + // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size. + if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0) + { + window->HiddenFramesCannotSkipItems = 1; + if (flags & ImGuiWindowFlags_AlwaysAutoResize) + { + if (!window_size_x_set_by_api) + window->Size.x = window->SizeFull.x = 0.f; + if (!window_size_y_set_by_api) + window->Size.y = window->SizeFull.y = 0.f; + window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f); + } + } + + // SELECT VIEWPORT + // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style) + + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + SetWindowViewport(window, viewport); + SetCurrentWindow(window); + + // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies) + + if (flags & ImGuiWindowFlags_ChildWindow) + window->WindowBorderSize = style.ChildBorderSize; + else + window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize; + window->WindowPadding = style.WindowPadding; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f) + window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f); + + // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. + window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); + window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; + + bool use_current_size_for_scrollbar_x = window_just_created; + bool use_current_size_for_scrollbar_y = window_just_created; + + // Collapse window by double-clicking on title bar + // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing + if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse)) + { + // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. + ImRect title_bar_rect = window->TitleBarRect(); + if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseClickedCount[0] == 2) + window->WantCollapseToggle = true; + if (window->WantCollapseToggle) + { + window->Collapsed = !window->Collapsed; + if (!window->Collapsed) + use_current_size_for_scrollbar_y = true; + MarkIniSettingsDirty(window); + } + } + else + { + window->Collapsed = false; + } + window->WantCollapseToggle = false; + + // SIZE + + // Outer Decoration Sizes + // (we need to clear ScrollbarSize immediatly as CalcWindowAutoFitSize() needs it and can be called from other locations). + const ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes; + window->DecoOuterSizeX1 = 0.0f; + window->DecoOuterSizeX2 = 0.0f; + window->DecoOuterSizeY1 = window->TitleBarHeight() + window->MenuBarHeight(); + window->DecoOuterSizeY2 = 0.0f; + window->ScrollbarSizes = ImVec2(0.0f, 0.0f); + + // Calculate auto-fit size, handle automatic resize + const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal); + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed) + { + // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc. + if (!window_size_x_set_by_api) + { + window->SizeFull.x = size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (!window_size_y_set_by_api) + { + window->SizeFull.y = size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + } + else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + { + // Auto-fit may only grow window during the first few frames + // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (!window_size_x_set_by_api && window->AutoFitFramesX > 0) + { + window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x; + use_current_size_for_scrollbar_x = true; + } + if (!window_size_y_set_by_api && window->AutoFitFramesY > 0) + { + window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y; + use_current_size_for_scrollbar_y = true; + } + if (!window->Collapsed) + MarkIniSettingsDirty(window); + } + + // Apply minimum/maximum window size constraints and final size + window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull); + window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull; + + // POSITION + + // Popup latch its initial position, will position itself when it appears next frame + if (window_just_activated_by_user) + { + window->AutoPosLastDirection = ImGuiDir_None; + if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos() + window->Pos = g.BeginPopupStack.back().OpenPopupPos; + } + + // Position child window + if (flags & ImGuiWindowFlags_ChildWindow) + { + IM_ASSERT(parent_window && parent_window->Active); + window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size; + parent_window->DC.ChildWindows.push_back(window); + if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = parent_window->DC.CursorPos; + } + + const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0); + if (window_pos_with_pivot) + SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering) + else if ((flags & ImGuiWindowFlags_ChildMenu) != 0) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize) + window->Pos = FindBestWindowPosForPopup(window); + else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip) + window->Pos = FindBestWindowPosForPopup(window); + + // Calculate the range of allowed position for that window (to be movable and visible past safe area padding) + // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect. + ImRect viewport_rect(viewport->GetMainRect()); + ImRect viewport_work_rect(viewport->GetWorkRect()); + ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding); + ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding); + + // Clamp position/size so window stays visible within its viewport or monitor + // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing. + if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow)) + if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f) + ClampWindowPos(window, visibility_rect); + window->Pos = ImFloor(window->Pos); + + // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) + // Large values tend to lead to variety of artifacts and are not recommended. + window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + + // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts. + //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f); + + // Apply window focus (new and reactivated windows are moved to front) + bool want_focus = false; + if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) + { + if (flags & ImGuiWindowFlags_Popup) + want_focus = true; + else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) + want_focus = true; + } + + // [Test Engine] Register whole window in the item system (before submitting further decorations) +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (g.TestEngineHookItems) + { + IM_ASSERT(window->IDStack.Size == 1); + window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself. + IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL); + IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); + window->IDStack.Size = 1; + } +#endif + + // Handle manual resize: Resize Grips, Borders, Gamepad + int border_held = -1; + ImU32 resize_grip_col[4] = {}; + const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); + if (!window->Collapsed) + if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) + use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; + window->ResizeBorderHeld = (signed char)border_held; + + // SCROLLBAR VISIBILITY + + // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size). + if (!window->Collapsed) + { + // When reading the current size we need to read it after size constraints have been applied. + // Intentionally use previous frame values for InnerRect and ScrollbarSizes. + // And when we use window->DecorationUp here it doesn't have ScrollbarSizes.y applied yet. + ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)); + ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame; + ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; + float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; + float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? + window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); + window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + if (window->ScrollbarX && !window->ScrollbarY) + window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar); + window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); + + // Amend the partially filled window->DecorationXXX values. + window->DecoOuterSizeX2 += window->ScrollbarSizes.x; + window->DecoOuterSizeY2 += window->ScrollbarSizes.y; + } + + // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING) + // Update various regions. Variables they depend on should be set above in this function. + // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame. + + // Outer rectangle + // Not affected by window border size. Used by: + // - FindHoveredWindow() (w/ extra padding when border resize is enabled) + // - Begin() initial clipping rect for drawing window background and borders. + // - Begin() clipping whole child + const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect; + const ImRect outer_rect = window->Rect(); + const ImRect title_bar_rect = window->TitleBarRect(); + window->OuterRectClipped = outer_rect; + window->OuterRectClipped.ClipWith(host_rect); + + // Inner rectangle + // Not affected by window border size. Used by: + // - InnerClipRect + // - ScrollToRectEx() + // - NavUpdatePageUpPageDown() + // - Scrollbar() + window->InnerRect.Min.x = window->Pos.x + window->DecoOuterSizeX1; + window->InnerRect.Min.y = window->Pos.y + window->DecoOuterSizeY1; + window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->DecoOuterSizeX2; + window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->DecoOuterSizeY2; + + // Inner clipping rectangle. + // Will extend a little bit outside the normal work region. + // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space. + // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. + // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior. + // Affected by window/frame border size. Used by: + // - Begin() initial clip rect + float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize)); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); + window->InnerClipRect.ClipWithFull(host_rect); + + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f); + else + window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f); + + // SCROLLING + + // Lock down maximum scrolling + // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate + // for right/bottom aligned items without creating a scrollbar. + window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth()); + window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight()); + + // Apply scrolling + window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window); + window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); + window->DecoInnerSizeX1 = window->DecoInnerSizeY1 = 0.0f; + + // DRAWING + + // Setup draw list and outer clipping rectangle + IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); + window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); + PushClipRect(host_rect.Min, host_rect.Max, false); + + // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71) + // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. + // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493) + { + bool render_decorations_in_parent = false; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) + { + // - We test overlap with the previous child window only (testing all would end up being O(log N) not a good investment here) + // - We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping childs + ImGuiWindow* previous_child = parent_window->DC.ChildWindows.Size >= 2 ? parent_window->DC.ChildWindows[parent_window->DC.ChildWindows.Size - 2] : NULL; + bool previous_child_overlapping = previous_child ? previous_child->Rect().Overlaps(window->Rect()) : false; + bool parent_is_empty = (parent_window->DrawList->VtxBuffer.Size == 0); + if (window->DrawList->CmdBuffer.back().ElemCount == 0 && !parent_is_empty && !previous_child_overlapping) + render_decorations_in_parent = true; + } + if (render_decorations_in_parent) + window->DrawList = parent_window->DrawList; + + // Handle title bar, scrollbar, resize grips and resize borders + const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; + const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); + const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch. + RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size); + + if (render_decorations_in_parent) + window->DrawList = &window->DrawListInst; + } + + // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) + + // Work rectangle. + // Affected by window padding and border size. Used by: + // - Columns() for right-most edge + // - TreeNode(), CollapsingHeader() for right-most edge + // - BeginTabBar() for right-most edge + const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar); + const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar); + const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); + const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); + window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize)); + window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize)); + window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x; + window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y; + window->ParentWorkRect = window->WorkRect; + + // [LEGACY] Content Region + // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it. + // Unless explicit content size is specified by user, this currently represent the region leading to no scrolling. + // Used by: + // - Mouse wheel scrolling + many other things + window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x + window->DecoOuterSizeX1; + window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->DecoOuterSizeY1; + window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - (window->DecoOuterSizeX1 + window->DecoOuterSizeX2))); + window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2))); + + // Setup drawing context + // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.) + window->DC.Indent.x = window->DecoOuterSizeX1 + window->WindowPadding.x - window->Scroll.x; + window->DC.GroupOffset.x = 0.0f; + window->DC.ColumnsOffset.x = 0.0f; + + // Record the loss of precision of CursorStartPos which can happen due to really large scrolling amount. + // This is used by clipper to compensate and fix the most common use case of large scroll area. Easy and cheap, next best thing compared to switching everything to double or ImU64. + double start_pos_highp_x = (double)window->Pos.x + window->WindowPadding.x - (double)window->Scroll.x + window->DecoOuterSizeX1 + window->DC.ColumnsOffset.x; + double start_pos_highp_y = (double)window->Pos.y + window->WindowPadding.y - (double)window->Scroll.y + window->DecoOuterSizeY1; + window->DC.CursorStartPos = ImVec2((float)start_pos_highp_x, (float)start_pos_highp_y); + window->DC.CursorStartPosLossyness = ImVec2((float)(start_pos_highp_x - window->DC.CursorStartPos.x), (float)(start_pos_highp_y - window->DC.CursorStartPos.y)); + window->DC.CursorPos = window->DC.CursorStartPos; + window->DC.CursorPosPrevLine = window->DC.CursorPos; + window->DC.CursorMaxPos = window->DC.CursorStartPos; + window->DC.IdealMaxPos = window->DC.CursorStartPos; + window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.IsSameLine = window->DC.IsSetPos = false; + + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext; + window->DC.NavLayersActiveMaskNext = 0x00; + window->DC.NavIsScrollPushableX = true; + window->DC.NavHideHighlightOneFrame = false; + window->DC.NavWindowHasScrollY = (window->ScrollMax.y > 0.0f); + + window->DC.MenuBarAppending = false; + window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user); + window->DC.TreeDepth = 0; + window->DC.TreeJumpToParentOnPopMask = 0x00; + window->DC.ChildWindows.resize(0); + window->DC.StateStorage = &window->StateStorage; + window->DC.CurrentColumns = NULL; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; + + window->DC.ItemWidth = window->ItemWidthDefault; + window->DC.TextWrapPos = -1.0f; // disabled + window->DC.ItemWidthStack.resize(0); + window->DC.TextWrapPosStack.resize(0); + + if (window->AutoFitFramesX > 0) + window->AutoFitFramesX--; + if (window->AutoFitFramesY > 0) + window->AutoFitFramesY--; + + // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there) + // We ImGuiFocusRequestFlags_UnlessBelowModal to: + // - Avoid focusing a window that is created outside of a modal. This will prevent active modal from being closed. + // - Position window behind the modal that is not a begin-parent of this window. + if (want_focus) + FocusWindow(window, ImGuiFocusRequestFlags_UnlessBelowModal); + if (want_focus && window == g.NavWindow) + NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls + + // Title bar + if (!(flags & ImGuiWindowFlags_NoTitleBar)) + RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open); + + // Clear hit test shape every frame + window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; + + // Pressing CTRL+C while holding on a window copy its content to the clipboard + // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. + // Maybe we can support CTRL+C on every element? + /* + //if (g.NavWindow == window && g.ActiveId == 0) + if (g.ActiveId == window->MoveId) + if (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_C)) + LogToClipboard(); + */ + + // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). + // This is useful to allow creating context menus on title bar only, etc. + SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); + + // [DEBUG] +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (g.DebugLocateId != 0 && (window->ID == g.DebugLocateId || window->MoveId == g.DebugLocateId)) + DebugLocateItemResolveWithLastItem(); +#endif + + // [Test Engine] Register title bar / tab with MoveId. +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.ID, g.LastItemData.Rect, &g.LastItemData); +#endif + } + else + { + // Append + SetCurrentWindow(window); + } + + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); + + // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) + window->WriteAccessed = false; + window->BeginCount++; + g.NextWindowData.ClearFlags(); + + // Update visibility + if (first_begin_of_the_frame) + { + if (flags & ImGuiWindowFlags_ChildWindow) + { + // Child window can be out of sight and have "negative" clip windows. + // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). + IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); + if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow?? + { + const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); + if (!g.LogEnabled && !nav_request) + if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) + window->HiddenFramesCanSkipItems = 1; + } + + // Hide along with parent or if parent is collapsed + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) + window->HiddenFramesCanSkipItems = 1; + if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + window->HiddenFramesCannotSkipItems = 1; + } + + // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point) + if (style.Alpha <= 0.0f) + window->HiddenFramesCanSkipItems = 1; + + // Update the Hidden flag + bool hidden_regular = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + window->Hidden = hidden_regular || (window->HiddenFramesForRenderOnly > 0); + + // Disable inputs for requested number of frames + if (window->DisableInputsFrames > 0) + { + window->DisableInputsFrames--; + window->Flags |= ImGuiWindowFlags_NoInputs; + } + + // Update the SkipItems flag, used to early out of all items functions (no layout required) + bool skip_items = false; + if (window->Collapsed || !window->Active || hidden_regular) + if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0) + skip_items = true; + window->SkipItems = skip_items; + } + + // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors. + // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing) + if (!window->IsFallbackWindow && ((g.IO.ConfigDebugBeginReturnValueOnce && window_just_created) || (g.IO.ConfigDebugBeginReturnValueLoop && g.DebugBeginReturnValueCullDepth == g.CurrentWindowStack.Size))) + { + if (window->AutoFitFramesX > 0) { window->AutoFitFramesX++; } + if (window->AutoFitFramesY > 0) { window->AutoFitFramesY++; } + return false; + } + + return !window->SkipItems; +} + +void ImGui::End() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Error checking: verify that user hasn't called End() too many times! + if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); + return; + } + IM_ASSERT(g.CurrentWindowStack.Size > 0); + + // Error checking: verify that user doesn't directly call End() on a child window. + if (window->Flags & ImGuiWindowFlags_ChildWindow) + IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + + // Close anything that is open + if (window->DC.CurrentColumns) + EndColumns(); + PopClipRect(); // Inner window clip rectangle + PopFocusScope(); + + // Stop logging + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging + LogFinish(); + + if (window->DC.IsSetPos) + ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + + // Pop from window stack + g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + g.BeginMenuCount--; + if (window->Flags & ImGuiWindowFlags_Popup) + g.BeginPopupStack.pop_back(); + g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g); + g.CurrentWindowStack.pop_back(); + SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); +} + +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == window->RootWindow); + + const int cur_order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); + if (g.WindowsFocusOrder.back() == window) + return; + + const int new_order = g.WindowsFocusOrder.Size - 1; + for (int n = cur_order; n < new_order; n++) + { + g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; + g.WindowsFocusOrder[n]->FocusOrder--; + IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); + } + g.WindowsFocusOrder[new_order] = window; + window->FocusOrder = (short)new_order; +} + +void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* current_front_window = g.Windows.back(); + if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window + if (g.Windows[i] == window) + { + memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); + g.Windows[g.Windows.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.Windows[0] == window) + return; + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i] == window) + { + memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); + g.Windows[0] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) +{ + IM_ASSERT(window != NULL && behind_window != NULL); + ImGuiContext& g = *GImGui; + window = window->RootWindow; + behind_window = behind_window->RootWindow; + int pos_wnd = FindWindowDisplayIndex(window); + int pos_beh = FindWindowDisplayIndex(behind_window); + if (pos_wnd < pos_beh) + { + size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); + g.Windows[pos_beh - 1] = window; + } + else + { + size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); + g.Windows[pos_beh] = window; + } +} + +int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + return g.Windows.index_from_ptr(g.Windows.find(window)); +} + +// Moving window to front of display and set focus (which happens to be back of our sorted list) +void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) +{ + ImGuiContext& g = *GImGui; + + // Modal check? + if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. + if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); + if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayBehind(window, blocking_modal); // Still bring to right below modal. + return; + } + + // Find last focused child (if any) and focus it instead. + if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) + window = NavRestoreLastChildNavWindow(window); + + // Apply focus + if (g.NavWindow != window) + { + SetNavWindow(window); + if (window && g.NavDisableMouseHover) + g.NavMousePosDirty = true; + g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId + g.NavLayer = ImGuiNavLayer_Main; + g.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0; + g.NavIdIsAlive = false; + + // Close popups if any + ClosePopupsOverWindow(window, false); + } + + // Move the root window to the top of the pile + IM_ASSERT(window == NULL || window->RootWindow != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop + ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; + + // Steal active widgets. Some of the cases it triggers includes: + // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. + // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) + if (!g.ActiveIdNoClearOnFocusLoss) + ClearActiveID(); + + // Passing NULL allow to disable keyboard focus + if (!window) + return; + + // Bring to front + BringWindowToFocusFront(focus_front_window); + if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayFront(display_front_window); +} + +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(filter_viewport); // Unused in master branch. + int start_idx = g.WindowsFocusOrder.Size - 1; + if (under_this_window != NULL) + { + // Aim at root window behind us, if we are in a child window that's our own root (see #4640) + int offset = -1; + while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) + { + under_this_window = under_this_window->ParentWindow; + offset = 0; + } + start_idx = FindWindowFocusIndex(under_this_window) + offset; + } + for (int i = start_idx; i >= 0; i--) + { + // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. + ImGuiWindow* window = g.WindowsFocusOrder[i]; + IM_ASSERT(window == window->RootWindow); + if (window == ignore_window || !window->WasActive) + continue; + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + FocusWindow(window, flags); + return; + } + } + FocusWindow(NULL, flags); +} + +// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. +void ImGui::SetCurrentFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.Font = font; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.TexUvLines = atlas->TexUvLines; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; +} + +void ImGui::PushFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + if (!font) + font = GetDefaultFont(); + SetCurrentFont(font); + g.FontStack.push_back(font); + g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); +} + +void ImGui::PopFont() +{ + ImGuiContext& g = *GImGui; + g.CurrentWindow->DrawList->PopTextureID(); + g.FontStack.pop_back(); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); +} + +void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiItemFlags item_flags = g.CurrentItemFlags; + IM_ASSERT(item_flags == g.ItemFlagsStack.back()); + if (enabled) + item_flags |= option; + else + item_flags &= ~option; + g.CurrentItemFlags = item_flags; + g.ItemFlagsStack.push_back(item_flags); +} + +void ImGui::PopItemFlag() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack. + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); +} + +// BeginDisabled()/EndDisabled() +// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) +// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently. +// - Feedback welcome at https://github.com/ocornut/imgui/issues/211 +// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. +// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag() +void ImGui::BeginDisabled(bool disabled) +{ + ImGuiContext& g = *GImGui; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (!was_disabled && disabled) + { + g.DisabledAlphaBackup = g.Style.Alpha; + g.Style.Alpha *= g.Style.DisabledAlpha; // PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * g.Style.DisabledAlpha); + } + if (was_disabled || disabled) + g.CurrentItemFlags |= ImGuiItemFlags_Disabled; + g.ItemFlagsStack.push_back(g.CurrentItemFlags); + g.DisabledStackSize++; +} + +void ImGui::EndDisabled() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DisabledStackSize > 0); + g.DisabledStackSize--; + bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + //PopItemFlag(); + g.ItemFlagsStack.pop_back(); + g.CurrentItemFlags = g.ItemFlagsStack.back(); + if (was_disabled && (g.CurrentItemFlags & ImGuiItemFlags_Disabled) == 0) + g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar(); +} + +void ImGui::PushTabStop(bool tab_stop) +{ + PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); +} + +void ImGui::PopTabStop() +{ + PopItemFlag(); +} + +void ImGui::PushButtonRepeat(bool repeat) +{ + PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); +} + +void ImGui::PopButtonRepeat() +{ + PopItemFlag(); +} + +void ImGui::PushTextWrapPos(float wrap_pos_x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos); + window->DC.TextWrapPos = wrap_pos_x; +} + +void ImGui::PopTextWrapPos() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); + window->DC.TextWrapPosStack.pop_back(); +} + +static ImGuiWindow* GetCombinedRootWindow(ImGuiWindow* window, bool popup_hierarchy) +{ + ImGuiWindow* last_window = NULL; + while (last_window != window) + { + last_window = window; + window = window->RootWindow; + if (popup_hierarchy) + window = window->RootWindowPopupTree; + } + return window; +} + +bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy) +{ + ImGuiWindow* window_root = GetCombinedRootWindow(window, popup_hierarchy); + if (window_root == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + if (window == window_root) // end of chain + return false; + window = window->ParentWindow; + } + return false; +} + +bool ImGui::IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent) +{ + if (window->RootWindow == potential_parent) + return true; + while (window != NULL) + { + if (window == potential_parent) + return true; + window = window->ParentWindowInBeginStack; + } + return false; +} + +bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below) +{ + ImGuiContext& g = *GImGui; + + // It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array + const int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below); + if (display_layer_delta != 0) + return display_layer_delta > 0; + + for (int i = g.Windows.Size - 1; i >= 0; i--) + { + ImGuiWindow* candidate_window = g.Windows[i]; + if (candidate_window == potential_above) + return true; + if (candidate_window == potential_below) + return false; + } + return false; +} + +bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) +{ + IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsWindowHovered) == 0 && "Invalid flags for IsWindowHovered()!"); + + ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.HoveredWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + if (ref_window == NULL) + return false; + + if ((flags & ImGuiHoveredFlags_AnyWindow) == 0) + { + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiHoveredFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + bool result; + if (flags & ImGuiHoveredFlags_ChildWindows) + result = IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + result = (ref_window == cur_window); + if (!result) + return false; + } + + if (!IsWindowContentHoverable(ref_window, flags)) + return false; + if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != ref_window->MoveId) + return false; + + // When changing hovered window we requires a bit of stationary delay before activating hover timer. + // FIXME: We don't support delay other than stationary one for now, other delay would need a way + // to fullfill the possibility that multiple IsWindowHovered() with varying flag could return true + // for different windows of the hierarchy. Possibly need a Hash(Current+Flags) ==> (Timer) cache. + // We can implement this for _Stationary because the data is linked to HoveredWindow rather than CurrentWindow. + if (flags & ImGuiHoveredFlags_ForTooltip) + flags |= g.Style.HoverFlagsForTooltipMouse; + if ((flags & ImGuiHoveredFlags_Stationary) != 0 && g.HoverWindowUnlockedStationaryId != ref_window->ID) + return false; + + return true; +} + +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.NavWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + + if (ref_window == NULL) + return false; + if (flags & ImGuiFocusedFlags_AnyWindow) + return true; + + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + if (flags & ImGuiHoveredFlags_ChildWindows) + return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + return (ref_window == cur_window); +} + +// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. +// If you want a window to never be focused, you may use the e.g. NoInputs flag. +bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +{ + return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); +} + +float ImGui::GetWindowWidth() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.x; +} + +float ImGui::GetWindowHeight() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Size.y; +} + +ImVec2 ImGui::GetWindowPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + return window->Pos; +} + +void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowPosAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX); + + // Set + const ImVec2 old_pos = window->Pos; + window->Pos = ImFloor(pos); + ImVec2 offset = window->Pos - old_pos; + if (offset.x == 0.0f && offset.y == 0.0f) + return; + MarkIniSettingsDirty(window); + window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. + window->DC.IdealMaxPos += offset; + window->DC.CursorStartPos += offset; +} + +void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + SetWindowPos(window, pos, cond); +} + +void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowPos(window, pos, cond); +} + +ImVec2 ImGui::GetWindowSize() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Size; +} + +void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowSizeAllowFlags & cond) == 0) + return; + + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + ImVec2 old_size = window->SizeFull; + window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0; + window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0; + if (size.x <= 0.0f) + window->AutoFitOnlyGrows = false; + else + window->SizeFull.x = IM_FLOOR(size.x); + if (size.y <= 0.0f) + window->AutoFitOnlyGrows = false; + else + window->SizeFull.y = IM_FLOOR(size.y); + if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y) + MarkIniSettingsDirty(window); +} + +void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond) +{ + SetWindowSize(GImGui->CurrentWindow, size, cond); +} + +void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowSize(window, size, cond); +} + +void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond) +{ + // Test condition (NB: bit 0 is always true) and clear flags for next time + if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0) + return; + window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); + + // Set + window->Collapsed = collapsed; +} + +void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) +{ + IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters + window->HitTestHoleSize = ImVec2ih(size); + window->HitTestHoleOffset = ImVec2ih(pos - window->Pos); +} + +void ImGui::SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window) +{ + window->Hidden = window->SkipItems = true; + window->HiddenFramesCanSkipItems = 1; +} + +void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); +} + +bool ImGui::IsWindowCollapsed() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Collapsed; +} + +bool ImGui::IsWindowAppearing() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->Appearing; +} + +void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) +{ + if (ImGuiWindow* window = FindWindowByName(name)) + SetWindowCollapsed(window, collapsed, cond); +} + +void ImGui::SetWindowFocus() +{ + FocusWindow(GImGui->CurrentWindow); +} + +void ImGui::SetWindowFocus(const char* name) +{ + if (name) + { + if (ImGuiWindow* window = FindWindowByName(name)) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } +} + +void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos; + g.NextWindowData.PosVal = pos; + g.NextWindowData.PosPivotVal = pivot; + g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize; + g.NextWindowData.SizeVal = size; + g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; + g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); + g.NextWindowData.SizeCallback = custom_callback; + g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; +} + +// Content size = inner scrollable rectangle, padded with WindowPadding. +// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item. +void ImGui::SetNextWindowContentSize(const ImVec2& size) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; + g.NextWindowData.ContentSizeVal = ImFloor(size); +} + +void ImGui::SetNextWindowScroll(const ImVec2& scroll) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll; + g.NextWindowData.ScrollVal = scroll; +} + +void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed; + g.NextWindowData.CollapsedVal = collapsed; + g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; +} + +void ImGui::SetNextWindowFocus() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; +} + +void ImGui::SetNextWindowBgAlpha(float alpha) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha; + g.NextWindowData.BgAlphaVal = alpha; +} + +ImDrawList* ImGui::GetWindowDrawList() +{ + ImGuiWindow* window = GetCurrentWindow(); + return window->DrawList; +} + +ImFont* ImGui::GetFont() +{ + return GImGui->Font; +} + +float ImGui::GetFontSize() +{ + return GImGui->FontSize; +} + +ImVec2 ImGui::GetFontTexUvWhitePixel() +{ + return GImGui->DrawListSharedData.TexUvWhitePixel; +} + +void ImGui::SetWindowFontScale(float scale) +{ + IM_ASSERT(scale > 0.0f); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->FontWindowScale = scale; + g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); +} + +void ImGui::PushFocusScope(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.FocusScopeStack.push_back(id); + g.CurrentFocusScopeId = id; +} + +void ImGui::PopFocusScope() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ? + g.FocusScopeStack.pop_back(); + g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back() : 0; +} + +// Focus = move navigation cursor, set scrolling, set focus window. +void ImGui::FocusItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IMGUI_DEBUG_LOG_FOCUS("FocusItem(0x%08x) in window \"%s\"\n", g.LastItemData.ID, window->Name); + if (g.DragDropActive || g.MovingWindow != NULL) // FIXME: Opt-in flags for this? + { + IMGUI_DEBUG_LOG_FOCUS("FocusItem() ignored while DragDropActive!\n"); + return; + } + + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSelect; + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + SetNavWindow(window); + NavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_Up, move_flags, scroll_flags); + NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal); +} + +void ImGui::ActivateItemByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + g.NavNextActivateId = id; + g.NavNextActivateFlags = ImGuiActivateFlags_None; +} + +// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system! +// But ActivateItem() should function without altering scroll/focus? +void ImGui::SetKeyboardFocusHere(int offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(offset >= -1); // -1 is allowed but not below + IMGUI_DEBUG_LOG_FOCUS("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name); + + // It makes sense in the vast majority of cases to never interrupt a drag and drop. + // When we refactor this function into ActivateItem() we may want to make this an option. + // MovingWindow is protected from most user inputs using SetActiveIdUsingNavAndKeys(), but + // is also automatically dropped in the event g.ActiveId is stolen. + if (g.DragDropActive || g.MovingWindow != NULL) + { + IMGUI_DEBUG_LOG_FOCUS("SetKeyboardFocusHere() ignored while DragDropActive!\n"); + return; + } + + SetNavWindow(window); + + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi; + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + if (offset == -1) + { + NavMoveRequestResolveWithLastItem(&g.NavMoveResultLocal); + } + else + { + g.NavTabbingDir = 1; + g.NavTabbingCounter = offset + 1; + } +} + +void ImGui::SetItemDefaultFocus() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!window->Appearing) + return; + if (g.NavWindow != window->RootWindowForNav || (!g.NavInitRequest && g.NavInitResult.ID == 0) || g.NavLayer != window->DC.NavLayerCurrent) + return; + + g.NavInitRequest = false; + NavApplyItemToResult(&g.NavInitResult); + NavUpdateAnyRequestFlag(); + + // Scroll could be done in NavInitRequestApplyResult() via an opt-in flag (we however don't want regular init requests to scroll) + if (!window->ClipRect.Contains(g.LastItemData.Rect)) + ScrollToRectEx(window, g.LastItemData.Rect, ImGuiScrollFlags_None); +} + +void ImGui::SetStateStorage(ImGuiStorage* tree) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + window->DC.StateStorage = tree ? tree : &window->StateStorage; +} + +ImGuiStorage* ImGui::GetStateStorage() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->DC.StateStorage; +} + +void ImGui::PushID(const char* str_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(str_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(str_id_begin, str_id_end); + window->IDStack.push_back(id); +} + +void ImGui::PushID(const void* ptr_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(ptr_id); + window->IDStack.push_back(id); +} + +void ImGui::PushID(int int_id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID(int_id); + window->IDStack.push_back(id); +} + +// Push a given id value ignoring the ID stack as a seed. +void ImGui::PushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL); + window->IDStack.push_back(id); +} + +// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call +// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level. +// for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more) +ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) +{ + ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_String, str, str_end); + return id; +} + +ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed) +{ + ImGuiID id = ImHashData(&n, sizeof(n), seed); + ImGuiContext& g = *GImGui; + if (g.DebugHookIdInfo == id) + DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL); + return id; +} + +void ImGui::PopID() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window? + window->IDStack.pop_back(); +} + +ImGuiID ImGui::GetID(const char* str_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id); +} + +ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(str_id_begin, str_id_end); +} + +ImGuiID ImGui::GetID(const void* ptr_id) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(ptr_id); +} + +bool ImGui::IsRectVisible(const ImVec2& size) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size)); +} + +bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); +} + + +//----------------------------------------------------------------------------- +// [SECTION] INPUTS +//----------------------------------------------------------------------------- +// - GetKeyData() [Internal] +// - GetKeyIndex() [Internal] +// - GetKeyName() +// - GetKeyChordName() [Internal] +// - CalcTypematicRepeatAmount() [Internal] +// - GetTypematicRepeatRate() [Internal] +// - GetKeyPressedAmount() [Internal] +// - GetKeyMagnitude2d() [Internal] +//----------------------------------------------------------------------------- +// - UpdateKeyRoutingTable() [Internal] +// - GetRoutingIdFromOwnerId() [Internal] +// - GetShortcutRoutingData() [Internal] +// - CalcRoutingScore() [Internal] +// - SetShortcutRouting() [Internal] +// - TestShortcutRouting() [Internal] +//----------------------------------------------------------------------------- +// - IsKeyDown() +// - IsKeyPressed() +// - IsKeyReleased() +//----------------------------------------------------------------------------- +// - IsMouseDown() +// - IsMouseClicked() +// - IsMouseReleased() +// - IsMouseDoubleClicked() +// - GetMouseClickedCount() +// - IsMouseHoveringRect() [Internal] +// - IsMouseDragPastThreshold() [Internal] +// - IsMouseDragging() +// - GetMousePos() +// - GetMousePosOnOpeningCurrentPopup() +// - IsMousePosValid() +// - IsAnyMouseDown() +// - GetMouseDragDelta() +// - ResetMouseDragDelta() +// - GetMouseCursor() +// - SetMouseCursor() +//----------------------------------------------------------------------------- +// - UpdateAliasKey() +// - GetMergedModsFromKeys() +// - UpdateKeyboardInputs() +// - UpdateMouseInputs() +//----------------------------------------------------------------------------- +// - LockWheelingWindow [Internal] +// - FindBestWheelingWindow [Internal] +// - UpdateMouseWheel() [Internal] +//----------------------------------------------------------------------------- +// - SetNextFrameWantCaptureKeyboard() +// - SetNextFrameWantCaptureMouse() +//----------------------------------------------------------------------------- +// - GetInputSourceName() [Internal] +// - DebugPrintInputEvent() [Internal] +// - UpdateInputEvents() [Internal] +//----------------------------------------------------------------------------- +// - GetKeyOwner() [Internal] +// - TestKeyOwner() [Internal] +// - SetKeyOwner() [Internal] +// - SetItemKeyOwner() [Internal] +// - Shortcut() [Internal] +//----------------------------------------------------------------------------- + +ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) +{ + ImGuiContext& g = *ctx; + + // Special storage location for mods + if (key & ImGuiMod_Mask_) + key = ConvertSingleModFlagToKey(ctx, key); + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); + if (IsLegacyKey(key) && g.IO.KeyMap[key] != -1) + key = (ImGuiKey)g.IO.KeyMap[key]; // Remap native->imgui or imgui->native +#else + IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); +#endif + return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET]; +} + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +ImGuiKey ImGui::GetKeyIndex(ImGuiKey key) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(IsNamedKey(key)); + const ImGuiKeyData* key_data = GetKeyData(key); + return (ImGuiKey)(key_data - g.IO.KeysData); +} +#endif + +// Those names a provided for debugging purpose and are not meant to be saved persistently not compared. +static const char* const GKeyNames[] = +{ + "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown", + "Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape", + "LeftCtrl", "LeftShift", "LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", + "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", + "Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "LeftBracket", + "Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen", + "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", + "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", + "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", + "GamepadStart", "GamepadBack", + "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown", + "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown", + "GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3", + "GamepadLStickLeft", "GamepadLStickRight", "GamepadLStickUp", "GamepadLStickDown", + "GamepadRStickLeft", "GamepadRStickRight", "GamepadRStickUp", "GamepadRStickDown", + "MouseLeft", "MouseRight", "MouseMiddle", "MouseX1", "MouseX2", "MouseWheelX", "MouseWheelY", + "ModCtrl", "ModShift", "ModAlt", "ModSuper", // ReservedForModXXX are showing the ModXXX names. +}; +IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames)); + +const char* ImGui::GetKeyName(ImGuiKey key) +{ + ImGuiContext& g = *GImGui; +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT((IsNamedKeyOrModKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); +#else + if (IsLegacyKey(key)) + { + if (g.IO.KeyMap[key] == -1) + return "N/A"; + IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key])); + key = (ImGuiKey)g.IO.KeyMap[key]; + } +#endif + if (key == ImGuiKey_None) + return "None"; + if (key & ImGuiMod_Mask_) + key = ConvertSingleModFlagToKey(&g, key); + if (!IsNamedKey(key)) + return "Unknown"; + + return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; +} + +// ImGuiMod_Shortcut is translated to either Ctrl or Super. +void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size) +{ + ImGuiContext& g = *GImGui; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); + ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s", + (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", + (key_chord & ImGuiMod_Shift) ? "Shift+" : "", + (key_chord & ImGuiMod_Alt) ? "Alt+" : "", + (key_chord & ImGuiMod_Super) ? (g.IO.ConfigMacOSXBehaviors ? "Cmd+" : "Super+") : "", + GetKeyName((ImGuiKey)(key_chord & ~ImGuiMod_Mask_))); +} + +// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime) +// t1 = current time (e.g.: g.Time) +// An event is triggered at: +// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N +int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate) +{ + if (t1 == 0.0f) + return 1; + if (t0 >= t1) + return 0; + if (repeat_rate <= 0.0f) + return (t0 < repeat_delay) && (t1 >= repeat_delay); + const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); + const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); + const int count = count_t1 - count_t0; + return count; +} + +void ImGui::GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate) +{ + ImGuiContext& g = *GImGui; + switch (flags & ImGuiInputFlags_RepeatRateMask_) + { + case ImGuiInputFlags_RepeatRateNavMove: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.80f; return; + case ImGuiInputFlags_RepeatRateNavTweak: *repeat_delay = g.IO.KeyRepeatDelay * 0.72f; *repeat_rate = g.IO.KeyRepeatRate * 0.30f; return; + case ImGuiInputFlags_RepeatRateDefault: default: *repeat_delay = g.IO.KeyRepeatDelay * 1.00f; *repeat_rate = g.IO.KeyRepeatRate * 1.00f; return; + } +} + +// Return value representing the number of presses in the last time period, for the given repeat rate +// (most often returns 0 or 1. The result is generally only >1 when RepeatRate is smaller than DeltaTime, aka large DeltaTime or fast RepeatRate) +int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_rate) +{ + ImGuiContext& g = *GImGui; + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return 0; + const float t = key_data->DownDuration; + return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); +} + +// Return 2D vector representing the combination of four cardinal direction, with analog value support (for e.g. ImGuiKey_GamepadLStick* values). +ImVec2 ImGui::GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down) +{ + return ImVec2( + GetKeyData(key_right)->AnalogValue - GetKeyData(key_left)->AnalogValue, + GetKeyData(key_down)->AnalogValue - GetKeyData(key_up)->AnalogValue); +} + +// Rewrite routing data buffers to strip old entries + sort by key to make queries not touch scattered data. +// Entries D,A,B,B,A,C,B --> A,A,B,B,B,C,D +// Index A:1 B:2 C:5 D:0 --> A:0 B:2 C:5 D:6 +// See 'Metrics->Key Owners & Shortcut Routing' to visualize the result of that operation. +static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt) +{ + ImGuiContext& g = *GImGui; + rt->EntriesNext.resize(0); + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + const int new_routing_start_idx = rt->EntriesNext.Size; + ImGuiKeyRoutingData* routing_entry; + for (int old_routing_idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; old_routing_idx != -1; old_routing_idx = routing_entry->NextEntryIndex) + { + routing_entry = &rt->Entries[old_routing_idx]; + routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry + routing_entry->RoutingNext = ImGuiKeyOwner_None; + routing_entry->RoutingNextScore = 255; + if (routing_entry->RoutingCurr == ImGuiKeyOwner_None) + continue; + rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer + + // Apply routing to owner if there's no owner already (RoutingCurr == None at this point) + if (routing_entry->Mods == g.IO.KeyMods) + { + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + owner_data->OwnerCurr = routing_entry->RoutingCurr; + } + } + + // Rewrite linked-list + rt->Index[key - ImGuiKey_NamedKey_BEGIN] = (ImGuiKeyRoutingIndex)(new_routing_start_idx < rt->EntriesNext.Size ? new_routing_start_idx : -1); + for (int n = new_routing_start_idx; n < rt->EntriesNext.Size; n++) + rt->EntriesNext[n].NextEntryIndex = (ImGuiKeyRoutingIndex)((n + 1 < rt->EntriesNext.Size) ? n + 1 : -1); + } + rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes +} + +// owner_id may be None/Any, but routing_id needs to be always be set, so we default to GetCurrentFocusScope(). +static inline ImGuiID GetRoutingIdFromOwnerId(ImGuiID owner_id) +{ + ImGuiContext& g = *GImGui; + return (owner_id != ImGuiKeyOwner_None && owner_id != ImGuiKeyOwner_Any) ? owner_id : g.CurrentFocusScopeId; +} + +ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord) +{ + // Majority of shortcuts will be Key + any number of Mods + // We accept _Single_ mod with ImGuiKey_None. + // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl); // Legal + // - Shortcut(ImGuiKey_S | ImGuiMod_Ctrl | ImGuiMod_Shift); // Legal + // - Shortcut(ImGuiMod_Ctrl); // Legal + // - Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift); // Not legal + ImGuiContext& g = *GImGui; + ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; + ImGuiKeyRoutingData* routing_data; + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); + if (key == ImGuiKey_None) + key = ConvertSingleModFlagToKey(&g, mods); + IM_ASSERT(IsNamedKey(key)); + + // Get (in the majority of case, the linked list will have one element so this should be 2 reads. + // Subsequent elements will be contiguous in memory as list is sorted/rebuilt in NewFrame). + for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; idx = routing_data->NextEntryIndex) + { + routing_data = &rt->Entries[idx]; + if (routing_data->Mods == mods) + return routing_data; + } + + // Add to linked-list + ImGuiKeyRoutingIndex routing_data_idx = (ImGuiKeyRoutingIndex)rt->Entries.Size; + rt->Entries.push_back(ImGuiKeyRoutingData()); + routing_data = &rt->Entries[routing_data_idx]; + routing_data->Mods = (ImU16)mods; + routing_data->NextEntryIndex = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; // Setup linked list + rt->Index[key - ImGuiKey_NamedKey_BEGIN] = routing_data_idx; + return routing_data; +} + +// Current score encoding (lower is highest priority): +// - 0: ImGuiInputFlags_RouteGlobalHigh +// - 1: ImGuiInputFlags_RouteFocused (if item active) +// - 2: ImGuiInputFlags_RouteGlobal +// - 3+: ImGuiInputFlags_RouteFocused (if window in focus-stack) +// - 254: ImGuiInputFlags_RouteGlobalLow +// - 255: never route +// 'flags' should include an explicit routing policy +static int CalcRoutingScore(ImGuiWindow* location, ImGuiID owner_id, ImGuiInputFlags flags) +{ + if (flags & ImGuiInputFlags_RouteFocused) + { + ImGuiContext& g = *GImGui; + ImGuiWindow* focused = g.NavWindow; + + // ActiveID gets top priority + // (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it) + if (owner_id != 0 && g.ActiveId == owner_id) + return 1; + + // Score based on distance to focused window (lower is better) + // Assuming both windows are submitting a routing request, + // - When Window....... is focused -> Window scores 3 (best), Window/ChildB scores 255 (no match) + // - When Window/ChildB is focused -> Window scores 4, Window/ChildB scores 3 (best) + // Assuming only WindowA is submitting a routing request, + // - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score. + if (focused != NULL && focused->RootWindow == location->RootWindow) + for (int next_score = 3; focused != NULL; next_score++) + { + if (focused == location) + { + IM_ASSERT(next_score < 255); + return next_score; + } + focused = (focused->RootWindow != focused) ? focused->ParentWindow : NULL; // FIXME: This could be later abstracted as a focus path + } + return 255; + } + + // ImGuiInputFlags_RouteGlobalHigh is default, so calls without flags are not conditional + if (flags & ImGuiInputFlags_RouteGlobal) + return 2; + if (flags & ImGuiInputFlags_RouteGlobalLow) + return 254; + return 0; +} + +// Request a desired route for an input chord (key + mods). +// Return true if the route is available this frame. +// - Routes and key ownership are attributed at the beginning of next frame based on best score and mod state. +// (Conceptually this does a "Submit for next frame" + "Test for current frame". +// As such, it could be called TrySetXXX or SubmitXXX, or the Submit and Test operations should be separate.) +// - Using 'owner_id == ImGuiKeyOwner_Any/0': auto-assign an owner based on current focus scope (each window has its focus scope by default) +// - Using 'owner_id == ImGuiKeyOwner_None': allows disabling/locking a shortcut. +bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) +{ + ImGuiContext& g = *GImGui; + if ((flags & ImGuiInputFlags_RouteMask_) == 0) + flags |= ImGuiInputFlags_RouteGlobalHigh; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut() + else + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used + + if (flags & ImGuiInputFlags_RouteUnlessBgFocused) + if (g.NavWindow == NULL) + return false; + if (flags & ImGuiInputFlags_RouteAlways) + return true; + + const int score = CalcRoutingScore(g.CurrentWindow, owner_id, flags); + if (score == 255) + return false; + + // Submit routing for NEXT frame (assuming score is sufficient) + // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <). + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); + const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); + //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore); + if (score < routing_data->RoutingNextScore) + { + routing_data->RoutingNext = routing_id; + routing_data->RoutingNextScore = (ImU8)score; + } + + // Return routing state for CURRENT frame + return routing_data->RoutingCurr == routing_id; +} + +// Currently unused by core (but used by tests) +// Note: this cannot be turned into GetShortcutRouting() because we do the owner_id->routing_id translation, name would be more misleading. +bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id) +{ + const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id); + ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry. + return routing_data->RoutingCurr == routing_id; +} + +// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes. +// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87) +bool ImGui::IsKeyDown(ImGuiKey key) +{ + return IsKeyDown(key, ImGuiKeyOwner_Any); +} + +bool ImGui::IsKeyDown(ImGuiKey key, ImGuiID owner_id) +{ + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; +} + +bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat) +{ + return IsKeyPressed(key, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); +} + +// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. +bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) +{ + const ImGuiKeyData* key_data = GetKeyData(key); + if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return false; + const float t = key_data->DownDuration; + if (t < 0.0f) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! + + bool pressed = (t == 0.0f); + if (!pressed && ((flags & ImGuiInputFlags_Repeat) != 0)) + { + float repeat_delay, repeat_rate; + GetTypematicRepeatRate(flags, &repeat_delay, &repeat_rate); + pressed = (t > repeat_delay) && GetKeyPressedAmount(key, repeat_delay, repeat_rate) > 0; + } + if (!pressed) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; +} + +bool ImGui::IsKeyReleased(ImGuiKey key) +{ + return IsKeyReleased(key, ImGuiKeyOwner_Any); +} + +bool ImGui::IsKeyReleased(ImGuiKey key, ImGuiID owner_id) +{ + const ImGuiKeyData* key_data = GetKeyData(key); + if (key_data->DownDurationPrev < 0.0f || key_data->Down) + return false; + if (!TestKeyOwner(key, owner_id)) + return false; + return true; +} + +bool ImGui::IsMouseDown(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // should be same as IsKeyDown(MouseButtonToKey(button), ImGuiKeyOwner_Any), but this allows legacy code hijacking the io.Mousedown[] array. +} + +bool ImGui::IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseDown[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyDown(MouseButtonToKey(button), owner_id), but this allows legacy code hijacking the io.Mousedown[] array. +} + +bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat) +{ + return IsMouseClicked(button, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None); +} + +bool ImGui::IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitates eating mechanism (until we finish work on key ownership) + return false; + const float t = g.IO.MouseDownDuration[button]; + if (t < 0.0f) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByIsKeyPressed) == 0); // Passing flags not supported by this function! + + const bool repeat = (flags & ImGuiInputFlags_Repeat) != 0; + const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0); + if (!pressed) + return false; + + if (!TestKeyOwner(MouseButtonToKey(button), owner_id)) + return false; + + return true; +} + +bool ImGui::IsMouseReleased(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); // Should be same as IsKeyReleased(MouseButtonToKey(button), ImGuiKeyOwner_Any) +} + +bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id) +} + +bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button] == 2 && TestKeyOwner(MouseButtonToKey(button), ImGuiKeyOwner_Any); +} + +int ImGui::GetMouseClickedCount(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + return g.IO.MouseClickedCount[button]; +} + +// Test if mouse cursor is hovering given rectangle +// NB- Rectangle is clipped by our current clip setting +// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding) +bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip) +{ + ImGuiContext& g = *GImGui; + + // Clip + ImRect rect_clipped(r_min, r_max); + if (clip) + rect_clipped.ClipWith(g.CurrentWindow->ClipRect); + + // Expand for touch input + const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding); + if (!rect_for_touch.Contains(g.IO.MousePos)) + return false; + return true; +} + +// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. +// [Internal] This doesn't test if the button is pressed +bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold; +} + +bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (!g.IO.MouseDown[button]) + return false; + return IsMouseDragPastThreshold(button, lock_threshold); +} + +ImVec2 ImGui::GetMousePos() +{ + ImGuiContext& g = *GImGui; + return g.IO.MousePos; +} + +// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiContext& g = *GImGui; + if (g.BeginPopupStack.Size > 0) + return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.IO.MousePos; +} + +// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position. +bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) +{ + // The assert is only to silence a false-positive in XCode Static Analysis. + // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions). + IM_ASSERT(GImGui != NULL); + const float MOUSE_INVALID = -256000.0f; + ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos; + return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; +} + +// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. +bool ImGui::IsAnyMouseDown() +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++) + if (g.IO.MouseDown[n]) + return true; + return false; +} + +// Return the delta from the initial clicking position while the mouse button is clicked or was just released. +// This is locked and return 0.0f until the mouse moves past a distance threshold at least once. +// NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window. +ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + if (lock_threshold < 0.0f) + lock_threshold = g.IO.MouseDragThreshold; + if (g.IO.MouseDown[button] || g.IO.MouseReleased[button]) + if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold) + if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button])) + return g.IO.MousePos - g.IO.MouseClickedPos[button]; + return ImVec2(0.0f, 0.0f); +} + +void ImGui::ResetMouseDragDelta(ImGuiMouseButton button) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr + g.IO.MouseClickedPos[button] = g.IO.MousePos; +} + +// Get desired mouse cursor shape. +// Important: this is meant to be used by a platform backend, it is reset in ImGui::NewFrame(), +// updated during the frame, and locked in EndFrame()/Render(). +// If you use software rendering by setting io.MouseDrawCursor then Dear ImGui will render those for you +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + ImGuiContext& g = *GImGui; + return g.MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + ImGuiContext& g = *GImGui; + g.MouseCursor = cursor_type; +} + +static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value) +{ + IM_ASSERT(ImGui::IsAliasKey(key)); + ImGuiKeyData* key_data = ImGui::GetKeyData(key); + key_data->Down = v; + key_data->AnalogValue = analog_value; +} + +// [Internal] Do not use directly +static ImGuiKeyChord GetMergedModsFromKeys() +{ + ImGuiKeyChord mods = 0; + if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; } + if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; } + if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; } + if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; } + return mods; +} + +static void ImGui::UpdateKeyboardInputs() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + // Import legacy keys or verify they are not used +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (io.BackendUsingLegacyKeyArrays == 0) + { + // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally. + for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + } + else + { + if (g.FrameCount == 0) + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); + + // Build reverse KeyMap (Named -> Legacy) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + if (io.KeyMap[n] != -1) + { + IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); + io.KeyMap[io.KeyMap[n]] = n; + } + + // Import legacy keys into new ones + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) + { + const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); + IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); + io.KeysData[key].Down = io.KeysDown[n]; + if (key != n) + io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends + io.BackendUsingLegacyKeyArrays = 1; + } + if (io.BackendUsingLegacyKeyArrays == 1) + { + GetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl; + GetKeyData(ImGuiMod_Shift)->Down = io.KeyShift; + GetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt; + GetKeyData(ImGuiMod_Super)->Down = io.KeySuper; + } + } + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active) + { + #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0) + #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0) + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown); + #undef NAV_MAP_KEY + } +#endif +#endif + + // Update aliases + for (int n = 0; n < ImGuiMouseButton_COUNT; n++) + UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); + UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH); + UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel); + + // Synchronize io.KeyMods and io.KeyXXX values. + // - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array. + // - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array. + // So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing. + io.KeyMods = GetMergedModsFromKeys(); + io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0; + io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0; + io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0; + io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0; + + // Clear gamepad data if disabled + if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) + for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) + { + io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false; + io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f; + } + + // Update keys + for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) + { + ImGuiKeyData* key_data = &io.KeysData[i]; + key_data->DownDurationPrev = key_data->DownDuration; + key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f; + } + + // Update keys/input owner (named keys only): one entry per key + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET]; + ImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; + owner_data->OwnerCurr = owner_data->OwnerNext; + if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. + owner_data->OwnerNext = ImGuiKeyOwner_None; + owner_data->LockThisFrame = owner_data->LockUntilRelease = owner_data->LockUntilRelease && key_data->Down; // Clear LockUntilRelease when key is not Down anymore + } + + UpdateKeyRoutingTable(&g.KeysRoutingTable); +} + +static void ImGui::UpdateMouseInputs() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + // Mouse Wheel swapping flag + // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead + // - We avoid doing it on OSX as it the OS input layer handles this already. + // - FIXME: However this means when running on OSX over Emscripten, Shift+WheelY will incur two swapping (1 in OS, 1 here), canceling the feature. + // - FIXME: When we can distinguish e.g. touchpad scroll events from mouse ones, we'll set this accordingly based on input source. + io.MouseWheelRequestAxisSwap = io.KeyShift && !io.ConfigMacOSXBehaviors; + + // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) + if (IsMousePosValid(&io.MousePos)) + io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos); + + // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta + if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev)) + io.MouseDelta = io.MousePos - io.MousePosPrev; + else + io.MouseDelta = ImVec2(0.0f, 0.0f); + + // Update stationary timer. + // FIXME: May need to rework again to have some tolerance for occasional small movement, while being functional on high-framerates. + const float mouse_stationary_threshold = (io.MouseSource == ImGuiMouseSource_Mouse) ? 2.0f : 3.0f; // Slightly higher threshold for ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen, may need rework. + const bool mouse_stationary = (ImLengthSqr(io.MouseDelta) <= mouse_stationary_threshold * mouse_stationary_threshold); + g.MouseStationaryTimer = mouse_stationary ? (g.MouseStationaryTimer + io.DeltaTime) : 0.0f; + //IMGUI_DEBUG_LOG("%.4f\n", g.MouseStationaryTimer); + + // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. + if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) + g.NavDisableMouseHover = false; + + io.MousePosPrev = io.MousePos; + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; + io.MouseClickedCount[i] = 0; // Will be filled below + io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; + io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; + io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; + if (io.MouseClicked[i]) + { + bool is_repeated_click = false; + if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTime) + { + ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (io.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); + if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDist * io.MouseDoubleClickMaxDist) + is_repeated_click = true; + } + if (is_repeated_click) + io.MouseClickedLastCount[i]++; + else + io.MouseClickedLastCount[i] = 1; + io.MouseClickedTime[i] = g.Time; + io.MouseClickedPos[i] = io.MousePos; + io.MouseClickedCount[i] = io.MouseClickedLastCount[i]; + io.MouseDragMaxDistanceSqr[i] = 0.0f; + } + else if (io.MouseDown[i]) + { + // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold + float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLengthSqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f; + io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i], delta_sqr_click_pos); + } + + // We provide io.MouseDoubleClicked[] as a legacy service + io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); + + // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation + if (io.MouseClicked[i]) + g.NavDisableMouseHover = false; + } +} + +static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount) +{ + ImGuiContext& g = *GImGui; + if (window) + g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER); + else + g.WheelingWindowReleaseTimer = 0.0f; + if (g.WheelingWindow == window) + return; + IMGUI_DEBUG_LOG_IO("[io] LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL"); + g.WheelingWindow = window; + g.WheelingWindowRefMousePos = g.IO.MousePos; + if (window == NULL) + { + g.WheelingWindowStartFrame = -1; + g.WheelingAxisAvg = ImVec2(0.0f, 0.0f); + } +} + +static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel) +{ + // For each axis, find window in the hierarchy that may want to use scrolling + ImGuiContext& g = *GImGui; + ImGuiWindow* windows[2] = { NULL, NULL }; + for (int axis = 0; axis < 2; axis++) + if (wheel[axis] != 0.0f) + for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow) + { + // Bubble up into parent window if: + // - a child window doesn't allow any scrolling. + // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag. + //// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP) + const bool has_scrolling = (window->ScrollMax[axis] != 0.0f); + const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs); + //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]); + if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits) + break; // select this window + } + if (windows[0] == NULL && windows[1] == NULL) + return NULL; + + // If there's only one window or only one axis then there's no ambiguity + if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL) + return windows[1] ? windows[1] : windows[0]; + + // If candidate are different windows we need to decide which one to prioritize + // - First frame: only find a winner if one axis is zero. + // - Subsequent frames: only find a winner when one is more than the other. + if (g.WheelingWindowStartFrame == -1) + g.WheelingWindowStartFrame = g.FrameCount; + if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y)) + { + g.WheelingWindowWheelRemainder = wheel; + return NULL; + } + return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1]; +} + +// Called by NewFrame() +void ImGui::UpdateMouseWheel() +{ + // Reset the locked window if we move the mouse or after the timer elapses. + // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795) + ImGuiContext& g = *GImGui; + if (g.WheelingWindow != NULL) + { + g.WheelingWindowReleaseTimer -= g.IO.DeltaTime; + if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold) + g.WheelingWindowReleaseTimer = 0.0f; + if (g.WheelingWindowReleaseTimer <= 0.0f) + LockWheelingWindow(NULL, 0.0f); + } + + ImVec2 wheel; + wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f; + wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f; + + //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y); + ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow; + if (!mouse_window || mouse_window->Collapsed) + return; + + // Zoom / Scale window + // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned. + if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling) + { + LockWheelingWindow(mouse_window, wheel.y); + ImGuiWindow* window = mouse_window; + const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f); + const float scale = new_font_scale / window->FontWindowScale; + window->FontWindowScale = new_font_scale; + if (window == window->RootWindow) + { + const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size; + SetWindowPos(window, window->Pos + offset, 0); + window->Size = ImFloor(window->Size * scale); + window->SizeFull = ImFloor(window->SizeFull * scale); + } + return; + } + if (g.IO.KeyCtrl) + return; + + // Mouse wheel scrolling + // Read about io.MouseWheelRequestAxisSwap and its issue on Mac+Emscripten in UpdateMouseInputs() + if (g.IO.MouseWheelRequestAxisSwap) + wheel = ImVec2(wheel.y, 0.0f); + + // Maintain a rough average of moving magnitude on both axises + // FIXME: should by based on wall clock time rather than frame-counter + g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30); + g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30); + + // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now. + wheel += g.WheelingWindowWheelRemainder; + g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f); + if (wheel.x == 0.0f && wheel.y == 0.0f) + return; + + // Mouse wheel scrolling: find target and apply + // - don't renew lock if axis doesn't apply on the window. + // - select a main axis when both axises are being moved. + if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel))) + if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) + { + bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f }; + if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y]) + do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false; + if (do_scroll[ImGuiAxis_X]) + { + LockWheelingWindow(window, wheel.x); + float max_step = window->InnerRect.GetWidth() * 0.67f; + float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step)); + SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); + } + if (do_scroll[ImGuiAxis_Y]) + { + LockWheelingWindow(window, wheel.y); + float max_step = window->InnerRect.GetHeight() * 0.67f; + float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step)); + SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); + } + } +} + +void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard) +{ + ImGuiContext& g = *GImGui; + g.WantCaptureKeyboardNextFrame = want_capture_keyboard ? 1 : 0; +} + +void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse) +{ + ImGuiContext& g = *GImGui; + g.WantCaptureMouseNextFrame = want_capture_mouse ? 1 : 0; +} + +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +static const char* GetInputSourceName(ImGuiInputSource source) +{ + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Clipboard" }; + IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT); + return input_source_names[source]; +} +static const char* GetMouseSourceName(ImGuiMouseSource source) +{ + const char* mouse_source_names[] = { "Mouse", "TouchScreen", "Pen" }; + IM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT && source >= 0 && source < ImGuiMouseSource_COUNT); + return mouse_source_names[source]; +} +static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) +{ + ImGuiContext& g = *GImGui; + if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } + if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("[io] %s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } + if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("[io] %s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } +} +#endif + +// Process input queue +// We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'. +// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost) +// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87) +void ImGui::UpdateInputEvents(bool trickle_fast_inputs) +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + // Only trickle chars<>key when working with InputText() + // FIXME: InputText() could parse event trail? + // FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters) + const bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1); + + bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false; + int mouse_button_changed = 0x00; + ImBitArray key_changed_mask; + + int event_n = 0; + for (; event_n < g.InputEventsQueue.Size; event_n++) + { + ImGuiInputEvent* e = &g.InputEventsQueue[event_n]; + if (e->Type == ImGuiInputEventType_MousePos) + { + // Trickling Rule: Stop processing queued events if we already handled a mouse button change + ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY); + if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted)) + break; + io.MousePos = event_pos; + io.MouseSource = e->MousePos.MouseSource; + mouse_moved = true; + } + else if (e->Type == ImGuiInputEventType_MouseButton) + { + // Trickling Rule: Stop processing queued events if we got multiple action on the same button + const ImGuiMouseButton button = e->MouseButton.Button; + IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); + if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled)) + break; + if (trickle_fast_inputs && e->MouseButton.MouseSource == ImGuiMouseSource_TouchScreen && mouse_moved) // #2702: TouchScreen have no initial hover. + break; + io.MouseDown[button] = e->MouseButton.Down; + io.MouseSource = e->MouseButton.MouseSource; + mouse_button_changed |= (1 << button); + } + else if (e->Type == ImGuiInputEventType_MouseWheel) + { + // Trickling Rule: Stop processing queued events if we got multiple action on the event + if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0)) + break; + io.MouseWheelH += e->MouseWheel.WheelX; + io.MouseWheel += e->MouseWheel.WheelY; + io.MouseSource = e->MouseWheel.MouseSource; + mouse_wheeled = true; + } + else if (e->Type == ImGuiInputEventType_Key) + { + // Trickling Rule: Stop processing queued events if we got multiple action on the same button + ImGuiKey key = e->Key.Key; + IM_ASSERT(key != ImGuiKey_None); + ImGuiKeyData* key_data = GetKeyData(key); + const int key_data_index = (int)(key_data - g.IO.KeysData); + if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0)) + break; + key_data->Down = e->Key.Down; + key_data->AnalogValue = e->Key.AnalogValue; + key_changed = true; + key_changed_mask.SetBit(key_data_index); + + // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + io.KeysDown[key_data_index] = key_data->Down; + if (io.KeyMap[key_data_index] != -1) + io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down; +#endif + } + else if (e->Type == ImGuiInputEventType_Text) + { + // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with + if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled)) + break; + unsigned int c = e->Text.Char; + io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); + if (trickle_interleaved_keys_and_text) + text_inputted = true; + } + else if (e->Type == ImGuiInputEventType_Focus) + { + // We intentionally overwrite this and process in NewFrame(), in order to give a chance + // to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame. + const bool focus_lost = !e->AppFocused.Focused; + io.AppFocusLost = focus_lost; + } + else + { + IM_ASSERT(0 && "Unknown event!"); + } + } + + // Record trail (for domain-specific applications wanting to access a precise trail) + //if (event_n != 0) IMGUI_DEBUG_LOG_IO("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n); + for (int n = 0; n < event_n; n++) + g.InputEventsTrail.push_back(g.InputEventsQueue[n]); + + // [DEBUG] +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO)) + for (int n = 0; n < g.InputEventsQueue.Size; n++) + DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]); +#endif + + // Remaining events will be processed on the next frame + if (event_n == g.InputEventsQueue.Size) + g.InputEventsQueue.resize(0); + else + g.InputEventsQueue.erase(g.InputEventsQueue.Data, g.InputEventsQueue.Data + event_n); + + // Clear buttons state when focus is lost + // - this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle. + // - we clear in EndFrame() and not now in order allow application/user code polling this flag + // (e.g. custom backend may want to clear additional data, custom widgets may want to react with a "canceling" event). + if (g.IO.AppFocusLost) + g.IO.ClearInputKeys(); +} + +ImGuiID ImGui::GetKeyOwner(ImGuiKey key) +{ + if (!IsNamedKeyOrModKey(key)) + return ImGuiKeyOwner_None; + + ImGuiContext& g = *GImGui; + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + ImGuiID owner_id = owner_data->OwnerCurr; + + if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) + if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) + return ImGuiKeyOwner_None; + + return owner_id; +} + +// TestKeyOwner(..., ID) : (owner == None || owner == ID) +// TestKeyOwner(..., None) : (owner == None) +// TestKeyOwner(..., Any) : no owner test +// All paths are also testing for key not being locked, for the rare cases that key have been locked with using ImGuiInputFlags_LockXXX flags. +bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id) +{ + if (!IsNamedKeyOrModKey(key)) + return true; + + ImGuiContext& g = *GImGui; + if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any) + if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) + return false; + + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + if (owner_id == ImGuiKeyOwner_Any) + return (owner_data->LockThisFrame == false); + + // Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId + // are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things. + // Setting OwnerCurr in SetKeyOwner() is more consistent than testing OwnerNext here: would be inconsistent with getter and other functions. + if (owner_data->OwnerCurr != owner_id) + { + if (owner_data->LockThisFrame) + return false; + if (owner_data->OwnerCurr != ImGuiKeyOwner_None) + return false; + } + + return true; +} + +// _LockXXX flags are useful to lock keys away from code which is not input-owner aware. +// When using _LockXXX flags, you can use ImGuiKeyOwner_Any to lock keys from everyone. +// - SetKeyOwner(..., None) : clears owner +// - SetKeyOwner(..., Any, !Lock) : illegal (assert) +// - SetKeyOwner(..., Any or None, Lock) : set lock +void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags) +{ + IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it) + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function! + + ImGuiContext& g = *GImGui; + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + owner_data->OwnerCurr = owner_data->OwnerNext = owner_id; + + // We cannot lock by default as it would likely break lots of legacy code. + // In the case of using LockUntilRelease while key is not down we still lock during the frame (no key_data->Down test) + owner_data->LockUntilRelease = (flags & ImGuiInputFlags_LockUntilRelease) != 0; + owner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease); +} + +// Rarely used helper +void ImGui::SetKeyOwnersForKeyChord(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) +{ + if (key_chord & ImGuiMod_Ctrl) { SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags); } + if (key_chord & ImGuiMod_Shift) { SetKeyOwner(ImGuiMod_Shift, owner_id, flags); } + if (key_chord & ImGuiMod_Alt) { SetKeyOwner(ImGuiMod_Alt, owner_id, flags); } + if (key_chord & ImGuiMod_Super) { SetKeyOwner(ImGuiMod_Super, owner_id, flags); } + if (key_chord & ImGuiMod_Shortcut) { SetKeyOwner(ImGuiMod_Shortcut, owner_id, flags); } + if (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); } +} + +// This is more or less equivalent to: +// if (IsItemHovered() || IsItemActive()) +// SetKeyOwner(key, GetItemID()); +// Extensive uses of that (e.g. many calls for a single item) may want to manually perform the tests once and then call SetKeyOwner() multiple times. +// More advanced usage scenarios may want to call SetKeyOwner() manually based on different condition. +// Worth noting is that only one item can be hovered and only one item can be active, therefore this usage pattern doesn't need to bother with routing and priority. +void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.LastItemData.ID; + if (id == 0 || (g.HoveredId != id && g.ActiveId != id)) + return; + if ((flags & ImGuiInputFlags_CondMask_) == 0) + flags |= ImGuiInputFlags_CondDefault_; + if ((g.HoveredId == id && (flags & ImGuiInputFlags_CondHovered)) || (g.ActiveId == id && (flags & ImGuiInputFlags_CondActive))) + { + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetItemKeyOwner) == 0); // Passing flags not supported by this function! + SetKeyOwner(key, id, flags & ~ImGuiInputFlags_CondMask_); + } +} + +bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags) +{ + ImGuiContext& g = *GImGui; + + // When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any. + if ((flags & ImGuiInputFlags_RouteMask_) == 0) + flags |= ImGuiInputFlags_RouteFocused; + if (!SetShortcutRouting(key_chord, owner_id, flags)) + return false; + + if (key_chord & ImGuiMod_Shortcut) + key_chord = ConvertShortcutMod(key_chord); + ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_); + if (g.IO.KeyMods != mods) + return false; + + // Special storage location for mods + ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); + if (key == ImGuiKey_None) + key = ConvertSingleModFlagToKey(&g, mods); + + if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_)))) + return false; + IM_ASSERT((flags & ~ImGuiInputFlags_SupportedByShortcut) == 0); // Passing flags not supported by this function! + + return true; +} + + +//----------------------------------------------------------------------------- +// [SECTION] ERROR CHECKING +//----------------------------------------------------------------------------- + +// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. +// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit +// If this triggers you have an issue: +// - Most commonly: mismatched headers and compiled code version. +// - Or: mismatched configuration #define, compilation settings, packing pragma etc. +// The configuration settings mentioned in imconfig.h must be set for all compilation units involved with Dear ImGui, +// which is way it is required you put them in your imconfig file (and not just before including imgui.h). +// Otherwise it is possible that different compilation units would see different structure layout +bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx) +{ + bool error = false; + if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); } + if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); } + if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); } + if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); } + if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); } + if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); } + if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); } + return !error; +} + +// Until 1.89 (IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos() to extend the boundary of a parent (e.g. window or table cell) +// This is causing issues and ambiguity and we need to retire that. +// See https://github.com/ocornut/imgui/issues/5548 for more details. +// [Scenario 1] +// Previously this would make the window content size ~200x200: +// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK +// Instead, please submit an item: +// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); // OK +// Alternative: +// Begin(...) + Dummy(ImVec2(200,200)) + End(); // OK +// [Scenario 2] +// For reference this is one of the issue what we aim to fix with this change: +// BeginGroup() + SomeItem("foobar") + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup() +// The previous logic made SetCursorScreenPos(GetCursorScreenPos()) have a side-effect! It would erroneously incorporate ItemSpacing.y after the item into content size, making the group taller! +// While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect. Using vertical alignment patterns could trigger this issue. +void ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->DC.IsSetPos); + window->DC.IsSetPos = false; +#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (window->DC.CursorPos.x <= window->DC.CursorMaxPos.x && window->DC.CursorPos.y <= window->DC.CursorMaxPos.y) + return; + if (window->SkipItems) + return; + IM_ASSERT(0 && "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries. Please submit an item e.g. Dummy() to validate extent."); +#else + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); +#endif +} + +static void ImGui::ErrorCheckNewFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + // Check user IM_ASSERT macro + // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined! + // If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block. + // This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.) + // #define IM_ASSERT(EXPR) if (SomeCode(EXPR)) SomeMoreCode(); // Wrong! + // #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct! + if (true) IM_ASSERT(1); else IM_ASSERT(0); + + // Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644) + // Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it. +#ifdef __EMSCRIPTEN__ + if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0) + g.IO.DeltaTime = 0.00001f; +#endif + + // Check user data + // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument) + IM_ASSERT(g.Initialized); + IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); + IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); + IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); + IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"); + IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations + IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); + IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); + IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)"); + + // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP) + if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); +#endif + + // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly. + if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors)) + g.IO.ConfigWindowsResizeFromEdges = false; +} + +static void ImGui::ErrorCheckEndFrameSanityChecks() +{ + ImGuiContext& g = *GImGui; + + // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() + // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). + // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will + // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. + // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // while still correctly asserting on mid-frame key press events. + const ImGuiKeyChord key_mods = GetMergedModsFromKeys(); + IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(key_mods); + + // [EXPERIMENTAL] Recover from errors: You may call this yourself before EndFrame(). + //ErrorCheckEndFrameRecover(); + + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) + { + if (g.CurrentWindowStack.Size > 1) + { + ImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended! + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + IM_UNUSED(window); + while (g.CurrentWindowStack.Size > 1) + End(); + } + else + { + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } + + IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!"); +} + +// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls. +// Must be called during or before EndFrame(). +// This is generally flawed as we are not necessarily End/Popping things in the right order. +// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet. +// FIXME: Can't recover from interleaved BeginTabBar/Begin +void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations" + ImGuiContext& g = *GImGui; + while (g.CurrentWindowStack.Size > 0) //-V1044 + { + ErrorCheckEndWindowRecover(log_callback, user_data); + ImGuiWindow* window = g.CurrentWindow; + if (g.CurrentWindowStack.Size == 1) + { + IM_ASSERT(window->IsFallbackWindow); + break; + } + if (window->Flags & ImGuiWindowFlags_ChildWindow) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name); + EndChild(); + } + else + { + if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name); + End(); + } + } +} + +// Must be called before End()/EndChild() +void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + ImGuiContext& g = *GImGui; + while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow)) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name); + EndTable(); + } + + ImGuiWindow* window = g.CurrentWindow; + ImGuiStackSizes* stack_sizes = &g.CurrentWindowStack.back().StackSizesOnBegin; + IM_ASSERT(window != NULL); + while (g.CurrentTabBar != NULL) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name); + EndTabBar(); + } + while (window->DC.TreeDepth > 0) + { + if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name); + TreePop(); + } + while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name); + EndGroup(); + } + while (window->IDStack.Size > 1) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name); + PopID(); + } + while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name); + EndDisabled(); + } + while (g.ColorStack.Size > stack_sizes->SizeOfColorStack) + { + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col)); + PopStyleColor(); + } + while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name); + PopItemFlag(); + } + while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); + PopStyleVar(); + } + while (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'", window->Name); + PopFont(); + } + while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044 + { + if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name); + PopFocusScope(); + } +} + +// Save current stack sizes for later compare +void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiWindow* window = g.CurrentWindow; + SizeOfIDStack = (short)window->IDStack.Size; + SizeOfColorStack = (short)g.ColorStack.Size; + SizeOfStyleVarStack = (short)g.StyleVarStack.Size; + SizeOfFontStack = (short)g.FontStack.Size; + SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; + SizeOfGroupStack = (short)g.GroupStack.Size; + SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size; + SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; + SizeOfDisabledStack = (short)g.DisabledStackSize; +} + +// Compare to detect usage errors +void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx) +{ + ImGuiContext& g = *ctx; + ImGuiWindow* window = g.CurrentWindow; + IM_UNUSED(window); + + // Window stacks + // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!"); + + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); + IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!"); + IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!"); + IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!"); + IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!"); + IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!"); + IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!"); + IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!"); +} + + +//----------------------------------------------------------------------------- +// [SECTION] LAYOUT +//----------------------------------------------------------------------------- +// - ItemSize() +// - ItemAdd() +// - SameLine() +// - GetCursorScreenPos() +// - SetCursorScreenPos() +// - GetCursorPos(), GetCursorPosX(), GetCursorPosY() +// - SetCursorPos(), SetCursorPosX(), SetCursorPosY() +// - GetCursorStartPos() +// - Indent() +// - Unindent() +// - SetNextItemWidth() +// - PushItemWidth() +// - PushMultiItemsWidths() +// - PopItemWidth() +// - CalcItemWidth() +// - CalcItemSize() +// - GetTextLineHeight() +// - GetTextLineHeightWithSpacing() +// - GetFrameHeight() +// - GetFrameHeightWithSpacing() +// - GetContentRegionMax() +// - GetContentRegionMaxAbs() [Internal] +// - GetContentRegionAvail(), +// - GetWindowContentRegionMin(), GetWindowContentRegionMax() +// - BeginGroup() +// - EndGroup() +// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns. +//----------------------------------------------------------------------------- + +// Advance cursor given item size for layout. +// Register minimum needed size so it can extend the bounding box used for auto-fit calculation. +// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different. +void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // We increase the height in this function to accommodate for baseline offset. + // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, + // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. + const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f; + + const float line_y1 = window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y; + const float line_height = ImMax(window->DC.CurrLineSize.y, /*ImMax(*/window->DC.CursorPos.y - line_y1/*, 0.0f)*/ + size.y + offset_to_match_baseline_y); + + // Always align ourselves on pixel boundaries + //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x; + window->DC.CursorPosPrevLine.y = line_y1; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line + window->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + + window->DC.PrevLineSize.y = line_height; + window->DC.CurrLineSize.y = 0.0f; + window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); + window->DC.CurrLineTextBaseOffset = 0.0f; + window->DC.IsSameLine = window->DC.IsSetPos = false; + + // Horizontal layout mode + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + SameLine(); +} + +// Declare item bounding box for clipping and interaction. +// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface +// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction. +bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Set item data + // (DisplayRect is left untouched, made valid when ImGuiItemStatusFlags_HasDisplayRect is set) + g.LastItemData.ID = id; + g.LastItemData.Rect = bb; + g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; + g.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; + g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; + + // Directional navigation processing + if (id != 0) + { + KeepAliveID(id); + + // Runs prior to clipping early-out + // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget + // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests + // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of + // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame. + // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able + // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). + // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. + // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. + if (!(g.LastItemData.InFlags & ImGuiItemFlags_NoNav)) + { + window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent); + if (g.NavId == id || g.NavAnyRequest) + if (g.NavWindow->RootWindowForNav == window->RootWindowForNav) + if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened)) + NavProcessItem(); + } + + // [DEBUG] People keep stumbling on this problem and using "" as identifier in the root of a window instead of "##something". + // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something". + // READ THE FAQ: https://dearimgui.com/faq + IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); + } + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; + g.NextItemData.ItemFlags = ImGuiItemFlags_None; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (id != 0) + IMGUI_TEST_ENGINE_ITEM_ADD(id, g.LastItemData.NavRect, &g.LastItemData); +#endif + + // Clipping test + // (FIXME: This is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value) + //const bool is_clipped = IsClippedEx(bb, id); + //if (is_clipped) + // return false; + const bool is_rect_visible = bb.Overlaps(window->ClipRect); + if (!is_rect_visible) + if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId)) + if (!g.LogEnabled) + return false; + + // [DEBUG] +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (id != 0 && id == g.DebugLocateId) + DebugLocateItemResolveWithLastItem(); +#endif + //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] + //if ((g.LastItemData.InFlags & ImGuiItemFlags_NoNav) == 0) + // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] + + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) + if (is_rect_visible) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Visible; + if (IsMouseHoveringRect(bb.Min, bb.Max)) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; + return true; +} + +// Gets back to previous line and continue with horizontal layout +// offset_from_start_x == 0 : follow right after previous item +// offset_from_start_x != 0 : align to specified x position (relative to window/group left) +// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w >= 0 : enforce spacing amount +void ImGui::SameLine(float offset_from_start_x, float spacing_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + if (offset_from_start_x != 0.0f) + { + if (spacing_w < 0.0f) + spacing_w = 0.0f; + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + else + { + if (spacing_w < 0.0f) + spacing_w = g.Style.ItemSpacing.x; + window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w; + window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y; + } + window->DC.CurrLineSize = window->DC.PrevLineSize; + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + window->DC.IsSameLine = true; +} + +ImVec2 ImGui::GetCursorScreenPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos; +} + +// 2022/08/05: Setting cursor position also extend boundaries (via modifying CursorMaxPos) used to compute window size, group size etc. +// I believe this was is a judicious choice but it's probably being relied upon (it has been the case since 1.31 and 1.50) +// It would be sane if we requested user to use SetCursorPos() + Dummy(ImVec2(0,0)) to extend CursorMaxPos... +void ImGui::SetCursorScreenPos(const ImVec2& pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = pos; + //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); + window->DC.IsSetPos = true; +} + +// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient. +// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'. +ImVec2 ImGui::GetCursorPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos - window->Pos + window->Scroll; +} + +float ImGui::GetCursorPosX() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; +} + +float ImGui::GetCursorPosY() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; +} + +void ImGui::SetCursorPos(const ImVec2& local_pos) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos = window->Pos - window->Scroll + local_pos; + //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); + window->DC.IsSetPos = true; +} + +void ImGui::SetCursorPosX(float x) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x; + //window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x); + window->DC.IsSetPos = true; +} + +void ImGui::SetCursorPosY(float y) +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y; + //window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); + window->DC.IsSetPos = true; +} + +ImVec2 ImGui::GetCursorStartPos() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CursorStartPos - window->Pos; +} + +void ImGui::Indent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +void ImGui::Unindent(float indent_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing; + window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x; +} + +// Affect large frame+labels widgets only. +void ImGui::SetNextItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Width = item_width; +} + +// FIXME: Remove the == 0.0f behavior? +void ImGui::PushItemWidth(float item_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width + window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PushMultiItemsWidths(int components, float w_full) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiStyle& style = g.Style; + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); + window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width + window->DC.ItemWidthStack.push_back(w_item_last); + for (int i = 0; i < components - 2; i++) + window->DC.ItemWidthStack.push_back(w_item_one); + window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one; + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; +} + +void ImGui::PopItemWidth() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemWidth = window->DC.ItemWidthStack.back(); + window->DC.ItemWidthStack.pop_back(); +} + +// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(). +// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags() +float ImGui::CalcItemWidth() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float w; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + w = g.NextItemData.Width; + else + w = window->DC.ItemWidth; + if (w < 0.0f) + { + float region_max_x = GetContentRegionMaxAbs().x; + w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); + } + w = IM_FLOOR(w); + return w; +} + +// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth(). +// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical. +// Note that only CalcItemWidth() is publicly exposed. +// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) +ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 region_max; + if (size.x < 0.0f || size.y < 0.0f) + region_max = GetContentRegionMaxAbs(); + + if (size.x == 0.0f) + size.x = default_w; + else if (size.x < 0.0f) + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); + + if (size.y == 0.0f) + size.y = default_h; + else if (size.y < 0.0f) + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); + + return size; +} + +float ImGui::GetTextLineHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize; +} + +float ImGui::GetTextLineHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.ItemSpacing.y; +} + +float ImGui::GetFrameHeight() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f; +} + +float ImGui::GetFrameHeightWithSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; +} + +// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! + +// FIXME: This is in window space (not screen space!). +ImVec2 ImGui::GetContentRegionMax() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; + return mx - window->Pos; +} + +// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. +ImVec2 ImGui::GetContentRegionMaxAbs() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; + return mx; +} + +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxAbs() - window->DC.CursorPos; +} + +// In window space (not screen space!) +ImVec2 ImGui::GetWindowContentRegionMin() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Min - window->Pos; +} + +ImVec2 ImGui::GetWindowContentRegionMax() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ContentRegionRect.Max - window->Pos; +} + +// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) +// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. +// FIXME-OPT: Could we safely early out on ->SkipItems? +void ImGui::BeginGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + g.GroupStack.resize(g.GroupStack.Size + 1); + ImGuiGroupData& group_data = g.GroupStack.back(); + group_data.WindowID = window->ID; + group_data.BackupCursorPos = window->DC.CursorPos; + group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; + group_data.BackupIndent = window->DC.Indent; + group_data.BackupGroupOffset = window->DC.GroupOffset; + group_data.BackupCurrLineSize = window->DC.CurrLineSize; + group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset; + group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; + group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; + group_data.EmitItem = true; + + window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; + window->DC.Indent = window->DC.GroupOffset; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return +} + +void ImGui::EndGroup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls + + ImGuiGroupData& group_data = g.GroupStack.back(); + IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window? + + if (window->DC.IsSetPos) + ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + + ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); + + window->DC.CursorPos = group_data.BackupCursorPos; + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); + window->DC.Indent = group_data.BackupIndent; + window->DC.GroupOffset = group_data.BackupGroupOffset; + window->DC.CurrLineSize = group_data.BackupCurrLineSize; + window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; + if (g.LogEnabled) + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return + + if (!group_data.EmitItem) + { + g.GroupStack.pop_back(); + return; + } + + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + ItemSize(group_bb.GetSize()); + ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop); + + // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. + // It would be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. + // Also if you grep for LastItemId you'll notice it is only used in that context. + // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) + const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; + const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); + if (group_contains_curr_active_id) + g.LastItemData.ID = g.ActiveId; + else if (group_contains_prev_active_id) + g.LastItemData.ID = g.ActiveIdPreviousFrame; + g.LastItemData.Rect = group_bb; + + // Forward Hovered flag + const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0; + if (group_contains_curr_hovered_id) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + + // Forward Edited flag + if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited; + + // Forward Deactivated flag + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated; + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated; + + g.GroupStack.pop_back(); + //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] +} + + +//----------------------------------------------------------------------------- +// [SECTION] SCROLLING +//----------------------------------------------------------------------------- + +// Helper to snap on edges when aiming at an item very close to the edge, +// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling. +// When we refactor the scrolling API this may be configurable with a flag? +// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default. +static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio) +{ + if (target <= snap_min + snap_threshold) + return ImLerp(snap_min, target, center_ratio); + if (target >= snap_max - snap_threshold) + return ImLerp(target, snap_max, center_ratio); + return target; +} + +static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) +{ + ImVec2 scroll = window->Scroll; + ImVec2 decoration_size(window->DecoOuterSizeX1 + window->DecoInnerSizeX1 + window->DecoOuterSizeX2, window->DecoOuterSizeY1 + window->DecoInnerSizeY1 + window->DecoOuterSizeY2); + for (int axis = 0; axis < 2; axis++) + { + if (window->ScrollTarget[axis] < FLT_MAX) + { + float center_ratio = window->ScrollTargetCenterRatio[axis]; + float scroll_target = window->ScrollTarget[axis]; + if (window->ScrollTargetEdgeSnapDist[axis] > 0.0f) + { + float snap_min = 0.0f; + float snap_max = window->ScrollMax[axis] + window->SizeFull[axis] - decoration_size[axis]; + scroll_target = CalcScrollEdgeSnap(scroll_target, snap_min, snap_max, window->ScrollTargetEdgeSnapDist[axis], center_ratio); + } + scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); + } + scroll[axis] = IM_FLOOR(ImMax(scroll[axis], 0.0f)); + if (!window->Collapsed && !window->SkipItems) + scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); + } + return scroll; +} + +void ImGui::ScrollToItem(ImGuiScrollFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ScrollToRectEx(window, g.LastItemData.NavRect, flags); +} + +void ImGui::ScrollToRect(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) +{ + ScrollToRectEx(window, item_rect, flags); +} + +// Scroll to keep newly navigated item fully into view +ImVec2 ImGui::ScrollToRectEx(ImGuiWindow* window, const ImRect& item_rect, ImGuiScrollFlags flags) +{ + ImGuiContext& g = *GImGui; + ImRect scroll_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)); + scroll_rect.Min.x = ImMin(scroll_rect.Min.x + window->DecoInnerSizeX1, scroll_rect.Max.x); + scroll_rect.Min.y = ImMin(scroll_rect.Min.y + window->DecoInnerSizeY1, scroll_rect.Max.y); + //GetForegroundDrawList(window)->AddRect(item_rect.Min, item_rect.Max, IM_COL32(255,0,0,255), 0.0f, 0, 5.0f); // [DEBUG] + //GetForegroundDrawList(window)->AddRect(scroll_rect.Min, scroll_rect.Max, IM_COL32_WHITE); // [DEBUG] + + // Check that only one behavior is selected per axis + IM_ASSERT((flags & ImGuiScrollFlags_MaskX_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskX_)); + IM_ASSERT((flags & ImGuiScrollFlags_MaskY_) == 0 || ImIsPowerOfTwo(flags & ImGuiScrollFlags_MaskY_)); + + // Defaults + ImGuiScrollFlags in_flags = flags; + if ((flags & ImGuiScrollFlags_MaskX_) == 0 && window->ScrollbarX) + flags |= ImGuiScrollFlags_KeepVisibleEdgeX; + if ((flags & ImGuiScrollFlags_MaskY_) == 0) + flags |= window->Appearing ? ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeY; + + const bool fully_visible_x = item_rect.Min.x >= scroll_rect.Min.x && item_rect.Max.x <= scroll_rect.Max.x; + const bool fully_visible_y = item_rect.Min.y >= scroll_rect.Min.y && item_rect.Max.y <= scroll_rect.Max.y; + const bool can_be_fully_visible_x = (item_rect.GetWidth() + g.Style.ItemSpacing.x * 2.0f) <= scroll_rect.GetWidth() || (window->AutoFitFramesX > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0; + const bool can_be_fully_visible_y = (item_rect.GetHeight() + g.Style.ItemSpacing.y * 2.0f) <= scroll_rect.GetHeight() || (window->AutoFitFramesY > 0) || (window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0; + + if ((flags & ImGuiScrollFlags_KeepVisibleEdgeX) && !fully_visible_x) + { + if (item_rect.Min.x < scroll_rect.Min.x || !can_be_fully_visible_x) + SetScrollFromPosX(window, item_rect.Min.x - g.Style.ItemSpacing.x - window->Pos.x, 0.0f); + else if (item_rect.Max.x >= scroll_rect.Max.x) + SetScrollFromPosX(window, item_rect.Max.x + g.Style.ItemSpacing.x - window->Pos.x, 1.0f); + } + else if (((flags & ImGuiScrollFlags_KeepVisibleCenterX) && !fully_visible_x) || (flags & ImGuiScrollFlags_AlwaysCenterX)) + { + if (can_be_fully_visible_x) + SetScrollFromPosX(window, ImFloor((item_rect.Min.x + item_rect.Max.x) * 0.5f) - window->Pos.x, 0.5f); + else + SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x, 0.0f); + } + + if ((flags & ImGuiScrollFlags_KeepVisibleEdgeY) && !fully_visible_y) + { + if (item_rect.Min.y < scroll_rect.Min.y || !can_be_fully_visible_y) + SetScrollFromPosY(window, item_rect.Min.y - g.Style.ItemSpacing.y - window->Pos.y, 0.0f); + else if (item_rect.Max.y >= scroll_rect.Max.y) + SetScrollFromPosY(window, item_rect.Max.y + g.Style.ItemSpacing.y - window->Pos.y, 1.0f); + } + else if (((flags & ImGuiScrollFlags_KeepVisibleCenterY) && !fully_visible_y) || (flags & ImGuiScrollFlags_AlwaysCenterY)) + { + if (can_be_fully_visible_y) + SetScrollFromPosY(window, ImFloor((item_rect.Min.y + item_rect.Max.y) * 0.5f) - window->Pos.y, 0.5f); + else + SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y, 0.0f); + } + + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + ImVec2 delta_scroll = next_scroll - window->Scroll; + + // Also scroll parent window to keep us into view if necessary + if (!(flags & ImGuiScrollFlags_NoScrollParent) && (window->Flags & ImGuiWindowFlags_ChildWindow)) + { + // FIXME-SCROLL: May be an option? + if ((in_flags & (ImGuiScrollFlags_AlwaysCenterX | ImGuiScrollFlags_KeepVisibleCenterX)) != 0) + in_flags = (in_flags & ~ImGuiScrollFlags_MaskX_) | ImGuiScrollFlags_KeepVisibleEdgeX; + if ((in_flags & (ImGuiScrollFlags_AlwaysCenterY | ImGuiScrollFlags_KeepVisibleCenterY)) != 0) + in_flags = (in_flags & ~ImGuiScrollFlags_MaskY_) | ImGuiScrollFlags_KeepVisibleEdgeY; + delta_scroll += ScrollToRectEx(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll), in_flags); + } + + return delta_scroll; +} + +float ImGui::GetScrollX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.x; +} + +float ImGui::GetScrollY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->Scroll.y; +} + +float ImGui::GetScrollMaxX() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.x; +} + +float ImGui::GetScrollMaxY() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return window->ScrollMax.y; +} + +void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x) +{ + window->ScrollTarget.x = scroll_x; + window->ScrollTargetCenterRatio.x = 0.0f; + window->ScrollTargetEdgeSnapDist.x = 0.0f; +} + +void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y) +{ + window->ScrollTarget.y = scroll_y; + window->ScrollTargetCenterRatio.y = 0.0f; + window->ScrollTargetEdgeSnapDist.y = 0.0f; +} + +void ImGui::SetScrollX(float scroll_x) +{ + ImGuiContext& g = *GImGui; + SetScrollX(g.CurrentWindow, scroll_x); +} + +void ImGui::SetScrollY(float scroll_y) +{ + ImGuiContext& g = *GImGui; + SetScrollY(g.CurrentWindow, scroll_y); +} + +// Note that a local position will vary depending on initial scroll value, +// This is a little bit confusing so bear with us: +// - local_pos = (absolution_pos - window->Pos) +// - So local_x/local_y are 0.0f for a position at the upper-left corner of a window, +// and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area. +// - They mostly exist because of legacy API. +// Following the rules above, when trying to work with scrolling code, consider that: +// - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect! +// - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense +// We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size +void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio) +{ + IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f); + window->ScrollTarget.x = IM_FLOOR(local_x - window->DecoOuterSizeX1 - window->DecoInnerSizeX1 + window->Scroll.x); // Convert local position to scroll offset + window->ScrollTargetCenterRatio.x = center_x_ratio; + window->ScrollTargetEdgeSnapDist.x = 0.0f; +} + +void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio) +{ + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); + window->ScrollTarget.y = IM_FLOOR(local_y - window->DecoOuterSizeY1 - window->DecoInnerSizeY1 + window->Scroll.y); // Convert local position to scroll offset + window->ScrollTargetCenterRatio.y = center_y_ratio; + window->ScrollTargetEdgeSnapDist.y = 0.0f; +} + +void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio); +} + +void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio); +} + +// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item. +void ImGui::SetScrollHereX(float center_x_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x); + float target_pos_x = ImLerp(g.LastItemData.Rect.Min.x - spacing_x, g.LastItemData.Rect.Max.x + spacing_x, center_x_ratio); + SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos + + // Tweak: snap on edges when aiming at an item very close to the edge + window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x); +} + +// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. +void ImGui::SetScrollHereY(float center_y_ratio) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y); + float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio); + SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos + + // Tweak: snap on edges when aiming at an item very close to the edge + window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y); +} + +//----------------------------------------------------------------------------- +// [SECTION] TOOLTIPS +//----------------------------------------------------------------------------- + +bool ImGui::BeginTooltip() +{ + return BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); +} + +bool ImGui::BeginItemTooltip() +{ + if (!IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + return false; + return BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); +} + +bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags) +{ + ImGuiContext& g = *GImGui; + + if (g.DragDropWithinSource || g.DragDropWithinTarget) + { + // Drag and Drop tooltips are positioning differently than other tooltips: + // - offset visibility to increase visibility around mouse. + // - never clamp within outer viewport boundary. + // We call SetNextWindowPos() to enforce position and disable clamping. + // See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones). + //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; + ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET * g.Style.MouseCursorScale; + SetNextWindowPos(tooltip_pos); + SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); + //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( + tooltip_flags |= ImGuiTooltipFlags_OverridePrevious; + } + + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (tooltip_flags & ImGuiTooltipFlags_OverridePrevious) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. + SetWindowHiddendAndSkipItemsForCurrentFrame(window); + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); + } + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; + Begin(window_name, NULL, flags | extra_window_flags); + // 2023-03-09: Added bool return value to the API, but currently always returning true. + // If this ever returns false we need to update BeginDragDropSource() accordingly. + //if (!ret) + // End(); + //return ret; + return true; +} + +void ImGui::EndTooltip() +{ + IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls + End(); +} + +void ImGui::SetTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + SetTooltipV(fmt, args); + va_end(args); +} + +void ImGui::SetTooltipV(const char* fmt, va_list args) +{ + if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None)) + return; + TextV(fmt, args); + EndTooltip(); +} + +// Shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav'. +// Defaults to == ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort when using the mouse. +void ImGui::SetItemTooltip(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + SetTooltipV(fmt, args); + va_end(args); +} + +void ImGui::SetItemTooltipV(const char* fmt, va_list args) +{ + if (IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + SetTooltipV(fmt, args); +} + + +//----------------------------------------------------------------------------- +// [SECTION] POPUPS +//----------------------------------------------------------------------------- + +// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel +bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + if (popup_flags & ImGuiPopupFlags_AnyPopupId) + { + // Return true if any popup is open at the current BeginPopup() level of the popup stack + // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level. + IM_ASSERT(id == 0); + if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) + return g.OpenPopupStack.Size > 0; + else + return g.OpenPopupStack.Size > g.BeginPopupStack.Size; + } + else + { + if (popup_flags & ImGuiPopupFlags_AnyPopupLevel) + { + // Return true if the popup is open anywhere in the popup stack + for (int n = 0; n < g.OpenPopupStack.Size; n++) + if (g.OpenPopupStack[n].PopupId == id) + return true; + return false; + } + else + { + // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query) + return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id; + } + } +} + +bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id); + if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0) + IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally + return IsPopupOpen(id, popup_flags); +} + +// Also see FindBlockingModal(NULL) +ImGuiWindow* ImGui::GetTopMostPopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if (popup->Flags & ImGuiWindowFlags_Modal) + return popup; + return NULL; +} + +// See Demo->Stacked Modal to confirm what this is for. +ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup)) + return popup; + return NULL; +} + +void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = g.CurrentWindow->GetID(str_id); + IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X)\n", str_id, id); + OpenPopupEx(id, popup_flags); +} + +void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + OpenPopupEx(id, popup_flags); +} + +// Mark popup as open (toggle toward open state). +// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. +// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). +// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL) +void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* parent_window = g.CurrentWindow; + const int current_stack_size = g.BeginPopupStack.Size; + + if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup) + if (IsPopupOpen((ImGuiID)0, ImGuiPopupFlags_AnyPopupId)) + return; + + ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. + popup_ref.PopupId = id; + popup_ref.Window = NULL; + popup_ref.BackupNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type). + popup_ref.OpenFrameCount = g.FrameCount; + popup_ref.OpenParentId = parent_window->IDStack.back(); + popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; + + IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)\n", id); + if (g.OpenPopupStack.Size < current_stack_size + 1) + { + g.OpenPopupStack.push_back(popup_ref); + } + else + { + // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui + // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing + // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand. + if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1) + { + g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount; + } + else + { + // Close child popups if any, then flag popup for open/reopen + ClosePopupToLevel(current_stack_size, false); + g.OpenPopupStack.push_back(popup_ref); + } + + // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow(). + // This is equivalent to what ClosePopupToLevel() does. + //if (g.OpenPopupStack[current_stack_size].PopupId == id) + // FocusWindow(parent_window); + } +} + +// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it. +// This function closes any popups that are over 'ref_window'. +void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size == 0) + return; + + // Don't close our own child popup windows. + int popup_count_to_keep = 0; + if (ref_window) + { + // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow) + for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++) + { + ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep]; + if (!popup.Window) + continue; + IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0); + if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow) + continue; + + // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow) + // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3: + // Window -> Popup1 -> Popup2 -> Popup3 + // - Each popups may contain child windows, which is why we compare ->RootWindow! + // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child + bool ref_window_is_descendent_of_popup = false; + for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++) + if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window) + if (IsWindowWithinBeginStackOf(ref_window, popup_window)) + { + ref_window_is_descendent_of_popup = true; + break; + } + if (!ref_window_is_descendent_of_popup) + break; + } + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + { + IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\")\n", ref_window ? ref_window->Name : ""); + ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup); + } +} + +void ImGui::ClosePopupsExceptModals() +{ + ImGuiContext& g = *GImGui; + + int popup_count_to_keep; + for (popup_count_to_keep = g.OpenPopupStack.Size; popup_count_to_keep > 0; popup_count_to_keep--) + { + ImGuiWindow* window = g.OpenPopupStack[popup_count_to_keep - 1].Window; + if (!window || (window->Flags & ImGuiWindowFlags_Modal)) + break; + } + if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below + ClosePopupToLevel(popup_count_to_keep, true); +} + +void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup) +{ + ImGuiContext& g = *GImGui; + IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup); + IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); + + // Trim open popup stack + ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; + ImGuiWindow* popup_backup_nav_window = g.OpenPopupStack[remaining].BackupNavWindow; + g.OpenPopupStack.resize(remaining); + + if (restore_focus_to_window_under_popup) + { + ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window; + if (focus_window && !focus_window->WasActive && popup_window) + FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_RestoreFocusedChild); // Fallback + else + FocusWindow(focus_window, (g.NavLayer == ImGuiNavLayer_Main) ? ImGuiFocusRequestFlags_RestoreFocusedChild : ImGuiFocusRequestFlags_None); + } +} + +// Close the popup we have begin-ed into. +void ImGui::CloseCurrentPopup() +{ + ImGuiContext& g = *GImGui; + int popup_idx = g.BeginPopupStack.Size - 1; + if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId) + return; + + // Closing a menu closes its top-most parent popup (unless a modal) + while (popup_idx > 0) + { + ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window; + ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window; + bool close_parent = false; + if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu)) + if (parent_popup_window && !(parent_popup_window->Flags & ImGuiWindowFlags_MenuBar)) + close_parent = true; + if (!close_parent) + break; + popup_idx--; + } + IMGUI_DEBUG_LOG_POPUP("[popup] CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx); + ClosePopupToLevel(popup_idx, true); + + // A common pattern is to close a popup when selecting a menu item/selectable that will open another window. + // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window. + // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic. + if (ImGuiWindow* window = g.NavWindow) + window->DC.NavHideHighlightOneFrame = true; +} + +// Attention! BeginPopup() adds default flags which BeginPopupEx()! +bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + char name[20]; + if (flags & ImGuiWindowFlags_ChildMenu) + ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuCount); // Recycle windows based on depth + else + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + + flags |= ImGuiWindowFlags_Popup; + bool is_open = Begin(name, NULL, flags); + if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) + EndPopup(); + + return is_open; +} + +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + ImGuiID id = g.CurrentWindow->GetID(str_id); + return BeginPopupEx(id, flags); +} + +// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup. +// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here. +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = window->GetID(name); + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + // Center modal windows by default for increased visibility + // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves) + // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + { + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); + } + + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse; + const bool is_open = Begin(name, p_open, flags); + if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + { + EndPopup(); + if (is_open) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + return false; + } + return is_open; +} + +void ImGui::EndPopup() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls + IM_ASSERT(g.BeginPopupStack.Size > 0); + + // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests) + if (g.NavWindow == window) + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); + + // Child-popups don't need to be laid out + IM_ASSERT(g.WithinEndChild == false); + if (window->Flags & ImGuiWindowFlags_ChildWindow) + g.WithinEndChild = true; + End(); + g.WithinEndChild = false; +} + +// Helper to open a popup if mouse button is released over the item +// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup() +void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + { + ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + OpenPopupEx(id, popup_flags); + } +} + +// This is a helper to handle the simplest case of associating one named popup to one given widget. +// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. +// - To create a popup with a specific identifier, pass it in str_id. +// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. +// - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). +// This is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight); +// return BeginPopup(id); +// Which is essentially the same as: +// id = str_id ? GetID(str_id) : GetItemID(); +// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) +// OpenPopup(id); +// return BeginPopup(id); +// The main difference being that this is tweaked to avoid computing the ID twice. +bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + ImGuiID id = str_id ? window->GetID(str_id) : g.LastItemData.ID; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict! + IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item) + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!str_id) + str_id = "window_context"; + ImGuiID id = window->GetID(str_id); + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered()) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (!str_id) + str_id = "void_context"; + ImGuiID id = window->GetID(str_id); + int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_); + if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) + if (GetTopMostPopupModal() == NULL) + OpenPopupEx(id, popup_flags); + return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings); +} + +// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.) +// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it. +// (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor +// information are available, it may represent the entire platform monitor from the frame of reference of the current viewport. +// this allows us to have tooltips/popups displayed out of the parent viewport.) +ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy) +{ + ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size); + //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255)); + //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255)); + + // Combo Box policy (we want a connecting edge) + if (policy == ImGuiPopupPositionPolicy_ComboBox) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + ImVec2 pos; + if (dir == ImGuiDir_Down) pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y); // Below, Toward Right (default) + if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right + if (dir == ImGuiDir_Left) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left + if (dir == ImGuiDir_Up) pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left + if (!r_outer.Contains(ImRect(pos, pos + size))) + continue; + *last_dir = dir; + return pos; + } + } + + // Tooltip and Default popup policy + // (Always first try the direction we used on the last frame, if any) + if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default) + { + const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left }; + for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++) + { + const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n]; + if (n != -1 && dir == *last_dir) // Already tried this direction? + continue; + + const float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x); + const float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y); + + // If there's not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width) + if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right)) + continue; + if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down)) + continue; + + ImVec2 pos; + pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x; + pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y; + + // Clamp top-left corner of popup + pos.x = ImMax(pos.x, r_outer.Min.x); + pos.y = ImMax(pos.y, r_outer.Min.y); + + *last_dir = dir; + return pos; + } + } + + // Fallback when not enough room: + *last_dir = ImGuiDir_None; + + // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible. + if (policy == ImGuiPopupPositionPolicy_Tooltip) + return ref_pos + ImVec2(2, 2); + + // Otherwise try to keep within display + ImVec2 pos = ref_pos; + pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x); + pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y); + return pos; +} + +// Note that this is used for popups, which can overlap the non work-area of individual viewports. +ImRect ImGui::GetPopupAllowedExtentRect(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(window); + ImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect(); + ImVec2 padding = g.Style.DisplaySafeAreaPadding; + r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f)); + return r_screen; +} + +ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + + ImRect r_outer = GetPopupAllowedExtentRect(window); + if (window->Flags & ImGuiWindowFlags_ChildMenu) + { + // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds. + // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu. + IM_ASSERT(g.CurrentWindow == window); + ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2].Window; + float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x). + ImRect r_avoid; + if (parent_window->DC.MenuBarAppending) + r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field + else + r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX); + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); + } + if (window->Flags & ImGuiWindowFlags_Popup) + { + return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositionPolicy_Default); // Ideally we'd disable r_avoid here + } + if (window->Flags & ImGuiWindowFlags_Tooltip) + { + // Position tooltip (always follows mouse + clamp within outer boundaries) + // Note that drag and drop tooltips are NOT using this path: BeginTooltipEx() manually sets their position. + // In theory we could handle both cases in same location, but requires a bit of shuffling as drag and drop tooltips are calling SetWindowPos() leading to 'window_pos_set_by_api' being set in Begin() + IM_ASSERT(g.CurrentWindow == window); + const float scale = g.Style.MouseCursorScale; + const ImVec2 ref_pos = NavCalcPreferredRefPos(); + const ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET * scale; + ImRect r_avoid; + if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); + else + r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. + //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255, 0, 255, 255)); + return FindBestWindowPosForPopupEx(tooltip_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); + } + IM_ASSERT(0); + return window->Pos; +} + +//----------------------------------------------------------------------------- +// [SECTION] KEYBOARD/GAMEPAD NAVIGATION +//----------------------------------------------------------------------------- + +// FIXME-NAV: The existence of SetNavID vs SetFocusID vs FocusWindow() needs to be clarified/reworked. +// In our terminology those should be interchangeable, yet right now this is super confusing. +// Those two functions are merely a legacy artifact, so at minimum naming should be clarified. + +void ImGui::SetNavWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.NavWindow != window) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")\n", window ? window->Name : ""); + g.NavWindow = window; + } + g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavClearPreferredPosForAxis(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer][axis] = FLT_MAX; +} + +void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow != NULL); + IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu); + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = focus_scope_id; + g.NavWindow->NavLastIds[nav_layer] = id; + g.NavWindow->NavRectRel[nav_layer] = rect_rel; + + // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavClearPreferredPosForAxis(ImGuiAxis_Y); +} + +void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(id != 0); + + if (g.NavWindow != window) + SetNavWindow(window); + + // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and g.CurrentFocusScopeId are valid. + // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text) + const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent; + g.NavId = id; + g.NavLayer = nav_layer; + g.NavFocusScopeId = g.CurrentFocusScopeId; + window->NavLastIds[nav_layer] = id; + if (g.LastItemData.ID == id) + window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); + + if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; + + // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavClearPreferredPosForAxis(ImGuiAxis_Y); +} + +static ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) +{ + if (ImFabs(dx) > ImFabs(dy)) + return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left; + return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up; +} + +static float inline NavScoreItemDistInterval(float cand_min, float cand_max, float curr_min, float curr_max) +{ + if (cand_max < curr_min) + return cand_max - curr_min; + if (curr_max < cand_min) + return cand_min - curr_max; + return 0.0f; +} + +// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 +static bool ImGui::NavScoreItem(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (g.NavLayer != window->DC.NavLayerCurrent) + return false; + + // FIXME: Those are not good variables names + ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle + const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width) + g.NavScoringDebugCount++; + + // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring + if (window->ParentWindow == g.NavWindow) + { + IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened); + if (!window->ClipRect.Overlaps(cand)) + return false; + cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window + } + + // Compute distance between boxes + // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed. + float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x); + float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items + if (dby != 0.0f && dbx != 0.0f) + dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f); + float dist_box = ImFabs(dbx) + ImFabs(dby); + + // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter) + float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x); + float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y); + float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee) + + // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance + ImGuiDir quadrant; + float dax = 0.0f, day = 0.0f, dist_axial = 0.0f; + if (dbx != 0.0f || dby != 0.0f) + { + // For non-overlapping boxes, use distance between boxes + dax = dbx; + day = dby; + dist_axial = dist_box; + quadrant = ImGetDirQuadrantFromDelta(dbx, dby); + } + else if (dcx != 0.0f || dcy != 0.0f) + { + // For overlapping boxes with different centers, use distance between centers + dax = dcx; + day = dcy; + dist_axial = dist_center; + quadrant = ImGetDirQuadrantFromDelta(dcx, dcy); + } + else + { + // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter) + quadrant = (g.LastItemData.ID < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right; + } + + const ImGuiDir move_dir = g.NavMoveDir; +#if IMGUI_DEBUG_NAV_SCORING + char buf[200]; + if (g.IO.KeyCtrl) // Hold CTRL to preview score in matching quadrant. CTRL+Arrow to rotate. + { + if (quadrant == move_dir) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center); + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 80)); + draw_list->AddRectFilled(cand.Min, cand.Min + CalcTextSize(buf), IM_COL32(255, 0, 0, 200)); + draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); + } + } + const bool debug_hovering = IsMouseHoveringRect(cand.Min, cand.Max); + const bool debug_tty = (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_Space)); + if (debug_hovering || debug_tty) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), + "d-box (%7.3f,%7.3f) -> %7.3f\nd-center (%7.3f,%7.3f) -> %7.3f\nd-axial (%7.3f,%7.3f) -> %7.3f\nnav %c, quadrant %c", + dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "-WENS"[move_dir+1], "-WENS"[quadrant+1]); + if (debug_hovering) + { + ImDrawList* draw_list = GetForegroundDrawList(window); + draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100)); + draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200)); + draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 200)); + draw_list->AddText(cand.Max, ~0U, buf); + } + if (debug_tty) { IMGUI_DEBUG_LOG_NAV("id 0x%08X\n%s\n", g.LastItemData.ID, buf); } + } +#endif + + // Is it in the quadrant we're interested in moving to? + bool new_best = false; + if (quadrant == move_dir) + { + // Does it beat the current best candidate? + if (dist_box < result->DistBox) + { + result->DistBox = dist_box; + result->DistCenter = dist_center; + return true; + } + if (dist_box == result->DistBox) + { + // Try using distance between center points to break ties + if (dist_center < result->DistCenter) + { + result->DistCenter = dist_center; + new_best = true; + } + else if (dist_center == result->DistCenter) + { + // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items + // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), + // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis. + if (((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance + new_best = true; + } + } + } + + // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches + // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness) + // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. + // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. + // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match + if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if ((move_dir == ImGuiDir_Left && dax < 0.0f) || (move_dir == ImGuiDir_Right && dax > 0.0f) || (move_dir == ImGuiDir_Up && day < 0.0f) || (move_dir == ImGuiDir_Down && day > 0.0f)) + { + result->DistAxial = dist_axial; + new_best = true; + } + + return new_best; +} + +static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + result->Window = window; + result->ID = g.LastItemData.ID; + result->FocusScopeId = g.CurrentFocusScopeId; + result->InFlags = g.LastItemData.InFlags; + result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); +} + +// True when current work location may be scrolled horizontally when moving left / right. +// This is generally always true UNLESS within a column. We don't have a vertical equivalent. +void ImGui::NavUpdateCurrentWindowIsScrollPushableX() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + window->DC.NavIsScrollPushableX = (g.CurrentTable == NULL && window->DC.CurrentColumns == NULL); +} + +// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above) +// This is called after LastItemData is set. +static void ImGui::NavProcessItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = g.LastItemData.ID; + const ImGuiItemFlags item_flags = g.LastItemData.InFlags; + + // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221) + if (window->DC.NavIsScrollPushableX == false) + { + g.LastItemData.NavRect.Min.x = ImClamp(g.LastItemData.NavRect.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x); + g.LastItemData.NavRect.Max.x = ImClamp(g.LastItemData.NavRect.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x); + } + const ImRect nav_bb = g.LastItemData.NavRect; + + // Process Init Request + if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0) + { + // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback + const bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0; + if (candidate_for_nav_default_focus || g.NavInitResult.ID == 0) + { + NavApplyItemToResult(&g.NavInitResult); + } + if (candidate_for_nav_default_focus) + { + g.NavInitRequest = false; // Found a match, clear request + NavUpdateAnyRequestFlag(); + } + } + + // Process Move Request (scoring for navigation) + // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRect + scoring from a rect wrapped according to current wrapping policy) + if (g.NavMoveScoringItems && (item_flags & ImGuiItemFlags_Disabled) == 0) + { + const bool is_tabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0; + if (is_tabbing) + { + NavProcessItemForTabbingRequest(id, item_flags, g.NavMoveFlags); + } + else if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) + { + ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther; + if (NavScoreItem(result)) + NavApplyItemToResult(result); + + // Features like PageUp/PageDown need to maintain a separate score for the visible set of items. + const float VISIBLE_RATIO = 0.70f; + if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb)) + if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO) + if (NavScoreItem(&g.NavMoveResultLocalVisible)) + NavApplyItemToResult(&g.NavMoveResultLocalVisible); + } + } + + // Update information for currently focused/navigated item + if (g.NavId == id) + { + if (g.NavWindow != window) + SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window. + g.NavLayer = window->DC.NavLayerCurrent; + g.NavFocusScopeId = g.CurrentFocusScopeId; + g.NavIdIsAlive = true; + window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position) + } +} + +// Handle "scoring" of an item for a tabbing/focusing request initiated by NavUpdateCreateTabbingRequest(). +// Note that SetKeyboardFocusHere() API calls are considered tabbing requests! +// - Case 1: no nav/active id: set result to first eligible item, stop storing. +// - Case 2: tab forward: on ref id set counter, on counter elapse store result +// - Case 3: tab forward wrap: set result to first eligible item (preemptively), on ref id set counter, on next frame if counter hasn't elapsed store result. // FIXME-TABBING: Could be done as a next-frame forwarded request +// - Case 4: tab backward: store all results, on ref id pick prev, stop storing +// - Case 5: tab backward wrap: store all results, on ref id if no result keep storing until last // FIXME-TABBING: Could be done as next-frame forwarded requested +void ImGui::NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags) +{ + ImGuiContext& g = *GImGui; + + if ((move_flags & ImGuiNavMoveFlags_FocusApi) == 0) + if (g.NavLayer != g.CurrentWindow->DC.NavLayerCurrent) + return; + + // - Can always land on an item when using API call. + // - Tabbing with _NavEnableKeyboard (space/enter/arrows): goes through every item. + // - Tabbing without _NavEnableKeyboard: goes through inputable items only. + bool can_stop; + if (move_flags & ImGuiNavMoveFlags_FocusApi) + can_stop = true; + else + can_stop = (item_flags & ImGuiItemFlags_NoTabStop) == 0 && ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) || (item_flags & ImGuiItemFlags_Inputable)); + + // Always store in NavMoveResultLocal (unlike directional request which uses NavMoveResultOther on sibling/flattened windows) + ImGuiNavItemData* result = &g.NavMoveResultLocal; + if (g.NavTabbingDir == +1) + { + // Tab Forward or SetKeyboardFocusHere() with >= 0 + if (can_stop && g.NavTabbingResultFirst.ID == 0) + NavApplyItemToResult(&g.NavTabbingResultFirst); + if (can_stop && g.NavTabbingCounter > 0 && --g.NavTabbingCounter == 0) + NavMoveRequestResolveWithLastItem(result); + else if (g.NavId == id) + g.NavTabbingCounter = 1; + } + else if (g.NavTabbingDir == -1) + { + // Tab Backward + if (g.NavId == id) + { + if (result->ID) + { + g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); + } + } + else if (can_stop) + { + // Keep applying until reaching NavId + NavApplyItemToResult(result); + } + } + else if (g.NavTabbingDir == 0) + { + if (can_stop && g.NavId == id) + NavMoveRequestResolveWithLastItem(result); + if (can_stop && g.NavTabbingResultFirst.ID == 0) // Tab init + NavApplyItemToResult(&g.NavTabbingResultFirst); + } +} + +bool ImGui::NavMoveRequestButNoResultYet() +{ + ImGuiContext& g = *GImGui; + return g.NavMoveScoringItems && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0; +} + +// FIXME: ScoringRect is not set +void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindow != NULL); + + if (move_flags & ImGuiNavMoveFlags_IsTabbing) + move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId; + + g.NavMoveSubmitted = g.NavMoveScoringItems = true; + g.NavMoveDir = move_dir; + g.NavMoveDirForDebug = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveFlags = move_flags; + g.NavMoveScrollFlags = scroll_flags; + g.NavMoveForwardToNextFrame = false; + g.NavMoveKeyMods = g.IO.KeyMods; + g.NavMoveResultLocal.Clear(); + g.NavMoveResultLocalVisible.Clear(); + g.NavMoveResultOther.Clear(); + g.NavTabbingCounter = 0; + g.NavTabbingResultFirst.Clear(); + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) +{ + ImGuiContext& g = *GImGui; + g.NavMoveScoringItems = false; // Ensure request doesn't need more processing + NavApplyItemToResult(result); + NavUpdateAnyRequestFlag(); +} + +void ImGui::NavMoveRequestCancel() +{ + ImGuiContext& g = *GImGui; + g.NavMoveSubmitted = g.NavMoveScoringItems = false; + NavUpdateAnyRequestFlag(); +} + +// Forward will reuse the move request again on the next frame (generally with modifications done to it) +void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavMoveForwardToNextFrame == false); + NavMoveRequestCancel(); + g.NavMoveForwardToNextFrame = true; + g.NavMoveDir = move_dir; + g.NavMoveClipDir = clip_dir; + g.NavMoveFlags = move_flags | ImGuiNavMoveFlags_Forwarded; + g.NavMoveScrollFlags = scroll_flags; +} + +// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire +// popup is assembled and in case of appended popups it is not clear which EndPopup() call is final. +void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wrap_flags) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT((wrap_flags & ImGuiNavMoveFlags_WrapMask_ ) != 0 && (wrap_flags & ~ImGuiNavMoveFlags_WrapMask_) == 0); // Call with _WrapX, _WrapY, _LoopX, _LoopY + + // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it: + // as NavEndFrame() will do the same test. It will end up calling NavUpdateCreateWrappingRequest(). + if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main) + g.NavMoveFlags = (g.NavMoveFlags & ~ImGuiNavMoveFlags_WrapMask_) | wrap_flags; +} + +// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). +// This way we could find the last focused window among our children. It would be much less confusing this way? +static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) +{ + ImGuiWindow* parent = nav_window; + while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + parent = parent->ParentWindow; + if (parent && parent != nav_window) + parent->NavLastChildNavWindow = nav_window; +} + +// Restore the last focused child. +// Call when we are expected to land on the Main Layer (0) after FocusWindow() +static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) + return window->NavLastChildNavWindow; + return window; +} + +void ImGui::NavRestoreLayer(ImGuiNavLayer layer) +{ + ImGuiContext& g = *GImGui; + if (layer == ImGuiNavLayer_Main) + { + ImGuiWindow* prev_nav_window = g.NavWindow; + g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); // FIXME-NAV: Should clear ongoing nav requests? + if (prev_nav_window) + IMGUI_DEBUG_LOG_FOCUS("[focus] NavRestoreLayer: from \"%s\" to SetNavWindow(\"%s\")\n", prev_nav_window->Name, g.NavWindow->Name); + } + ImGuiWindow* window = g.NavWindow; + if (window->NavLastIds[layer] != 0) + { + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + } + else + { + g.NavLayer = layer; + NavInitWindow(window, true); + } +} + +void ImGui::NavRestoreHighlightAfterMove() +{ + ImGuiContext& g = *GImGui; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; +} + +static inline void ImGui::NavUpdateAnyRequestFlag() +{ + ImGuiContext& g = *GImGui; + g.NavAnyRequest = g.NavMoveScoringItems || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL); + if (g.NavAnyRequest) + IM_ASSERT(g.NavWindow != NULL); +} + +// This needs to be called before we submit any widget (aka in or before Begin) +void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == g.NavWindow); + + if (window->Flags & ImGuiWindowFlags_NoNavInputs) + { + g.NavId = 0; + g.NavFocusScopeId = window->NavRootFocusScopeId; + return; + } + + bool init_for_nav = false; + if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit) + init_for_nav = true; + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer); + if (init_for_nav) + { + SetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect()); + g.NavInitRequest = true; + g.NavInitRequestFromMove = false; + g.NavInitResult.ID = 0; + NavUpdateAnyRequestFlag(); + } + else + { + g.NavId = window->NavLastIds[0]; + g.NavFocusScopeId = window->NavRootFocusScopeId; + } +} + +static ImVec2 ImGui::NavCalcPreferredRefPos() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window) + { + // Mouse (we need a fallback in case the mouse becomes invalid after being used) + // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard. + // In theory we could move that +1.0f offset in OpenPopupEx() + ImVec2 p = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : g.MouseLastValidPos; + return ImVec2(p.x + 1.0f, p.y); + } + else + { + // When navigation is active and mouse is disabled, pick a position around the bottom left of the currently navigated item + // Take account of upcoming scrolling (maybe set mouse pos should be done in EndFrame?) + ImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLayer]); + if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x != FLT_MAX || window->ScrollTarget.y != FLT_MAX)) + { + ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); + rect_rel.Translate(window->Scroll - next_scroll); + } + ImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); + ImGuiViewport* viewport = GetMainViewport(); + return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. + } +} + +float ImGui::GetNavTweakPressedAmount(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + float repeat_delay, repeat_rate; + GetTypematicRepeatRate(ImGuiInputFlags_RepeatRateNavTweak, &repeat_delay, &repeat_rate); + + ImGuiKey key_less, key_more; + if (g.NavInputSource == ImGuiInputSource_Gamepad) + { + key_less = (axis == ImGuiAxis_X) ? ImGuiKey_GamepadDpadLeft : ImGuiKey_GamepadDpadUp; + key_more = (axis == ImGuiAxis_X) ? ImGuiKey_GamepadDpadRight : ImGuiKey_GamepadDpadDown; + } + else + { + key_less = (axis == ImGuiAxis_X) ? ImGuiKey_LeftArrow : ImGuiKey_UpArrow; + key_more = (axis == ImGuiAxis_X) ? ImGuiKey_RightArrow : ImGuiKey_DownArrow; + } + float amount = (float)GetKeyPressedAmount(key_more, repeat_delay, repeat_rate) - (float)GetKeyPressedAmount(key_less, repeat_delay, repeat_rate); + if (amount != 0.0f && IsKeyDown(key_less) && IsKeyDown(key_more)) // Cancel when opposite directions are held, regardless of repeat phase + amount = 0.0f; + return amount; +} + +static void ImGui::NavUpdate() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + io.WantSetMousePos = false; + //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG_NAV("[nav] NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); + + // Set input source based on which keys are last pressed (as some features differs when used with Gamepad vs Keyboard) + // FIXME-NAV: Now that keys are separated maybe we can get rid of NavInputSource? + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const ImGuiKey nav_gamepad_keys_to_change_source[] = { ImGuiKey_GamepadFaceRight, ImGuiKey_GamepadFaceLeft, ImGuiKey_GamepadFaceUp, ImGuiKey_GamepadFaceDown, ImGuiKey_GamepadDpadRight, ImGuiKey_GamepadDpadLeft, ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadDpadDown }; + if (nav_gamepad_active) + for (ImGuiKey key : nav_gamepad_keys_to_change_source) + if (IsKeyDown(key)) + g.NavInputSource = ImGuiInputSource_Gamepad; + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + const ImGuiKey nav_keyboard_keys_to_change_source[] = { ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, ImGuiKey_RightArrow, ImGuiKey_LeftArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow }; + if (nav_keyboard_active) + for (ImGuiKey key : nav_keyboard_keys_to_change_source) + if (IsKeyDown(key)) + g.NavInputSource = ImGuiInputSource_Keyboard; + + // Process navigation init request (select first/default focus) + g.NavJustMovedToId = 0; + if (g.NavInitResult.ID != 0) + NavInitRequestApplyResult(); + g.NavInitRequest = false; + g.NavInitRequestFromMove = false; + g.NavInitResult.ID = 0; + + // Process navigation move request + if (g.NavMoveSubmitted) + NavMoveRequestApplyResult(); + g.NavTabbingCounter = 0; + g.NavMoveSubmitted = g.NavMoveScoringItems = false; + + // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) + bool set_mouse_pos = false; + if (g.NavMousePosDirty && g.NavIdIsAlive) + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) + set_mouse_pos = true; + g.NavMousePosDirty = false; + IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu); + + // Store our return window (for returning from Menu Layer to Main Layer) and clear it as soon as we step back in our own Layer 0 + if (g.NavWindow) + NavSaveLastChildNavWindowIntoParent(g.NavWindow); + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main) + g.NavWindow->NavLastChildNavWindow = NULL; + + // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) + NavUpdateWindowing(); + + // Set output flags for user application + io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); + io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); + + // Process NavCancel input (to close a popup, get back to parent, clear focus) + NavUpdateCancelRequest(); + + // Process manual activation request + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0; + g.NavActivateFlags = ImGuiActivateFlags_None; + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate)); + const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, false))); + const bool input_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Enter)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadInput)); + const bool input_pressed = input_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Enter, false)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadInput, false))); + if (g.ActiveId == 0 && activate_pressed) + { + g.NavActivateId = g.NavId; + g.NavActivateFlags = ImGuiActivateFlags_PreferTweak; + } + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && input_pressed) + { + g.NavActivateId = g.NavId; + g.NavActivateFlags = ImGuiActivateFlags_PreferInput; + } + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_down || input_down)) + g.NavActivateDownId = g.NavId; + if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && (activate_pressed || input_pressed)) + g.NavActivatePressedId = g.NavId; + } + if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + g.NavDisableHighlight = true; + if (g.NavActivateId != 0) + IM_ASSERT(g.NavActivateDownId == g.NavActivateId); + + // Process programmatic activation request + // FIXME-NAV: Those should eventually be queued (unlike focus they don't cancel each others) + if (g.NavNextActivateId != 0) + { + g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavNextActivateId; + g.NavActivateFlags = g.NavNextActivateFlags; + } + g.NavNextActivateId = 0; + + // Process move requests + NavUpdateCreateMoveRequest(); + if (g.NavMoveDir == ImGuiDir_None) + NavUpdateCreateTabbingRequest(); + NavUpdateAnyRequestFlag(); + g.NavIdIsAlive = false; + + // Scrolling + if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) + { + // *Fallback* manual-scroll with Nav directional keys when window has no navigable item + ImGuiWindow* window = g.NavWindow; + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + const ImGuiDir move_dir = g.NavMoveDir; + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None) + { + if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) + SetScrollX(window, ImFloor(window->Scroll.x + ((move_dir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed)); + if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) + SetScrollY(window, ImFloor(window->Scroll.y + ((move_dir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed)); + } + + // *Normal* Manual scroll with LStick + // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds. + if (nav_gamepad_active) + { + const ImVec2 scroll_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); + const float tweak_factor = IsKeyDown(ImGuiKey_NavGamepadTweakSlow) ? 1.0f / 10.0f : IsKeyDown(ImGuiKey_NavGamepadTweakFast) ? 10.0f : 1.0f; + if (scroll_dir.x != 0.0f && window->ScrollbarX) + SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed * tweak_factor)); + if (scroll_dir.y != 0.0f) + SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed * tweak_factor)); + } + } + + // Always prioritize mouse highlight if navigation is disabled + if (!nav_keyboard_active && !nav_gamepad_active) + { + g.NavDisableHighlight = true; + g.NavDisableMouseHover = set_mouse_pos = false; + } + + // Update mouse position if requested + // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied) + if (set_mouse_pos && (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + { + io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos(); + io.WantSetMousePos = true; + //IMGUI_DEBUG_LOG_IO("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); + } + + // [DEBUG] + g.NavScoringDebugCount = 0; +#if IMGUI_DEBUG_NAV_RECTS + if (ImGuiWindow* debug_window = g.NavWindow) + { + ImDrawList* draw_list = GetForegroundDrawList(debug_window); + int layer = g.NavLayer; /* for (int layer = 0; layer < 2; layer++)*/ { ImRect r = WindowRectRelToAbs(debug_window, debug_window->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 200, 0, 255)); } + //if (1) { ImU32 col = (!debug_window->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); } + } +#endif +} + +void ImGui::NavInitRequestApplyResult() +{ + // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void) + ImGuiContext& g = *GImGui; + if (!g.NavWindow) + return; + + ImGuiNavItemData* result = &g.NavInitResult; + if (g.NavId != result->ID) + { + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = 0; + } + + // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) + // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently. + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); + SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result + if (g.NavInitRequestFromMove) + NavRestoreHighlightAfterMove(); +} + +// Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position +static void NavBiasScoringRect(ImRect& r, ImVec2& preferred_pos_rel, ImGuiDir move_dir, ImGuiNavMoveFlags move_flags) +{ + // Bias initial rect + ImGuiContext& g = *GImGui; + const ImVec2 rel_to_abs_offset = g.NavWindow->DC.CursorStartPos; + + // Initialize bias on departure if we don't have any. So mouse-click + arrow will record bias. + // - We default to L/U bias, so moving down from a large source item into several columns will land on left-most column. + // - But each successful move sets new bias on one axis, only cleared when using mouse. + if ((move_flags & ImGuiNavMoveFlags_Forwarded) == 0) + { + if (preferred_pos_rel.x == FLT_MAX) + preferred_pos_rel.x = ImMin(r.Min.x + 1.0f, r.Max.x) - rel_to_abs_offset.x; + if (preferred_pos_rel.y == FLT_MAX) + preferred_pos_rel.y = r.GetCenter().y - rel_to_abs_offset.y; + } + + // Apply general bias on the other axis + if ((move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down) && preferred_pos_rel.x != FLT_MAX) + r.Min.x = r.Max.x = preferred_pos_rel.x + rel_to_abs_offset.x; + else if ((move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right) && preferred_pos_rel.y != FLT_MAX) + r.Min.y = r.Max.y = preferred_pos_rel.y + rel_to_abs_offset.y; +} + +void ImGui::NavUpdateCreateMoveRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiWindow* window = g.NavWindow; + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + + if (g.NavMoveForwardToNextFrame && window != NULL) + { + // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window) + // (preserve most state, which were already set by the NavMoveRequestForward() function) + IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None); + IM_ASSERT(g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded); + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir); + } + else + { + // Initiate directional inputs request + g.NavMoveDir = ImGuiDir_None; + g.NavMoveFlags = ImGuiNavMoveFlags_None; + g.NavMoveScrollFlags = ImGuiScrollFlags_None; + if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs)) + { + const ImGuiInputFlags repeat_mode = ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateNavMove; + if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadLeft, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_LeftArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Left; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadRight, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_RightArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Right; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadUp, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_UpArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Up; } + if (!IsActiveIdUsingNavDir(ImGuiDir_Down) && ((nav_gamepad_active && IsKeyPressed(ImGuiKey_GamepadDpadDown, ImGuiKeyOwner_None, repeat_mode)) || (nav_keyboard_active && IsKeyPressed(ImGuiKey_DownArrow, ImGuiKeyOwner_None, repeat_mode)))) { g.NavMoveDir = ImGuiDir_Down; } + } + g.NavMoveClipDir = g.NavMoveDir; + g.NavScoringNoClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + } + + // Update PageUp/PageDown/Home/End scroll + // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag? + float scoring_rect_offset_y = 0.0f; + if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active) + scoring_rect_offset_y = NavUpdatePageUpPageDown(); + if (scoring_rect_offset_y != 0.0f) + { + g.NavScoringNoClipRect = window->InnerRect; + g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y); + } + + // [DEBUG] Always send a request when holding CTRL. Hold CTRL + Arrow change the direction. +#if IMGUI_DEBUG_NAV_SCORING + //if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C)) + // g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); + if (io.KeyCtrl) + { + if (g.NavMoveDir == ImGuiDir_None) + g.NavMoveDir = g.NavMoveDirForDebug; + g.NavMoveClipDir = g.NavMoveDir; + g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; + } +#endif + + // Submit + g.NavMoveForwardToNextFrame = false; + if (g.NavMoveDir != ImGuiDir_None) + NavMoveRequestSubmit(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); + + // Moving with no reference triggers an init request (will be used as a fallback if the direction fails to find a match) + if (g.NavMoveSubmitted && g.NavId == 0) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); + g.NavInitRequest = g.NavInitRequestFromMove = true; + g.NavInitResult.ID = 0; + g.NavDisableHighlight = false; + } + + // When using gamepad, we project the reference nav bounding box into window visible area. + // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, + // since with gamepad all movements are relative (can't focus a visible object like we can with the mouse). + if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded)) + { + bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0; + bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0; + ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1))); + + // Take account of changing scroll to handle triggering a new move request on a scrolling frame. (#6171) + // Otherwise 'inner_rect_rel' would be off on the move result frame. + inner_rect_rel.Translate(CalcNextScrollFromScrollTargetAndClamp(window) - window->Scroll); + + if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer])) + { + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n"); + float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f); + float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item + inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX; + inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX; + inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX; + inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX; + window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel); + g.NavId = 0; + } + } + + // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) + ImRect scoring_rect; + if (window != NULL) + { + ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); + scoring_rect = WindowRectRelToAbs(window, nav_rect_rel); + scoring_rect.TranslateY(scoring_rect_offset_y); + if (g.NavMoveSubmitted) + NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags); + IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem(). + //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] + //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] + } + g.NavScoringRect = scoring_rect; + g.NavScoringNoClipRect.Add(scoring_rect); +} + +void ImGui::NavUpdateCreateTabbingRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + IM_ASSERT(g.NavMoveDir == ImGuiDir_None); + if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGuiWindowFlags_NoNavInputs)) + return; + + const bool tab_pressed = IsKeyPressed(ImGuiKey_Tab, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat) && !g.IO.KeyCtrl && !g.IO.KeyAlt; + if (!tab_pressed) + return; + + // Initiate tabbing request + // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!) + // Initially this was designed to use counters and modulo arithmetic, but that could not work with unsubmitted items (list clipper). Instead we use a strategy close to other move requests. + // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping. + const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + if (nav_keyboard_active) + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1; + else + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate; + ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; + ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down; + NavMoveRequestSubmit(ImGuiDir_None, clip_dir, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. + g.NavTabbingCounter = -1; +} + +// Apply result from previous frame navigation directional move request. Always called from NavUpdate() +void ImGui::NavMoveRequestApplyResult() +{ + ImGuiContext& g = *GImGui; +#if IMGUI_DEBUG_NAV_SCORING + if (g.NavMoveFlags & ImGuiNavMoveFlags_DebugNoResult) // [DEBUG] Scoring all items in NavWindow at all times + return; +#endif + + // Select which result to use + ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : (g.NavMoveResultOther.ID != 0) ? &g.NavMoveResultOther : NULL; + + // Tabbing forward wrap + if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && result == NULL) + if ((g.NavTabbingCounter == 1 || g.NavTabbingDir == 0) && g.NavTabbingResultFirst.ID) + result = &g.NavTabbingResultFirst; + + // In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) + const ImGuiAxis axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + if (result == NULL) + { + if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) + g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight; + if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); + NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis. + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); + return; + } + + // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page. + if (g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) + if (g.NavMoveResultLocalVisible.ID != 0 && g.NavMoveResultLocalVisible.ID != g.NavId) + result = &g.NavMoveResultLocalVisible; + + // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules. + if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) + if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter)) + result = &g.NavMoveResultOther; + IM_ASSERT(g.NavWindow && result->Window); + + // Scroll to keep newly navigated item fully into view. + if (g.NavLayer == ImGuiNavLayer_Main) + { + ImRect rect_abs = WindowRectRelToAbs(result->Window, result->RectRel); + ScrollToRectEx(result->Window, rect_abs, g.NavMoveScrollFlags); + + if (g.NavMoveFlags & ImGuiNavMoveFlags_ScrollToEdgeY) + { + // FIXME: Should remove this? Or make more precise: use ScrollToRectEx() with edge? + float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f; + SetScrollY(result->Window, scroll_target); + } + } + + if (g.NavWindow != result->Window) + { + IMGUI_DEBUG_LOG_FOCUS("[focus] NavMoveRequest: SetNavWindow(\"%s\")\n", result->Window->Name); + g.NavWindow = result->Window; + } + if (g.ActiveId != result->ID) + ClearActiveID(); + + // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId) + // PageUp/PageDown however sets always set NavJustMovedTo (vs Home/End which doesn't) mimicking Windows behavior. + if ((g.NavId != result->ID || (g.NavMoveFlags & ImGuiNavMoveFlags_IsPageMove)) && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSelect) == 0) + { + g.NavJustMovedToId = result->ID; + g.NavJustMovedToFocusScopeId = result->FocusScopeId; + g.NavJustMovedToKeyMods = g.NavMoveKeyMods; + } + + // Apply new NavID/Focus + IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); + ImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer]; + SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); + + // Restore last preferred position for current axis + // (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..) + if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) == 0) + { + preferred_scoring_pos_rel[axis] = result->RectRel.GetCenter()[axis]; + g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer] = preferred_scoring_pos_rel; + } + + // Tabbing: Activates Inputable, otherwise only Focus + if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->InFlags & ImGuiItemFlags_Inputable) == 0) + g.NavMoveFlags &= ~ImGuiNavMoveFlags_Activate; + + // Activate + if (g.NavMoveFlags & ImGuiNavMoveFlags_Activate) + { + g.NavNextActivateId = result->ID; + g.NavNextActivateFlags = ImGuiActivateFlags_None; + g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight; + if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) + g.NavNextActivateFlags |= ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState; + } + + // Enable nav highlight + if ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); +} + +// Process NavCancel input (to close a popup, get back to parent, clear focus) +// FIXME: In order to support e.g. Escape to clear a selection we'll need: +// - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it. +// - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept +static void ImGui::NavUpdateCancelRequest() +{ + ImGuiContext& g = *GImGui; + const bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + if (!(nav_keyboard_active && IsKeyPressed(ImGuiKey_Escape, ImGuiKeyOwner_None)) && !(nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, ImGuiKeyOwner_None))) + return; + + IMGUI_DEBUG_LOG_NAV("[nav] NavUpdateCancelRequest()\n"); + if (g.ActiveId != 0) + { + ClearActiveID(); + } + else if (g.NavLayer != ImGuiNavLayer_Main) + { + // Leave the "menu" layer + NavRestoreLayer(ImGuiNavLayer_Main); + NavRestoreHighlightAfterMove(); + } + else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow) + { + // Exit child window + ImGuiWindow* child_window = g.NavWindow; + ImGuiWindow* parent_window = g.NavWindow->ParentWindow; + IM_ASSERT(child_window->ChildId != 0); + ImRect child_rect = child_window->Rect(); + FocusWindow(parent_window); + SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect)); + NavRestoreHighlightAfterMove(); + } + else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) + { + // Close open popup/menu + ClosePopupToLevel(g.OpenPopupStack.Size - 1, true); + } + else + { + // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = 0; + } +} + +// Handle PageUp/PageDown/Home/End keys +// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request +// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use NavWindow rectangle for reference +// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid? +static float ImGui::NavUpdatePageUpPageDown() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL) + return 0.0f; + + const bool page_up_held = IsKeyDown(ImGuiKey_PageUp, ImGuiKeyOwner_None); + const bool page_down_held = IsKeyDown(ImGuiKey_PageDown, ImGuiKeyOwner_None); + const bool home_pressed = IsKeyPressed(ImGuiKey_Home, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat); + const bool end_pressed = IsKeyPressed(ImGuiKey_End, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat); + if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out + return 0.0f; + + if (g.NavLayer != ImGuiNavLayer_Main) + NavRestoreLayer(ImGuiNavLayer_Main); + + if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY) + { + // Fallback manual-scroll when window has no navigable item + if (IsKeyPressed(ImGuiKey_PageUp, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat)) + SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()); + else if (IsKeyPressed(ImGuiKey_PageDown, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat)) + SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()); + else if (home_pressed) + SetScrollY(window, 0.0f); + else if (end_pressed) + SetScrollY(window, window->ScrollMax.y); + } + else + { + ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + float nav_scoring_rect_offset_y = 0.0f; + if (IsKeyPressed(ImGuiKey_PageUp, true)) + { + nav_scoring_rect_offset_y = -page_offset_y; + g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Up; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet | ImGuiNavMoveFlags_IsPageMove; + } + else if (IsKeyPressed(ImGuiKey_PageDown, true)) + { + nav_scoring_rect_offset_y = +page_offset_y; + g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item) + g.NavMoveClipDir = ImGuiDir_Down; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet | ImGuiNavMoveFlags_IsPageMove; + } + else if (home_pressed) + { + // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y + // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav result. + // Preserve current horizontal position if we have any. + nav_rect_rel.Min.y = nav_rect_rel.Max.y = 0.0f; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Down; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY; + // FIXME-NAV: MoveClipDir left to _None, intentional? + } + else if (end_pressed) + { + nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ContentSize.y; + if (nav_rect_rel.IsInverted()) + nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f; + g.NavMoveDir = ImGuiDir_Up; + g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdgeY; + // FIXME-NAV: MoveClipDir left to _None, intentional? + } + return nav_scoring_rect_offset_y; + } + return 0.0f; +} + +static void ImGui::NavEndFrame() +{ + ImGuiContext& g = *GImGui; + + // Show CTRL+TAB list window + if (g.NavWindowingTarget != NULL) + NavUpdateWindowingOverlay(); + + // Perform wrap-around in menus + // FIXME-NAV: Wrap may need to apply a weight bias on the other axis. e.g. 4x4 grid with 2 last items missing on last item won't handle LoopY/WrapY correctly. + // FIXME-NAV: Wrap (not Loop) support could be handled by the scoring function and then WrapX would function without an extra frame. + if (g.NavWindow && NavMoveRequestButNoResultYet() && (g.NavMoveFlags & ImGuiNavMoveFlags_WrapMask_) && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + NavUpdateCreateWrappingRequest(); +} + +static void ImGui::NavUpdateCreateWrappingRequest() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.NavWindow; + + bool do_forward = false; + ImRect bb_rel = window->NavRectRel[g.NavLayer]; + ImGuiDir clip_dir = g.NavMoveDir; + + const ImGuiNavMoveFlags move_flags = g.NavMoveFlags; + //const ImGuiAxis move_axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row + clip_dir = ImGuiDir_Up; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) + { + bb_rel.Min.x = bb_rel.Max.x = -window->WindowPadding.x; + if (move_flags & ImGuiNavMoveFlags_WrapX) + { + bb_rel.TranslateY(+bb_rel.GetHeight()); // Next row + clip_dir = ImGuiDir_Down; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column + clip_dir = ImGuiDir_Left; + } + do_forward = true; + } + if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) + { + bb_rel.Min.y = bb_rel.Max.y = -window->WindowPadding.y; + if (move_flags & ImGuiNavMoveFlags_WrapY) + { + bb_rel.TranslateX(+bb_rel.GetWidth()); // Next column + clip_dir = ImGuiDir_Right; + } + do_forward = true; + } + if (!do_forward) + return; + window->NavRectRel[g.NavLayer] = bb_rel; + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavClearPreferredPosForAxis(ImGuiAxis_Y); + NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); +} + +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + int order = window->FocusOrder; + IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) + IM_ASSERT(g.WindowsFocusOrder[order] == window); + return order; +} + +static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) +{ + ImGuiContext& g = *GImGui; + for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir) + if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i])) + return g.WindowsFocusOrder[i]; + return NULL; +} + +static void NavUpdateWindowingHighlightWindow(int focus_change_dir) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget); + if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal) + return; + + const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget); + ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); + if (!window_target) + window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir); + if (window_target) // Don't reset windowing target if there's a single window in the list + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target; + g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); + } + g.NavWindowingToggleLayer = false; +} + +// Windowing management mode +// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) +// Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) +static void ImGui::NavUpdateWindowing() +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + ImGuiWindow* apply_focus_window = NULL; + bool apply_toggle_layer = false; + + ImGuiWindow* modal_window = GetTopMostPopupModal(); + bool allow_windowing = (modal_window == NULL); // FIXME: This prevent CTRL+TAB from being usable with windows that are inside the Begin-stack of that modal. + if (!allow_windowing) + g.NavWindowingTarget = NULL; + + // Fade out + if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) + { + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.DeltaTime * 10.0f, 0.0f); + if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) + g.NavWindowingTargetAnim = NULL; + } + + // Start CTRL+Tab or Square+L/R window selection + const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing"); + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; + const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); + const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways); + const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, 0, ImGuiInputFlags_None); + const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard! + if (start_windowing_with_gamepad || start_windowing_with_keyboard) + if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) + { + g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; + g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; + g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); + g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer + g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; + + // Register ownership of our mods. Using ImGuiInputFlags_RouteGlobalHigh in the Shortcut() calls instead would probably be correct but may have more side-effects. + if (keyboard_next_window || keyboard_prev_window) + SetKeyOwnersForKeyChord((g.ConfigNavWindowingKeyNext | g.ConfigNavWindowingKeyPrev) & ImGuiMod_Mask_, owner_id); + } + + // Gamepad update + g.NavWindowingTimer += io.DeltaTime; + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) + { + // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + // Select window to focus + const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1); + if (focus_change_dir != 0) + { + NavUpdateWindowingHighlightWindow(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } + + // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) + if (!IsKeyDown(ImGuiKey_NavGamepadMenu)) + { + g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. + if (g.NavWindowingToggleLayer && g.NavWindow) + apply_toggle_layer = true; + else if (!g.NavWindowingToggleLayer) + apply_focus_window = g.NavWindowingTarget; + g.NavWindowingTarget = NULL; + } + } + + // Keyboard: Focus + if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard) + { + // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise + ImGuiKeyChord shared_mods = ((g.ConfigNavWindowingKeyNext ? g.ConfigNavWindowingKeyNext : ImGuiMod_Mask_) & (g.ConfigNavWindowingKeyPrev ? g.ConfigNavWindowingKeyPrev : ImGuiMod_Mask_)) & ImGuiMod_Mask_; + IM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to "hold", otherwise Prev actions would keep cycling between two windows. + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f + if (keyboard_next_window || keyboard_prev_window) + NavUpdateWindowingHighlightWindow(keyboard_next_window ? -1 : +1); + else if ((io.KeyMods & shared_mods) != shared_mods) + apply_focus_window = g.NavWindowingTarget; + } + + // Keyboard: Press and Release ALT to toggle menu layer + // - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer. + // - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway. + if (nav_keyboard_active && IsKeyPressed(ImGuiMod_Alt, ImGuiKeyOwner_None)) + { + g.NavWindowingToggleLayer = true; + g.NavInputSource = ImGuiInputSource_Keyboard; + } + if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard) + { + // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370) + // We cancel toggling nav layer when other modifiers are pressed. (See #4439) + // We cancel toggling nav layer if an owner has claimed the key. + if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_None) == false) + g.NavWindowingToggleLayer = false; + + // Apply layer toggle on release + // Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss. + if (IsKeyReleased(ImGuiMod_Alt) && g.NavWindowingToggleLayer) + if (g.ActiveId == 0 || g.ActiveIdAllowOverlap) + if (IsMousePosValid(&io.MousePos) == IsMousePosValid(&io.MousePosPrev)) + apply_toggle_layer = true; + if (!IsKeyDown(ImGuiMod_Alt)) + g.NavWindowingToggleLayer = false; + } + + // Move window + if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove)) + { + ImVec2 nav_move_dir; + if (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift) + nav_move_dir = GetKeyMagnitude2d(ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow); + if (g.NavInputSource == ImGuiInputSource_Gamepad) + nav_move_dir = GetKeyMagnitude2d(ImGuiKey_GamepadLStickLeft, ImGuiKey_GamepadLStickRight, ImGuiKey_GamepadLStickUp, ImGuiKey_GamepadLStickDown); + if (nav_move_dir.x != 0.0f || nav_move_dir.y != 0.0f) + { + const float NAV_MOVE_SPEED = 800.0f; + const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + g.NavWindowingAccumDeltaPos += nav_move_dir * move_step; + g.NavDisableMouseHover = true; + ImVec2 accum_floored = ImFloor(g.NavWindowingAccumDeltaPos); + if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) + { + ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow; + SetWindowPos(moving_window, moving_window->Pos + accum_floored, ImGuiCond_Always); + g.NavWindowingAccumDeltaPos -= accum_floored; + } + } + } + + // Apply final focus + if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) + { + ClearActiveID(); + NavRestoreHighlightAfterMove(); + ClosePopupsOverWindow(apply_focus_window, false); + FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); + apply_focus_window = g.NavWindow; + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); + + // If the window has ONLY a menu layer (no main layer), select it directly + // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame, + // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since + // the target window as already been previewed once. + // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases, + // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask* + // won't be valid. + if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + } + if (apply_focus_window) + g.NavWindowingTarget = NULL; + + // Apply menu/layer toggle + if (apply_toggle_layer && g.NavWindow) + { + ClearActiveID(); + + // Move to parent menu if necessary + ImGuiWindow* new_nav_window = g.NavWindow; + while (new_nav_window->ParentWindow + && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 + && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 + && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) + new_nav_window = new_nav_window->ParentWindow; + if (new_nav_window != g.NavWindow) + { + ImGuiWindow* old_nav_window = g.NavWindow; + FocusWindow(new_nav_window); + new_nav_window->NavLastChildNavWindow = old_nav_window; + } + + // Toggle layer + const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main; + if (new_nav_layer != g.NavLayer) + { + // Reinitialize navigation when entering menu bar with the Alt key (FIXME: could be a properly of the layer?) + if (new_nav_layer == ImGuiNavLayer_Menu) + g.NavWindow->NavLastIds[new_nav_layer] = 0; + NavRestoreLayer(new_nav_layer); + NavRestoreHighlightAfterMove(); + } + } +} + +// Window has already passed the IsWindowNavFocusable() +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingPopup); + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingMainMenuBar); + return ImGui::LocalizeGetMsg(ImGuiLocKey_WindowingUntitled); +} + +// Overlay displayed when using CTRL+TAB. Called by EndFrame(). +void ImGui::NavUpdateWindowingOverlay() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.NavWindowingTarget != NULL); + + if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY) + return; + + if (g.NavWindowingListWindow == NULL) + g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); + const ImGuiViewport* viewport = GetMainViewport(); + SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); + Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) + { + ImGuiWindow* window = g.WindowsFocusOrder[n]; + IM_ASSERT(window != NULL); // Fix static analyzers + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); + } + End(); + PopStyleVar(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] DRAG AND DROP +//----------------------------------------------------------------------------- + +bool ImGui::IsDragDropActive() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive; +} + +void ImGui::ClearDragDrop() +{ + ImGuiContext& g = *GImGui; + g.DragDropActive = false; + g.DragDropPayload.Clear(); + g.DragDropAcceptFlags = ImGuiDragDropFlags_None; + g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0; + g.DragDropAcceptIdCurrRectSurface = FLT_MAX; + g.DragDropAcceptFrameCount = -1; + + g.DragDropPayloadBufHeap.clear(); + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); +} + +// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource() +// If the item has an identifier: +// - This assume/require the item to be activated (typically via ButtonBehavior). +// - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button. +// - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag. +// If the item has no identifier: +// - Currently always assume left mouse button. +bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button, + // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic). + ImGuiMouseButton mouse_button = ImGuiMouseButton_Left; + + bool source_drag_active = false; + ImGuiID source_id = 0; + ImGuiID source_parent_id = 0; + if (!(flags & ImGuiDragDropFlags_SourceExtern)) + { + source_id = g.LastItemData.ID; + if (source_id != 0) + { + // Common path: items with ID + if (g.ActiveId != source_id) + return false; + if (g.ActiveIdMouseButton != -1) + mouse_button = g.ActiveIdMouseButton; + if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) + return false; + g.ActiveIdAllowOverlap = false; + } + else + { + // Uncommon path: items without ID + if (g.IO.MouseDown[mouse_button] == false || window->SkipItems) + return false; + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window)) + return false; + + // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag. + if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) + { + IM_ASSERT(0); + return false; + } + + // Magic fallback to handle items with no assigned ID, e.g. Text(), Image() + // We build a throwaway ID based on current ID stack + relative AABB of items in window. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. + // Rely on keeping other window->LastItemXXX fields intact. + source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); + KeepAliveID(source_id); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags); + if (is_hovered && g.IO.MouseClicked[mouse_button]) + { + SetActiveID(source_id, window); + FocusWindow(window); + } + if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker. + g.ActiveIdAllowOverlap = is_hovered; + } + if (g.ActiveId != source_id) + return false; + source_parent_id = window->IDStack.back(); + source_drag_active = IsMouseDragging(mouse_button); + + // Disable navigation and key inputs while dragging + cancel existing request if any + SetActiveIdUsingAllKeyboardKeys(); + } + else + { + window = NULL; + source_id = ImHashStr("#SourceExtern"); + source_drag_active = true; + } + + if (source_drag_active) + { + if (!g.DragDropActive) + { + IM_ASSERT(source_id != 0); + ClearDragDrop(); + ImGuiPayload& payload = g.DragDropPayload; + payload.SourceId = source_id; + payload.SourceParentId = source_parent_id; + g.DragDropActive = true; + g.DragDropSourceFlags = flags; + g.DragDropMouseButton = mouse_button; + if (payload.SourceId == g.ActiveId) + g.ActiveIdNoClearOnFocusLoss = true; + } + g.DragDropSourceFrameCount = g.FrameCount; + g.DragDropWithinSource = true; + + if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + { + // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit) + // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents. + bool ret = BeginTooltip(); + IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame(). + IM_UNUSED(ret); + + if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) + SetWindowHiddendAndSkipItemsForCurrentFrame(g.CurrentWindow); + } + + if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern)) + g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect; + + return true; + } + return false; +} + +void ImGui::EndDragDropSource() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?"); + + if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + EndTooltip(); + + // Discard the drag if have not called SetDragDropPayload() + if (g.DragDropPayload.DataFrameCount == -1) + ClearDragDrop(); + g.DragDropWithinSource = false; +} + +// Use 'cond' to choose to submit payload on drag start or every frame +bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + ImGuiPayload& payload = g.DragDropPayload; + if (cond == 0) + cond = ImGuiCond_Always; + + IM_ASSERT(type != NULL); + IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long"); + IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0)); + IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); + IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() + + if (cond == ImGuiCond_Always || payload.DataFrameCount == -1) + { + // Copy payload + ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType)); + g.DragDropPayloadBufHeap.resize(0); + if (data_size > sizeof(g.DragDropPayloadBufLocal)) + { + // Store in heap + g.DragDropPayloadBufHeap.resize((int)data_size); + payload.Data = g.DragDropPayloadBufHeap.Data; + memcpy(payload.Data, data, data_size); + } + else if (data_size > 0) + { + // Store locally + memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal)); + payload.Data = g.DragDropPayloadBufLocal; + memcpy(payload.Data, data, data_size); + } + else + { + payload.Data = NULL; + } + payload.DataSize = (int)data_size; + } + payload.DataFrameCount = g.FrameCount; + + // Return whether the payload has been accepted + return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1); +} + +bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow) + return false; + IM_ASSERT(id != 0); + if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId)) + return false; + if (window->SkipItems) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = bb; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} + +// We don't use BeginDragDropTargetCustom() and duplicate its code because: +// 1) we use LastItemRectHoveredRect which handles items that push a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them. +// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can. +// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case) +bool ImGui::BeginDragDropTarget() +{ + ImGuiContext& g = *GImGui; + if (!g.DragDropActive) + return false; + + ImGuiWindow* window = g.CurrentWindow; + if (!(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect)) + return false; + ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow; + if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow || window->SkipItems) + return false; + + const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect; + ImGuiID id = g.LastItemData.ID; + if (id == 0) + { + id = window->GetIDFromRectangle(display_rect); + KeepAliveID(id); + } + if (g.DragDropPayload.SourceId == id) + return false; + + IM_ASSERT(g.DragDropWithinTarget == false); + g.DragDropTargetRect = display_rect; + g.DragDropTargetId = id; + g.DragDropWithinTarget = true; + return true; +} + +bool ImGui::IsDragDropPayloadBeingAccepted() +{ + ImGuiContext& g = *GImGui; + return g.DragDropActive && g.DragDropAcceptIdPrev != 0; +} + +const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiPayload& payload = g.DragDropPayload; + IM_ASSERT(g.DragDropActive); // Not called between BeginDragDropTarget() and EndDragDropTarget() ? + IM_ASSERT(payload.DataFrameCount != -1); // Forgot to call EndDragDropTarget() ? + if (type != NULL && !payload.IsDataType(type)) + return NULL; + + // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints. + // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function! + const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId); + ImRect r = g.DragDropTargetRect; + float r_surface = r.GetWidth() * r.GetHeight(); + if (r_surface > g.DragDropAcceptIdCurrRectSurface) + return NULL; + + g.DragDropAcceptFlags = flags; + g.DragDropAcceptIdCurr = g.DragDropTargetId; + g.DragDropAcceptIdCurrRectSurface = r_surface; + //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: accept\n", g.DragDropTargetId); + + // Render default drop visuals + payload.Preview = was_accepted_previously; + flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame) + if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview) + window->DrawList->AddRect(r.Min - ImVec2(3.5f,3.5f), r.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); + + g.DragDropAcceptFrameCount = g.FrameCount; + payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased() + if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery)) + return NULL; + + //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: return payload\n", g.DragDropTargetId); + return &payload; +} + +// FIXME-DRAGDROP: Settle on a proper default visuals for drop target. +void ImGui::RenderDragDropTargetRect(const ImRect& bb) +{ + GetWindowDrawList()->AddRect(bb.Min - ImVec2(3.5f, 3.5f), bb.Max + ImVec2(3.5f, 3.5f), GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); +} + +const ImGuiPayload* ImGui::GetDragDropPayload() +{ + ImGuiContext& g = *GImGui; + return (g.DragDropActive && g.DragDropPayload.DataFrameCount != -1) ? &g.DragDropPayload : NULL; +} + +void ImGui::EndDragDropTarget() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.DragDropActive); + IM_ASSERT(g.DragDropWithinTarget); + g.DragDropWithinTarget = false; + + // Clear drag and drop state payload right after delivery + if (g.DragDropPayload.Delivery) + ClearDragDrop(); +} + +//----------------------------------------------------------------------------- +// [SECTION] LOGGING/CAPTURING +//----------------------------------------------------------------------------- +// All text output from the interface can be captured into tty/file/clipboard. +// By default, tree nodes are automatically opened during logging. +//----------------------------------------------------------------------------- + +// Pass text data straight to log (without being displayed) +static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args) +{ + if (g.LogFile) + { + g.LogBuffer.Buf.resize(0); + g.LogBuffer.appendfv(fmt, args); + ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile); + } + else + { + g.LogBuffer.appendfv(fmt, args); + } +} + +void ImGui::LogText(const char* fmt, ...) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + va_list args; + va_start(args, fmt); + LogTextV(g, fmt, args); + va_end(args); +} + +void ImGui::LogTextV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogTextV(g, fmt, args); +} + +// Internal version that takes a position to decide on newline placement and pad items according to their depth. +// We split text into individual lines to add current tree level padding +// FIXME: This code is a little complicated perhaps, considering simplifying the whole system. +void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const char* prefix = g.LogNextPrefix; + const char* suffix = g.LogNextSuffix; + g.LogNextPrefix = g.LogNextSuffix = NULL; + + if (!text_end) + text_end = FindRenderedTextEnd(text, text_end); + + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1); + if (ref_pos) + g.LogLinePosY = ref_pos->y; + if (log_new_line) + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } + + if (prefix) + LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here. + + // Re-adjust padding if we have popped out of our starting depth + if (g.LogDepthRef > window->DC.TreeDepth) + g.LogDepthRef = window->DC.TreeDepth; + const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); + + const char* text_remaining = text; + for (;;) + { + // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry. + // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured. + const char* line_start = text_remaining; + const char* line_end = ImStreolRange(line_start, text_end); + const bool is_last_line = (line_end == text_end); + if (line_start != line_end || !is_last_line) + { + const int line_length = (int)(line_end - line_start); + const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1; + LogText("%*s%.*s", indentation, "", line_length, line_start); + g.LogLineFirstItem = false; + if (*line_end == '\n') + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } + } + if (is_last_line) + break; + text_remaining = line_end + 1; + } + + if (suffix) + LogRenderedText(ref_pos, suffix, suffix + strlen(suffix)); +} + +// Start logging/capturing text output +void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.LogEnabled == false); + IM_ASSERT(g.LogFile == NULL); + IM_ASSERT(g.LogBuffer.empty()); + g.LogEnabled = true; + g.LogType = type; + g.LogNextPrefix = g.LogNextSuffix = NULL; + g.LogDepthRef = window->DC.TreeDepth; + g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); + g.LogLinePosY = FLT_MAX; + g.LogLineFirstItem = true; +} + +// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText) +void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix) +{ + ImGuiContext& g = *GImGui; + g.LogNextPrefix = prefix; + g.LogNextSuffix = suffix; +} + +void ImGui::LogToTTY(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + IM_UNUSED(auto_open_depth); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + LogBegin(ImGuiLogType_TTY, auto_open_depth); + g.LogFile = stdout; +#endif +} + +// Start logging/capturing text output to given file +void ImGui::LogToFile(int auto_open_depth, const char* filename) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + + // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still + // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE. + // By opening the file in binary mode "ab" we have consistent output everywhere. + if (!filename) + filename = g.IO.LogFilename; + if (!filename || !filename[0]) + return; + ImFileHandle f = ImFileOpen(filename, "ab"); + if (!f) + { + IM_ASSERT(0); + return; + } + + LogBegin(ImGuiLogType_File, auto_open_depth); + g.LogFile = f; +} + +// Start logging/capturing text output to clipboard +void ImGui::LogToClipboard(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Clipboard, auto_open_depth); +} + +void ImGui::LogToBuffer(int auto_open_depth) +{ + ImGuiContext& g = *GImGui; + if (g.LogEnabled) + return; + LogBegin(ImGuiLogType_Buffer, auto_open_depth); +} + +void ImGui::LogFinish() +{ + ImGuiContext& g = *GImGui; + if (!g.LogEnabled) + return; + + LogText(IM_NEWLINE); + switch (g.LogType) + { + case ImGuiLogType_TTY: +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + fflush(g.LogFile); +#endif + break; + case ImGuiLogType_File: + ImFileClose(g.LogFile); + break; + case ImGuiLogType_Buffer: + break; + case ImGuiLogType_Clipboard: + if (!g.LogBuffer.empty()) + SetClipboardText(g.LogBuffer.begin()); + break; + case ImGuiLogType_None: + IM_ASSERT(0); + break; + } + + g.LogEnabled = false; + g.LogType = ImGuiLogType_None; + g.LogFile = NULL; + g.LogBuffer.clear(); +} + +// Helper to display logging buttons +// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!) +void ImGui::LogButtons() +{ + ImGuiContext& g = *GImGui; + + PushID("LogButtons"); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + const bool log_to_tty = Button("Log To TTY"); SameLine(); +#else + const bool log_to_tty = false; +#endif + const bool log_to_file = Button("Log To File"); SameLine(); + const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); + PushTabStop(false); + SetNextItemWidth(80.0f); + SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL); + PopTabStop(); + PopID(); + + // Start logging at the end of the function so that the buttons don't appear in the log + if (log_to_tty) + LogToTTY(); + if (log_to_file) + LogToFile(); + if (log_to_clipboard) + LogToClipboard(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] SETTINGS +//----------------------------------------------------------------------------- +// - UpdateSettings() [Internal] +// - MarkIniSettingsDirty() [Internal] +// - FindSettingsHandler() [Internal] +// - ClearIniSettings() [Internal] +// - LoadIniSettingsFromDisk() +// - LoadIniSettingsFromMemory() +// - SaveIniSettingsToDisk() +// - SaveIniSettingsToMemory() +//----------------------------------------------------------------------------- +// - CreateNewWindowSettings() [Internal] +// - FindWindowSettingsByID() [Internal] +// - FindWindowSettingsByWindow() [Internal] +// - ClearWindowSettings() [Internal] +// - WindowSettingsHandler_***() [Internal] +//----------------------------------------------------------------------------- + +// Called by NewFrame() +void ImGui::UpdateSettings() +{ + // Load settings on first frame (if not explicitly loaded manually before) + ImGuiContext& g = *GImGui; + if (!g.SettingsLoaded) + { + IM_ASSERT(g.SettingsWindows.empty()); + if (g.IO.IniFilename) + LoadIniSettingsFromDisk(g.IO.IniFilename); + g.SettingsLoaded = true; + } + + // Save settings (with a delay after the last modification, so we don't spam disk too much) + if (g.SettingsDirtyTimer > 0.0f) + { + g.SettingsDirtyTimer -= g.IO.DeltaTime; + if (g.SettingsDirtyTimer <= 0.0f) + { + if (g.IO.IniFilename != NULL) + SaveIniSettingsToDisk(g.IO.IniFilename); + else + g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves. + g.SettingsDirtyTimer = 0.0f; + } + } +} + +void ImGui::MarkIniSettingsDirty() +{ + ImGuiContext& g = *GImGui; + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) + if (g.SettingsDirtyTimer <= 0.0f) + g.SettingsDirtyTimer = g.IO.IniSavingRate; +} + +void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(FindSettingsHandler(handler->TypeName) == NULL); + g.SettingsHandlers.push_back(*handler); +} + +void ImGui::RemoveSettingsHandler(const char* type_name) +{ + ImGuiContext& g = *GImGui; + if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name)) + g.SettingsHandlers.erase(handler); +} + +ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) +{ + ImGuiContext& g = *GImGui; + const ImGuiID type_hash = ImHashStr(type_name); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].TypeHash == type_hash) + return &g.SettingsHandlers[handler_n]; + return NULL; +} + +// Clear all settings (windows, tables, docking etc.) +void ImGui::ClearIniSettings() +{ + ImGuiContext& g = *GImGui; + g.SettingsIniData.clear(); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ClearAllFn) + g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); +} + +void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) +{ + size_t file_data_size = 0; + char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size); + if (!file_data) + return; + if (file_data_size > 0) + LoadIniSettingsFromMemory(file_data, (size_t)file_data_size); + IM_FREE(file_data); +} + +// Zero-tolerance, no error reporting, cheap .ini parsing +// Set ini_size==0 to let us use strlen(ini_data). Do not call this function with a 0 if your buffer is actually empty! +void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Initialized); + //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()"); + //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0); + + // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). + // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. + if (ini_size == 0) + ini_size = strlen(ini_data); + g.SettingsIniData.Buf.resize((int)ini_size + 1); + char* const buf = g.SettingsIniData.Buf.Data; + char* const buf_end = buf + ini_size; + memcpy(buf, ini_data, ini_size); + buf_end[0] = 0; + + // Call pre-read handlers + // Some types will clear their data (e.g. dock information) some types will allow merge/override (window) + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ReadInitFn) + g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); + + void* entry_data = NULL; + ImGuiSettingsHandler* entry_handler = NULL; + + char* line_end = NULL; + for (char* line = buf; line < buf_end; line = line_end + 1) + { + // Skip new lines markers, then find end of the line + while (*line == '\n' || *line == '\r') + line++; + line_end = line; + while (line_end < buf_end && *line_end != '\n' && *line_end != '\r') + line_end++; + line_end[0] = 0; + if (line[0] == ';') + continue; + if (line[0] == '[' && line_end > line && line_end[-1] == ']') + { + // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code. + line_end[-1] = 0; + const char* name_end = line_end - 1; + const char* type_start = line + 1; + char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']'); + const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL; + if (!type_end || !name_start) + continue; + *type_end = 0; // Overwrite first ']' + name_start++; // Skip second '[' + entry_handler = FindSettingsHandler(type_start); + entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL; + } + else if (entry_handler != NULL && entry_data != NULL) + { + // Let type handler parse the line + entry_handler->ReadLineFn(&g, entry_handler, entry_data, line); + } + } + g.SettingsLoaded = true; + + // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary) + memcpy(buf, ini_data, ini_size); + + // Call post-read handlers + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + if (g.SettingsHandlers[handler_n].ApplyAllFn) + g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); +} + +void ImGui::SaveIniSettingsToDisk(const char* ini_filename) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + if (!ini_filename) + return; + + size_t ini_data_size = 0; + const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); + ImFileHandle f = ImFileOpen(ini_filename, "wt"); + if (!f) + return; + ImFileWrite(ini_data, sizeof(char), ini_data_size, f); + ImFileClose(f); +} + +// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer +const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) +{ + ImGuiContext& g = *GImGui; + g.SettingsDirtyTimer = 0.0f; + g.SettingsIniData.Buf.resize(0); + g.SettingsIniData.Buf.push_back(0); + for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) + { + ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n]; + handler->WriteAllFn(&g, handler, &g.SettingsIniData); + } + if (out_size) + *out_size = (size_t)g.SettingsIniData.size(); + return g.SettingsIniData.c_str(); +} + +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + + if (g.IO.ConfigDebugIniSettings == false) + { + // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + // Preserve the full string when ConfigDebugVerboseIniSettings is set to make .ini inspection easier. + if (const char* p = strstr(name, "###")) + name = p; + } + const size_t name_len = strlen(name); + + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + + return settings; +} + +// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names. +// This is called once per window .ini entry + once per newly instantiated window. +ImGuiWindowSettings* ImGui::FindWindowSettingsByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id && !settings->WantDelete) + return settings; + return NULL; +} + +// This is faster if you are holding on a Window already as we don't need to perform a search. +ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (window->SettingsOffset != -1) + return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); + return FindWindowSettingsByID(window->ID); +} + +// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more. +void ImGui::ClearWindowSettings(const char* name) +{ + //IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name); + ImGuiWindow* window = FindWindowByName(name); + if (window != NULL) + { + window->Flags |= ImGuiWindowFlags_NoSavedSettings; + InitOrLoadWindowSettings(window, NULL); + } + if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name))) + settings->WantDelete = true; +} + +static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + g.Windows[i]->SettingsOffset = -1; + g.SettingsWindows.clear(); +} + +static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiID id = ImHashStr(name); + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByID(id); + if (settings) + *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry + else + settings = ImGui::CreateNewWindowSettings(name); + settings->ID = id; + settings->WantApply = true; + return (void*)settings; +} + +static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; + int x, y; + int i; + if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) { settings->Pos = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) { settings->Size = ImVec2ih((short)x, (short)y); } + else if (sscanf(line, "Collapsed=%d", &i) == 1) { settings->Collapsed = (i != 0); } +} + +// Apply to existing windows (if any) +static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->WantApply) + { + if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID)) + ApplyWindowSettings(window, settings); + settings->WantApply = false; + } +} + +static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + // Gather data from windows that were active during this session + // (if a window wasn't opened in this session we preserve its settings) + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Flags & ImGuiWindowFlags_NoSavedSettings) + continue; + + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window); + if (!settings) + { + settings = ImGui::CreateNewWindowSettings(window->Name); + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + } + IM_ASSERT(settings->ID == window->ID); + settings->Pos = ImVec2ih(window->Pos); + settings->Size = ImVec2ih(window->SizeFull); + + settings->Collapsed = window->Collapsed; + settings->WantDelete = false; + } + + // Write to text buffer + buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + { + if (settings->WantDelete) + continue; + const char* settings_name = settings->GetName(); + buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); + buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); + buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y); + buf->appendf("Collapsed=%d\n", settings->Collapsed); + buf->append("\n"); + } +} + + +//----------------------------------------------------------------------------- +// [SECTION] LOCALIZATION +//----------------------------------------------------------------------------- + +void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count) +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < count; n++) + g.LocalizationTable[entries[n].Key] = entries[n].Text; +} + + +//----------------------------------------------------------------------------- +// [SECTION] VIEWPORTS, PLATFORM WINDOWS +//----------------------------------------------------------------------------- +// - GetMainViewport() +// - SetWindowViewport() [Internal] +// - UpdateViewportsNewFrame() [Internal] +// (this section is more complete in the 'docking' branch) +//----------------------------------------------------------------------------- + +ImGuiViewport* ImGui::GetMainViewport() +{ + ImGuiContext& g = *GImGui; + return g.Viewports[0]; +} + +void ImGui::SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport) +{ + window->Viewport = viewport; +} + +// Update viewports and monitor infos +static void ImGui::UpdateViewportsNewFrame() +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.Viewports.Size == 1); + + // Update main viewport with current platform position. + // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent. + ImGuiViewportP* main_viewport = g.Viewports[0]; + main_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp; + main_viewport->Pos = ImVec2(0.0f, 0.0f); + main_viewport->Size = g.IO.DisplaySize; + + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + + // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again. + viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin; + viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; + viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); + viewport->UpdateWorkRect(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] DOCKING +//----------------------------------------------------------------------------- + +// (this section is filled in the 'docking' branch) + + +//----------------------------------------------------------------------------- +// [SECTION] PLATFORM DEPENDENT HELPERS +//----------------------------------------------------------------------------- + +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) + +#ifdef _MSC_VER +#pragma comment(lib, "user32") +#pragma comment(lib, "kernel32") +#endif + +// Win32 clipboard implementation +// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +{ + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + g.ClipboardHandlerData.clear(); + if (!::OpenClipboard(NULL)) + return NULL; + HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return NULL; + } + if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle)) + { + int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL); + g.ClipboardHandlerData.resize(buf_len); + ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL); + } + ::GlobalUnlock(wbuf_handle); + ::CloseClipboard(); + return g.ClipboardHandlerData.Data; +} + +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!::OpenClipboard(NULL)) + return; + const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); + HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR)); + if (wbuf_handle == NULL) + { + ::CloseClipboard(); + return; + } + WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle); + ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length); + ::GlobalUnlock(wbuf_handle); + ::EmptyClipboard(); + if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL) + ::GlobalFree(wbuf_handle); + ::CloseClipboard(); +} + +#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) + +#include // Use old API to avoid need for separate .mm file +static PasteboardRef main_clipboard = 0; + +// OSX clipboard implementation +// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) +{ + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardClear(main_clipboard); + CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); + if (cf_data) + { + PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); + CFRelease(cf_data); + } +} + +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +{ + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + if (!main_clipboard) + PasteboardCreate(kPasteboardClipboard, &main_clipboard); + PasteboardSynchronize(main_clipboard); + + ItemCount item_count = 0; + PasteboardGetItemCount(main_clipboard, &item_count); + for (ItemCount i = 0; i < item_count; i++) + { + PasteboardItemID item_id = 0; + PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id); + CFArrayRef flavor_type_array = 0; + PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array); + for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++) + { + CFDataRef cf_data; + if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr) + { + g.ClipboardHandlerData.clear(); + int length = (int)CFDataGetLength(cf_data); + g.ClipboardHandlerData.resize(length + 1); + CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data); + g.ClipboardHandlerData[length] = 0; + CFRelease(cf_data); + return g.ClipboardHandlerData.Data; + } + } + } + return NULL; +} + +#else + +// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) +{ + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); +} + +static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text) +{ + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; + g.ClipboardHandlerData.clear(); + const char* text_end = text + strlen(text); + g.ClipboardHandlerData.resize((int)(text_end - text) + 1); + memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text)); + g.ClipboardHandlerData[(int)(text_end - text)] = 0; +} + +#endif + +// Win32 API IME support (for Asian languages, etc.) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) + +#include +#ifdef _MSC_VER +#pragma comment(lib, "imm32") +#endif + +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data) +{ + // Notify OS Input Method Editor of text input position + HWND hwnd = (HWND)viewport->PlatformHandleRaw; + if (hwnd == 0) + return; + + //::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); + if (HIMC himc = ::ImmGetContext(hwnd)) + { + COMPOSITIONFORM composition_form = {}; + composition_form.ptCurrentPos.x = (LONG)data->InputPos.x; + composition_form.ptCurrentPos.y = (LONG)data->InputPos.y; + composition_form.dwStyle = CFS_FORCE_POSITION; + ::ImmSetCompositionWindow(himc, &composition_form); + CANDIDATEFORM candidate_form = {}; + candidate_form.dwStyle = CFS_CANDIDATEPOS; + candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x; + candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y; + ::ImmSetCandidateWindow(himc, &candidate_form); + ::ImmReleaseContext(hwnd, himc); + } +} + +#else + +static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeData*) {} + +#endif + +//----------------------------------------------------------------------------- +// [SECTION] METRICS/DEBUGGER WINDOW +//----------------------------------------------------------------------------- +// - RenderViewportThumbnail() [Internal] +// - RenderViewportsThumbnails() [Internal] +// - DebugTextEncoding() +// - MetricsHelpMarker() [Internal] +// - ShowFontAtlas() [Internal] +// - ShowMetricsWindow() +// - DebugNodeColumns() [Internal] +// - DebugNodeDrawList() [Internal] +// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal] +// - DebugNodeFont() [Internal] +// - DebugNodeFontGlyph() [Internal] +// - DebugNodeStorage() [Internal] +// - DebugNodeTabBar() [Internal] +// - DebugNodeViewport() [Internal] +// - DebugNodeWindow() [Internal] +// - DebugNodeWindowSettings() [Internal] +// - DebugNodeWindowsList() [Internal] +// - DebugNodeWindowsListByBeginStackParent() [Internal] +//----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + +void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 scale = bb.GetSize() / viewport->Size; + ImVec2 off = bb.Min - viewport->Pos * scale; + float alpha_mul = 1.0f; + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f)); + for (int i = 0; i != g.Windows.Size; i++) + { + ImGuiWindow* thumb_window = g.Windows[i]; + if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow)) + continue; + + ImRect thumb_r = thumb_window->Rect(); + ImRect title_r = thumb_window->TitleBarRect(); + thumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off + thumb_r.Max * scale)); + title_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off + ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height + thumb_r.ClipWithFull(bb); + title_r.ClipWithFull(bb); + const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); + window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul)); + window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul)); + window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); + window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name)); + } + draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul)); +} + +static void RenderViewportsThumbnails() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports. + float SCALE = 1.0f / 8.0f; + ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + for (int n = 0; n < g.Viewports.Size; n++) + bb_full.Add(g.Viewports[n]->GetMainRect()); + ImVec2 p = window->DC.CursorPos; + ImVec2 off = p - bb_full.Min * SCALE; + for (int n = 0; n < g.Viewports.Size; n++) + { + ImGuiViewportP* viewport = g.Viewports[n]; + ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE); + ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb); + } + ImGui::Dummy(bb_full.GetSize() * SCALE); +} + +// Draw an arbitrary US keyboard layout to visualize translated keys +void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list) +{ + const ImVec2 key_size = ImVec2(35.0f, 35.0f); + const float key_rounding = 3.0f; + const ImVec2 key_face_size = ImVec2(25.0f, 25.0f); + const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f); + const float key_face_rounding = 2.0f; + const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f); + const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f); + const float key_row_offset = 9.0f; + + ImVec2 board_min = GetCursorScreenPos(); + ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f); + ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y); + + struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; }; + const KeyLayoutData keys_to_display[] = + { + { 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R }, + { 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F }, + { 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V } + }; + + // Elements rendered manually via ImDrawList API are not clipped automatically. + // While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view. + Dummy(board_max - board_min); + if (!IsItemVisible()) + return; + draw_list->PushClipRect(board_min, board_max, true); + for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++) + { + const KeyLayoutData* key_data = &keys_to_display[n]; + ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y); + ImVec2 key_max = key_min + key_size; + draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding); + draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding); + ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y); + ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y); + draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f); + draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding); + ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y); + draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label); + if (IsKeyDown(key_data->Key)) + draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding); + } + draw_list->PopClipRect(); +} + +// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct. +void ImGui::DebugTextEncoding(const char* str) +{ + Text("Text: \"%s\"", str); + if (!BeginTable("##DebugTextEncoding", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable)) + return; + TableSetupColumn("Offset"); + TableSetupColumn("UTF-8"); + TableSetupColumn("Glyph"); + TableSetupColumn("Codepoint"); + TableHeadersRow(); + for (const char* p = str; *p != 0; ) + { + unsigned int c; + const int c_utf8_len = ImTextCharFromUtf8(&c, p, NULL); + TableNextColumn(); + Text("%d", (int)(p - str)); + TableNextColumn(); + for (int byte_index = 0; byte_index < c_utf8_len; byte_index++) + { + if (byte_index > 0) + SameLine(); + Text("0x%02X", (int)(unsigned char)p[byte_index]); + } + TableNextColumn(); + if (GetFont()->FindGlyphNoFallback((ImWchar)c)) + TextUnformatted(p, p + c_utf8_len); + else + TextUnformatted((c == IM_UNICODE_CODEPOINT_INVALID) ? "[invalid]" : "[missing]"); + TableNextColumn(); + Text("U+%04X", (int)c); + p += c_utf8_len; + } + EndTable(); +} + +// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. +static void MetricsHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::BeginItemTooltip()) + { + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +// [DEBUG] List fonts in a font atlas and display its texture +void ImGui::ShowFontAtlas(ImFontAtlas* atlas) +{ + for (int i = 0; i < atlas->Fonts.Size; i++) + { + ImFont* font = atlas->Fonts[i]; + PushID(font); + DebugNodeFont(font); + PopID(); + } + if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + { + ImGuiContext& g = *GImGui; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons + ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + ImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border); + Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); + TreePop(); + } +} + +void ImGui::ShowMetricsWindow(bool* p_open) +{ + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + if (cfg->ShowDebugLog) + ShowDebugLogWindow(&cfg->ShowDebugLog); + if (cfg->ShowStackTool) + ShowStackToolWindow(&cfg->ShowStackTool); + + if (!Begin("Dear ImGui Metrics/Debugger", p_open) || GetCurrentWindow()->BeginCount > 1) + { + End(); + return; + } + + // Basic info + Text("Dear ImGui %s", GetVersion()); + Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); + Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations); + //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; } + + Separator(); + + // Debugging enums + enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type + const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" }; + enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type + const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" }; + if (cfg->ShowWindowsRectsType < 0) + cfg->ShowWindowsRectsType = WRT_WorkRect; + if (cfg->ShowTablesRectsType < 0) + cfg->ShowTablesRectsType = TRT_WorkRect; + + struct Funcs + { + static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n) + { + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance + if (rect_type == TRT_OuterRect) { return table->OuterRect; } + else if (rect_type == TRT_InnerRect) { return table->InnerRect; } + else if (rect_type == TRT_WorkRect) { return table->WorkRect; } + else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; } + else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; } + else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; } + else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); } + else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); } + else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; } + else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate + else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } + else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight); } + else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFrozenHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); } + IM_ASSERT(0); + return ImRect(); + } + + static ImRect GetWindowRect(ImGuiWindow* window, int rect_type) + { + if (rect_type == WRT_OuterRect) { return window->Rect(); } + else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; } + else if (rect_type == WRT_InnerRect) { return window->InnerRect; } + else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; } + else if (rect_type == WRT_WorkRect) { return window->WorkRect; } + else if (rect_type == WRT_Content) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); } + else if (rect_type == WRT_ContentIdeal) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); } + else if (rect_type == WRT_ContentRegionRect) { return window->ContentRegionRect; } + IM_ASSERT(0); + return ImRect(); + } + }; + + // Tools + if (TreeNode("Tools")) + { + bool show_encoding_viewer = TreeNode("UTF-8 Encoding viewer"); + SameLine(); + MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct."); + if (show_encoding_viewer) + { + static char buf[100] = ""; + SetNextItemWidth(-FLT_MIN); + InputText("##Text", buf, IM_ARRAYSIZE(buf)); + if (buf[0] != 0) + DebugTextEncoding(buf); + TreePop(); + } + + // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. + if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive) + DebugStartItemPicker(); + SameLine(); + MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); + + // Stack Tool is your best friend! + Checkbox("Show Debug Log", &cfg->ShowDebugLog); + SameLine(); + MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code."); + + // Stack Tool is your best friend! + Checkbox("Show Stack Tool", &cfg->ShowStackTool); + SameLine(); + MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code."); + + Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder); + Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); + SameLine(); + SetNextItemWidth(GetFontSize() * 12); + cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count); + if (cfg->ShowWindowsRects && g.NavWindow != NULL) + { + BulletText("'%s':", g.NavWindow->Name); + Indent(); + for (int rect_n = 0; rect_n < WRT_Count; rect_n++) + { + ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n); + Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]); + } + Unindent(); + } + + Checkbox("Show tables rectangles", &cfg->ShowTablesRects); + SameLine(); + SetNextItemWidth(GetFontSize() * 12); + cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count); + if (cfg->ShowTablesRects && g.NavWindow != NULL) + { + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) + { + ImGuiTable* table = g.Tables.TryGetMapData(table_n); + if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow)) + continue; + + BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + Indent(); + char buf[128]; + for (int rect_n = 0; rect_n < TRT_Count; rect_n++) + { + if (rect_n >= TRT_ColumnsRect) + { + if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect) + continue; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImRect r = Funcs::GetTableRect(table, rect_n, column_n); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]); + Selectable(buf); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + } + } + else + { + ImRect r = Funcs::GetTableRect(table, rect_n, -1); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), trt_rects_names[rect_n]); + Selectable(buf); + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f); + } + } + Unindent(); + } + } + + Checkbox("Debug Begin/BeginChild return value", &io.ConfigDebugBeginReturnValueLoop); + SameLine(); + MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running."); + + TreePop(); + } + + // Windows + if (TreeNode("Windows", "Windows (%d)", g.Windows.Size)) + { + //SetNextItemOpen(true, ImGuiCond_Once); + DebugNodeWindowsList(&g.Windows, "By display order"); + DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)"); + if (TreeNode("By submission order (begin stack)")) + { + // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship! + ImVector& temp_buffer = g.WindowsTempSortBuffer; + temp_buffer.resize(0); + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount) + temp_buffer.push_back(g.Windows[i]); + struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } }; + ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder); + DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL); + TreePop(); + } + + TreePop(); + } + + // DrawLists + int drawlist_count = 0; + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + drawlist_count += g.Viewports[viewport_i]->DrawDataP.CmdLists.Size; + if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) + { + Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh); + Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes); + for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) + { + ImGuiViewportP* viewport = g.Viewports[viewport_i]; + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList"); + } + TreePop(); + } + + // Viewports + if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size)) + { + Indent(GetTreeNodeToLabelSpacing()); + RenderViewportsThumbnails(); + Unindent(GetTreeNodeToLabelSpacing()); + for (int i = 0; i < g.Viewports.Size; i++) + DebugNodeViewport(g.Viewports[i]); + TreePop(); + } + + // Details for Popups + if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) + { + for (int i = 0; i < g.OpenPopupStack.Size; i++) + { + // As it's difficult to interact with tree nodes while popups are open, we display everything inline. + const ImGuiPopupData* popup_data = &g.OpenPopupStack[i]; + ImGuiWindow* window = popup_data->Window; + BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'", + popup_data->PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "", + popup_data->BackupNavWindow ? popup_data->BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL"); + } + TreePop(); + } + + // Details for TabBars + if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount())) + { + for (int n = 0; n < g.TabBars.GetMapSize(); n++) + if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n)) + { + PushID(tab_bar); + DebugNodeTabBar(tab_bar, "TabBar"); + PopID(); + } + TreePop(); + } + + // Details for Tables + if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount())) + { + for (int n = 0; n < g.Tables.GetMapSize(); n++) + if (ImGuiTable* table = g.Tables.TryGetMapData(n)) + DebugNodeTable(table); + TreePop(); + } + + // Details for Fonts + ImFontAtlas* atlas = g.IO.Fonts; + if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size)) + { + ShowFontAtlas(atlas); + TreePop(); + } + + // Details for InputText + if (TreeNode("InputText")) + { + DebugNodeInputTextState(&g.InputTextState); + TreePop(); + } + + // Details for Docking +#ifdef IMGUI_HAS_DOCK + if (TreeNode("Docking")) + { + TreePop(); + } +#endif // #ifdef IMGUI_HAS_DOCK + + // Settings + if (TreeNode("Settings")) + { + if (SmallButton("Clear")) + ClearIniSettings(); + SameLine(); + if (SmallButton("Save to memory")) + SaveIniSettingsToMemory(); + SameLine(); + if (SmallButton("Save to disk")) + SaveIniSettingsToDisk(g.IO.IniFilename); + SameLine(); + if (g.IO.IniFilename) + Text("\"%s\"", g.IO.IniFilename); + else + TextUnformatted(""); + Checkbox("io.ConfigDebugIniSettings", &io.ConfigDebugIniSettings); + Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); + if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) + { + for (int n = 0; n < g.SettingsHandlers.Size; n++) + BulletText("\"%s\"", g.SettingsHandlers[n].TypeName); + TreePop(); + } + if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) + { + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + DebugNodeWindowSettings(settings); + TreePop(); + } + + if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) + { + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + DebugNodeTableSettings(settings); + TreePop(); + } + +#ifdef IMGUI_HAS_DOCK +#endif // #ifdef IMGUI_HAS_DOCK + + if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size())) + { + InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiInputTextFlags_ReadOnly); + TreePop(); + } + TreePop(); + } + + if (TreeNode("Inputs")) + { + Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); + { + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. + // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. + Indent(); +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } } +#endif + Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } + Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); + Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. + DebugRenderKeyboardPreview(GetWindowDrawList()); + Unindent(); + } + + Text("MOUSE STATE"); + { + Indent(); + if (IsMousePosValid()) + Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y); + else + Text("Mouse pos: "); + Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); + int count = IM_ARRAYSIZE(io.MouseDown); + Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); } + Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); } + Text("Mouse wheel: %.1f", io.MouseWheel); + Text("MouseStationaryTimer: %.2f", g.MouseStationaryTimer); + Text("Mouse source: %s", GetMouseSourceName(io.MouseSource)); + Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused + Unindent(); + } + + Text("MOUSE WHEELING"); + { + Indent(); + Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL"); + Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer); + Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : ""); + Unindent(); + } + + Text("KEY OWNERS"); + { + Indent(); + if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) + { + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); + if (owner_data->OwnerCurr == ImGuiKeyOwner_None) + continue; + Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr, + owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : ""); + DebugLocateItemOnHover(owner_data->OwnerCurr); + } + EndListBox(); + } + Unindent(); + } + Text("SHORTCUT ROUTING"); + { + Indent(); + if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6))) + { + for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) + { + ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable; + for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; ) + { + char key_chord_name[64]; + ImGuiKeyRoutingData* routing_data = &rt->Entries[idx]; + GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name)); + Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr); + DebugLocateItemOnHover(routing_data->RoutingCurr); + idx = routing_data->NextEntryIndex; + } + } + EndListBox(); + } + Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); + Unindent(); + } + TreePop(); + } + + if (TreeNode("Internal state")) + { + Text("WINDOWING"); + Indent(); + Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); + Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : "NULL"); + Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); + Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL"); + Unindent(); + + Text("ITEMS"); + Indent(); + Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource)); + DebugLocateItemOnHover(g.ActiveId); + Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); + Text("ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: %X", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask); + Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame + Text("HoverItemDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverItemDelayId, g.HoverItemDelayTimer, g.HoverItemDelayClearTimer); + Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); + DebugLocateItemOnHover(g.DragDropPayload.SourceId); + Unindent(); + + Text("NAV,FOCUS"); + Indent(); + Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); + Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); + DebugLocateItemOnHover(g.NavId); + Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource)); + Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); + Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId); + Text("NavActivateFlags: %04X", g.NavActivateFlags); + Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); + Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); + Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL"); + Unindent(); + + TreePop(); + } + + // Overlay: Display windows Rectangles and Begin Order + if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder) + { + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + if (!window->WasActive) + continue; + ImDrawList* draw_list = GetForegroundDrawList(window); + if (cfg->ShowWindowsRects) + { + ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + if (cfg->ShowWindowsBeginOrder && !(window->Flags & ImGuiWindowFlags_ChildWindow)) + { + char buf[32]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); + float font_size = GetFontSize(); + draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); + } + } + } + + // Overlay: Display Tables Rectangles + if (cfg->ShowTablesRects) + { + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) + { + ImGuiTable* table = g.Tables.TryGetMapData(table_n); + if (table == NULL || table->LastFrameActive < g.FrameCount - 1) + continue; + ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow); + if (cfg->ShowTablesRectsType >= TRT_ColumnsRect) + { + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n); + ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255); + float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f; + draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness); + } + } + else + { + ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1); + draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255)); + } + } + } + +#ifdef IMGUI_HAS_DOCK + // Overlay: Display Docking info + if (show_docking_nodes && g.IO.KeyCtrl) + { + } +#endif // #ifdef IMGUI_HAS_DOCK + + End(); +} + +// [DEBUG] Display contents of Columns +void ImGui::DebugNodeColumns(ImGuiOldColumns* columns) +{ + if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) + return; + BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); + for (int column_n = 0; column_n < columns->Columns.Size; column_n++) + BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); + TreePop(); +} + +// [DEBUG] Display contents of ImDrawList +void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(viewport); // Used in docking branch + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + int cmd_count = draw_list->CmdBuffer.Size; + if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL) + cmd_count--; + bool node_open = TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, cmd_count); + if (draw_list == GetWindowDrawList()) + { + SameLine(); + TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered) + if (node_open) + TreePop(); + return; + } + + ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list + if (window && IsItemHovered() && fg_draw_list) + fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!node_open) + return; + + if (window && !window->WasActive) + TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!"); + + for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++) + { + if (pcmd->UserCallback) + { + BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); + continue; + } + + char buf[300]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", + pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId, + pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); + bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf); + if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes); + if (!pcmd_node_open) + continue; + + // Calculate approximate coverage area (touched pixel count) + // This will be in pixels squared as long there's no post-scaling happening to the renderer output. + const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; + const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset; + float total_area = 0.0f; + for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; ) + { + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_n++) + triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos; + total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]); + } + + // Display vertex information summary. Hover to get all triangles drawn in wire-frame + ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area); + Selectable(buf); + if (IsItemHovered() && fg_draw_list) + DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false); + + // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. + ImGuiListClipper clipper; + clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. + while (clipper.Step()) + for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++) + { + char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf); + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_i++) + { + const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i]; + triangle[n] = v.pos; + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "Vert:" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + } + + Selectable(buf, false); + if (fg_draw_list && IsItemHovered()) + { + ImDrawListFlags backup_flags = fg_draw_list->Flags; + fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); + fg_draw_list->Flags = backup_flags; + } + } + TreePop(); + } + TreePop(); +} + +// [DEBUG] Display mesh/aabb of a ImDrawCmd +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb) +{ + IM_ASSERT(show_mesh || show_aabb); + + // Draw wire-frame version of all triangles + ImRect clip_rect = draw_cmd->ClipRect; + ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); + ImDrawListFlags backup_flags = out_draw_list->Flags; + out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; ) + { + ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list + ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset; + + ImVec2 triangle[3]; + for (int n = 0; n < 3; n++, idx_n++) + vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos)); + if (show_mesh) + out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles + } + // Draw bounding boxes + if (show_aabb) + { + out_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU + out_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles + } + out_draw_list->Flags = backup_flags; +} + +// [DEBUG] Display details for a single font, called by ShowStyleEditor(). +void ImGui::DebugNodeFont(ImFont* font) +{ + bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", + font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + SameLine(); + if (SmallButton("Set as default")) + GetIO().FontDefault = font; + if (!opened) + return; + + // Display preview text + PushFont(font); + Text("The quick brown fox jumps over the lazy dog"); + PopFont(); + + // Display details + SetNextItemWidth(GetFontSize() * 8); + DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); + SameLine(); MetricsHelpMarker( + "Note than the default embedded font is NOT meant to be scaled.\n\n" + "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " + "You may oversample them to get some flexibility with scaling. " + "You can also render at multiple sizes and select which one to use at runtime.\n\n" + "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); + Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + char c_str[5]; + Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); + Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); + const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface); + Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); + for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) + if (font->ConfigData) + if (const ImFontConfig* cfg = &font->ConfigData[config_i]) + BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", + config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + + // Display all glyphs of the fonts in separate pages of 256 characters + if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + { + ImDrawList* draw_list = GetWindowDrawList(); + const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); + const float cell_size = font->FontSize * 1; + const float cell_spacing = GetStyle().ItemSpacing.y; + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + { + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) + { + base += 4096 - 256; + continue; + } + + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (font->FindGlyphNoFallback((ImWchar)(base + n))) + count++; + if (count <= 0) + continue; + if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + continue; + + // Draw a 16x16 grid of glyphs + ImVec2 base_pos = GetCursorScreenPos(); + for (unsigned int n = 0; n < 256; n++) + { + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (!glyph) + continue; + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + { + DebugNodeFontGlyph(font, glyph); + EndTooltip(); + } + } + Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + TreePop(); + } + TreePop(); + } + TreePop(); +} + +void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph) +{ + Text("Codepoint: U+%04X", glyph->Codepoint); + Separator(); + Text("Visible: %d", glyph->Visible); + Text("AdvanceX: %.1f", glyph->AdvanceX); + Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); + Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); +} + +// [DEBUG] Display contents of ImGuiStorage +void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label) +{ + if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) + return; + for (int n = 0; n < storage->Data.Size; n++) + { + const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n]; + BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. + } + TreePop(); +} + +// [DEBUG] Display contents of ImGuiTabBar +void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label) +{ + // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings. + char buf[256]; + char* p = buf; + const char* buf_end = buf + IM_ARRAYSIZE(buf); + const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2); + p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s {", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*"); + for (int tab_n = 0; tab_n < ImMin(tab_bar->Tabs.Size, 3); tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + p += ImFormatString(p, buf_end - p, "%s'%s'", tab_n > 0 ? ", " : "", TabBarGetTabName(tab_bar, tab)); + } + p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } "); + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(label, "%s", buf); + if (!is_active) { PopStyleColor(); } + if (is_active && IsItemHovered()) + { + ImDrawList* draw_list = GetForegroundDrawList(); + draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255)); + draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255)); + } + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + PushID(tab); + if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2); + if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine(); + Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f", + tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, TabBarGetTabName(tab_bar, tab), tab->Offset, tab->Width, tab->ContentWidth); + PopID(); + } + TreePop(); + } +} + +void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) +{ + SetNextItemOpen(true, ImGuiCond_Once); + if (TreeNode("viewport0", "Viewport #%d", 0)) + { + ImGuiWindowFlags flags = viewport->Flags; + BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f", + viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, + viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y); + BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags, + (flags & ImGuiViewportFlags_IsPlatformWindow) ? " IsPlatformWindow" : "", + (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "", + (flags & ImGuiViewportFlags_OwnedByApp) ? " OwnedByApp" : ""); + for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++) + DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList"); + TreePop(); + } +} + +void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) +{ + if (window == NULL) + { + BulletText("%s: NULL", label); + return; + } + + ImGuiContext& g = *GImGui; + const bool is_active = window->WasActive; + ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None; + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PopStyleColor(); } + if (IsItemHovered() && is_active) + GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255)); + if (!open) + return; + + if (window->MemoryCompacted) + TextDisabled("Note: some memory buffers have been compacted/freed."); + + ImGuiWindowFlags flags = window->Flags; + DebugNodeDrawList(window, window->Viewport, window->DrawList, "DrawList"); + BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y); + BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags, + (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", + (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", + (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); + BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); + BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); + BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems); + for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) + { + ImRect r = window->NavRectRel[layer]; + if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y) + BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]); + else + BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); + DebugLocateItemOnHover(window->NavLastIds[layer]); + } + const ImVec2* pr = window->NavPreferredScoringPosRel; + for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) + BulletText("NavPreferredScoringPosRel[%d] = {%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater. + BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); + if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); } + if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); } + if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); } + if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) + { + for (int n = 0; n < window->ColumnsStorage.Size; n++) + DebugNodeColumns(&window->ColumnsStorage[n]); + TreePop(); + } + DebugNodeStorage(&window->StateStorage, "Storage"); + TreePop(); +} + +void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) +{ + if (settings->WantDelete) + BeginDisabled(); + Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", + settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); + if (settings->WantDelete) + EndDisabled(); +} + +void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) +{ + if (!TreeNode(label, "%s (%d)", label, windows->Size)) + return; + for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back + { + PushID((*windows)[i]); + DebugNodeWindow((*windows)[i], "Window"); + PopID(); + } + TreePop(); +} + +// FIXME-OPT: This is technically suboptimal, but it is simpler this way. +void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack) +{ + for (int i = 0; i < windows_size; i++) + { + ImGuiWindow* window = windows[i]; + if (window->ParentWindowInBeginStack != parent_in_begin_stack) + continue; + char buf[20]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext); + //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name); + DebugNodeWindow(window, buf); + Indent(); + DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window); + Unindent(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] DEBUG LOG WINDOW +//----------------------------------------------------------------------------- + +void ImGui::DebugLog(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + DebugLogV(fmt, args); + va_end(args); +} + +void ImGui::DebugLogV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + const int old_size = g.DebugLogBuf.size(); + g.DebugLogBuf.appendf("[%05d] ", g.FrameCount); + g.DebugLogBuf.appendfv(fmt, args); + if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY) + IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size); + g.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size()); +} + +void ImGui::ShowDebugLogWindow(bool* p_open) +{ + ImGuiContext& g = *GImGui; + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver); + if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1) + { + End(); + return; + } + + CheckboxFlags("All", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_); + SameLine(); CheckboxFlags("ActiveId", &g.DebugLogFlags, ImGuiDebugLogFlags_EventActiveId); + SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus); + SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup); + SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav); + SameLine(); if (CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper)) { g.DebugLogClipperAutoDisableFrames = 2; } if (IsItemHovered()) SetTooltip("Clipper log auto-disabled after 2 frames"); + //SameLine(); CheckboxFlags("Selection", &g.DebugLogFlags, ImGuiDebugLogFlags_EventSelection); + SameLine(); CheckboxFlags("IO", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO); + + if (SmallButton("Clear")) + { + g.DebugLogBuf.clear(); + g.DebugLogIndex.clear(); + } + SameLine(); + if (SmallButton("Copy")) + SetClipboardText(g.DebugLogBuf.c_str()); + BeginChild("##log", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + + ImGuiListClipper clipper; + clipper.Begin(g.DebugLogIndex.size()); + while (clipper.Step()) + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no); + const char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no); + TextUnformatted(line_begin, line_end); + ImRect text_rect = g.LastItemData.Rect; + if (IsItemHovered()) + for (const char* p = line_begin; p <= line_end - 10; p++) + { + ImGuiID id = 0; + if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) + continue; + ImVec2 p0 = CalcTextSize(line_begin, p); + ImVec2 p1 = CalcTextSize(p, p + 10); + g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y)); + if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true)) + DebugLocateItemOnHover(id); + p += 10; + } + } + if (GetScrollY() >= GetScrollMaxY()) + SetScrollHereY(1.0f); + EndChild(); + + End(); +} + +//----------------------------------------------------------------------------- +// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) +//----------------------------------------------------------------------------- + +static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green + +void ImGui::DebugLocateItem(ImGuiID target_id) +{ + ImGuiContext& g = *GImGui; + g.DebugLocateId = target_id; + g.DebugLocateFrames = 2; +} + +void ImGui::DebugLocateItemOnHover(ImGuiID target_id) +{ + if (target_id == 0 || !IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenBlockedByPopup)) + return; + ImGuiContext& g = *GImGui; + DebugLocateItem(target_id); + GetForegroundDrawList(g.CurrentWindow)->AddRect(g.LastItemData.Rect.Min - ImVec2(3.0f, 3.0f), g.LastItemData.Rect.Max + ImVec2(3.0f, 3.0f), DEBUG_LOCATE_ITEM_COLOR); +} + +void ImGui::DebugLocateItemResolveWithLastItem() +{ + ImGuiContext& g = *GImGui; + ImGuiLastItemData item_data = g.LastItemData; + g.DebugLocateId = 0; + ImDrawList* draw_list = GetForegroundDrawList(g.CurrentWindow); + ImRect r = item_data.Rect; + r.Expand(3.0f); + ImVec2 p1 = g.IO.MousePos; + ImVec2 p2 = ImVec2((p1.x < r.Min.x) ? r.Min.x : (p1.x > r.Max.x) ? r.Max.x : p1.x, (p1.y < r.Min.y) ? r.Min.y : (p1.y > r.Max.y) ? r.Max.y : p1.y); + draw_list->AddRect(r.Min, r.Max, DEBUG_LOCATE_ITEM_COLOR); + draw_list->AddLine(p1, p2, DEBUG_LOCATE_ITEM_COLOR); +} + +// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. +void ImGui::UpdateDebugToolItemPicker() +{ + ImGuiContext& g = *GImGui; + g.DebugItemPickerBreakId = 0; + if (!g.DebugItemPickerActive) + return; + + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + SetMouseCursor(ImGuiMouseCursor_Hand); + if (IsKeyPressed(ImGuiKey_Escape)) + g.DebugItemPickerActive = false; + const bool change_mapping = g.IO.KeyMods == (ImGuiMod_Ctrl | ImGuiMod_Shift); + if (!change_mapping && IsMouseClicked(g.DebugItemPickerMouseButton) && hovered_id) + { + g.DebugItemPickerBreakId = hovered_id; + g.DebugItemPickerActive = false; + } + for (int mouse_button = 0; mouse_button < 3; mouse_button++) + if (change_mapping && IsMouseClicked(mouse_button)) + g.DebugItemPickerMouseButton = (ImU8)mouse_button; + SetNextWindowBgAlpha(0.70f); + if (!BeginTooltip()) + return; + Text("HoveredId: 0x%08X", hovered_id); + Text("Press ESC to abort picking."); + const char* mouse_button_names[] = { "Left", "Right", "Middle" }; + if (change_mapping) + Text("Remap w/ Ctrl+Shift: click anywhere to select new mouse button."); + else + TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click %s Button to break in debugger! (remap w/ Ctrl+Shift)", mouse_button_names[g.DebugItemPickerMouseButton]); + EndTooltip(); +} + +// [DEBUG] Stack Tool: update queries. Called by NewFrame() +void ImGui::UpdateDebugToolStackQueries() +{ + ImGuiContext& g = *GImGui; + ImGuiStackTool* tool = &g.DebugStackTool; + + // Clear hook when stack tool is not visible + g.DebugHookIdInfo = 0; + if (g.FrameCount != tool->LastActiveFrame + 1) + return; + + // Update queries. The steps are: -1: query Stack, >= 0: query each stack item + // We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time + const ImGuiID query_id = g.HoveredIdPreviousFrame ? g.HoveredIdPreviousFrame : g.ActiveId; + if (tool->QueryId != query_id) + { + tool->QueryId = query_id; + tool->StackLevel = -1; + tool->Results.resize(0); + } + if (query_id == 0) + return; + + // Advance to next stack level when we got our result, or after 2 frames (in case we never get a result) + int stack_level = tool->StackLevel; + if (stack_level >= 0 && stack_level < tool->Results.Size) + if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2) + tool->StackLevel++; + + // Update hook + stack_level = tool->StackLevel; + if (stack_level == -1) + g.DebugHookIdInfo = query_id; + if (stack_level >= 0 && stack_level < tool->Results.Size) + { + g.DebugHookIdInfo = tool->Results[stack_level].ID; + tool->Results[stack_level].QueryFrameCount++; + } +} + +// [DEBUG] Stack tool: hooks called by GetID() family functions +void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStackTool* tool = &g.DebugStackTool; + + // Step 0: stack query + // This assumes that the ID was computed with the current ID stack, which tends to be the case for our widget. + if (tool->StackLevel == -1) + { + tool->StackLevel++; + tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo()); + for (int n = 0; n < window->IDStack.Size + 1; n++) + tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id; + return; + } + + // Step 1+: query for individual level + IM_ASSERT(tool->StackLevel >= 0); + if (tool->StackLevel != window->IDStack.Size) + return; + ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel]; + IM_ASSERT(info->ID == id && info->QueryFrameCount > 0); + + switch (data_type) + { + case ImGuiDataType_S32: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id); + break; + case ImGuiDataType_String: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id), (const char*)data_id); + break; + case ImGuiDataType_Pointer: + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id); + break; + case ImGuiDataType_ID: + if (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one. + return; + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id); + break; + default: + IM_ASSERT(0); + } + info->QuerySuccess = true; + info->DataType = data_type; +} + +static int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size) +{ + ImGuiStackLevelInfo* info = &tool->Results[n]; + ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL; + if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked) + return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", window->Name); + if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id) + return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", info->Desc); + if (tool->StackLevel < tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers. + return (*buf = 0); +#ifdef IMGUI_ENABLE_TEST_ENGINE + if (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID)) // Source: ImGuiTestEngine's ItemInfo() + return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", label); +#endif + return ImFormatString(buf, buf_size, "???"); +} + +// Stack Tool: Display UI +void ImGui::ShowStackToolWindow(bool* p_open) +{ + ImGuiContext& g = *GImGui; + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) + SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); + if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) + { + End(); + return; + } + + // Display hovered/active status + ImGuiStackTool* tool = &g.DebugStackTool; + const ImGuiID hovered_id = g.HoveredIdPreviousFrame; + const ImGuiID active_id = g.ActiveId; +#ifdef IMGUI_ENABLE_TEST_ENGINE + Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : ""); +#else + Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id); +#endif + SameLine(); + MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details."); + + // CTRL+C to copy path + const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime; + Checkbox("Ctrl+C: copy path to clipboard", &tool->CopyToClipboardOnCtrlC); + SameLine(); + TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*"); + if (tool->CopyToClipboardOnCtrlC && IsKeyDown(ImGuiMod_Ctrl) && IsKeyPressed(ImGuiKey_C)) + { + tool->CopyToClipboardLastTime = (float)g.Time; + char* p = g.TempBuffer.Data; + char* p_end = p + g.TempBuffer.Size; + for (int stack_n = 0; stack_n < tool->Results.Size && p + 3 < p_end; stack_n++) + { + *p++ = '/'; + char level_desc[256]; + StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc)); + for (int n = 0; level_desc[n] && p + 2 < p_end; n++) + { + if (level_desc[n] == '/') + *p++ = '\\'; + *p++ = level_desc[n]; + } + } + *p = '\0'; + SetClipboardText(g.TempBuffer.Data); + } + + // Display decorated stack + tool->LastActiveFrame = g.FrameCount; + if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders)) + { + const float id_width = CalcTextSize("0xDDDDDDDD").x; + TableSetupColumn("Seed", ImGuiTableColumnFlags_WidthFixed, id_width); + TableSetupColumn("PushID", ImGuiTableColumnFlags_WidthStretch); + TableSetupColumn("Result", ImGuiTableColumnFlags_WidthFixed, id_width); + TableHeadersRow(); + for (int n = 0; n < tool->Results.Size; n++) + { + ImGuiStackLevelInfo* info = &tool->Results[n]; + TableNextColumn(); + Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0); + TableNextColumn(); + StackToolFormatLevelInfo(tool, n, true, g.TempBuffer.Data, g.TempBuffer.Size); + TextUnformatted(g.TempBuffer.Data); + TableNextColumn(); + Text("0x%08X", info->ID); + if (n == tool->Results.Size - 1) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_Header)); + } + EndTable(); + } + End(); +} + +#else + +void ImGui::ShowMetricsWindow(bool*) {} +void ImGui::ShowFontAtlas(ImFontAtlas*) {} +void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} +void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {} +void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} +void ImGui::DebugNodeFont(ImFont*) {} +void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} +void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} +void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} +void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {} +void ImGui::DebugNodeWindowsList(ImVector*, const char*) {} +void ImGui::DebugNodeViewport(ImGuiViewportP*) {} + +void ImGui::DebugLog(const char*, ...) {} +void ImGui::DebugLogV(const char*, va_list) {} +void ImGui::ShowDebugLogWindow(bool*) {} +void ImGui::ShowStackToolWindow(bool*) {} +void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {} +void ImGui::UpdateDebugToolItemPicker() {} +void ImGui::UpdateDebugToolStackQueries() {} + +#endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS + +//----------------------------------------------------------------------------- + +// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed. +// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github. +#ifdef IMGUI_INCLUDE_IMGUI_USER_INL +#include "imgui_user.inl" +#endif + +//----------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui.h b/Amalgam/include/ImGui/imgui.h new file mode 100644 index 0000000..f74ae7f --- /dev/null +++ b/Amalgam/include/ImGui/imgui.h @@ -0,0 +1,3212 @@ +// dear imgui, v1.89.8 +// (headers) + +// Help: +// - Read FAQ at http://dearimgui.com/faq +// - Newcomers, read 'Programmer guide' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. +// Read imgui.cpp for details, links and comments. + +// Resources: +// - FAQ http://dearimgui.com/faq +// - Homepage https://github.com/ocornut/imgui +// - Releases & changelog https://github.com/ocornut/imgui/releases +// - Gallery https://github.com/ocornut/imgui/issues/6478 (please post your screenshots/video there!) +// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there) +// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started +// - Glossary https://github.com/ocornut/imgui/wiki/Glossary +// - Issues & support https://github.com/ocornut/imgui/issues +// - Tests & Automation https://github.com/ocornut/imgui_test_engine + +// Getting Started? +// - Read https://github.com/ocornut/imgui/wiki/Getting-Started +// - For first-time users having issues compiling/linking/running/loading fonts: +// please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. + +// Library Version +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') +#define IMGUI_VERSION "1.89.8" +#define IMGUI_VERSION_NUM 18980 +#define IMGUI_HAS_TABLE + +/* + +Index of this file: +// [SECTION] Header mess +// [SECTION] Forward declarations and basic types +// [SECTION] Dear ImGui end-user API functions +// [SECTION] Flags & Enumerations +// [SECTION] Helpers: Memory allocations macros, ImVector<> +// [SECTION] ImGuiStyle +// [SECTION] ImGuiIO +// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) +// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) +// [SECTION] Platform Dependent Interfaces (ImGuiPlatformImeData) +// [SECTION] Obsolete functions and types + +*/ + +#pragma once + +// Configuration file with compile-time options +// (edit imconfig.h or '#define IMGUI_USER_CONFIG "myfilename.h" from your build system') +#ifdef IMGUI_USER_CONFIG +#include IMGUI_USER_CONFIG +#endif +#include "imconfig.h" + +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +// Includes +#include // FLT_MIN, FLT_MAX +#include // va_list, va_start, va_end +#include // ptrdiff_t, NULL +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp + +// Define attributes of all API symbols declarations (e.g. for DLL under Windows) +// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) +// Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API) +#ifndef IMGUI_API +#define IMGUI_API +#endif +#ifndef IMGUI_IMPL_API +#define IMGUI_IMPL_API IMGUI_API +#endif + +// Helper Macros +#ifndef IM_ASSERT +#include +#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h +#endif +#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! +#define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. +#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11 +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) + +// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. +#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif + +// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) +#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(IMGUI_DEBUG_PARANOID) +#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) +#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) +#else +#define IM_MSVC_RUNTIME_CHECKS_OFF +#define IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + +// Warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#endif +#if defined(__clang__) +#pragma clang diagnostic push +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Forward declarations and basic types +//----------------------------------------------------------------------------- + +// Forward declarations +struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() +struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) +struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. +struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder) +struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) +struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back. +struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) +struct ImFont; // Runtime data for a single font within a parent ImFontAtlas +struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader +struct ImFontBuilderIO; // Opaque interface to a font builder (stb_truetype or FreeType). +struct ImFontConfig; // Configuration data when adding a font or merging fonts +struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) +struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) +struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) +struct ImGuiIO; // Main configuration and I/O between your application and ImGui +struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) +struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. +struct ImGuiListClipper; // Helper to manually clip large list of items +struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame +struct ImGuiPayload; // User data payload for drag and drop operations +struct ImGuiPlatformImeData; // Platform IME data for io.SetPlatformImeDataFn() function. +struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use) +struct ImGuiStorage; // Helper for key->value storage +struct ImGuiStyle; // Runtime data for styling/colors +struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table +struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) +struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") +struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor + +// Enumerations +// - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value) +enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen) +typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling +typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions +typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type +typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction +typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle) +typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor shape +typedef int ImGuiSortDirection; // -> enum ImGuiSortDirection_ // Enum: A sorting direction (ascending or descending) +typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling +typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor() + +// Flags (declared as int for compatibility with old C++, to allow using as flags without overhead, and to not pollute the top of this file) +// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists! +// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions +typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build +typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags +typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. +typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags +typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() +typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() +typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() +typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. +typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline() +typedef int ImGuiKeyChord; // -> ImGuiKey | ImGuiMod_XXX // Flags: for storage only for now: an ImGuiKey optionally OR-ed with one or more ImGuiMod_XXX values. +typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() +typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable() +typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. +typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar() +typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem() +typedef int ImGuiTableFlags; // -> enum ImGuiTableFlags_ // Flags: For BeginTable() +typedef int ImGuiTableColumnFlags; // -> enum ImGuiTableColumnFlags_// Flags: For TableSetupColumn() +typedef int ImGuiTableRowFlags; // -> enum ImGuiTableRowFlags_ // Flags: For TableNextRow() +typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader() +typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport +typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() + +// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] +// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. +#ifndef ImTextureID +typedef void* ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +#endif + +// ImDrawIdx: vertex index. [Compile-time configurable type] +// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). +// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) +#endif + +// Scalar data types +typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string) +typedef signed char ImS8; // 8-bit signed integer +typedef unsigned char ImU8; // 8-bit unsigned integer +typedef signed short ImS16; // 16-bit signed integer +typedef unsigned short ImU16; // 16-bit unsigned integer +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) +typedef signed long long ImS64; // 64-bit signed integer +typedef unsigned long long ImU64; // 64-bit unsigned integer + +// Character types +// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) +typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings. +typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. +#ifdef IMGUI_USE_WCHAR32 // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16] +typedef ImWchar32 ImWchar; +#else +typedef ImWchar16 ImWchar; +#endif + +// Callback and functions types +typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText() +typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() +typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() +typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() + +// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] +// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. +IM_MSVC_RUNTIME_CHECKS_OFF +struct ImVec2 +{ + float x, y; + constexpr ImVec2() : x(0.0f), y(0.0f) { } + constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { } + float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(void*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine. + float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const void*)(const char*)this)[idx]; } +#ifdef IM_VEC2_CLASS_EXTRA + IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2. +#endif +}; + +// ImVec4: 4D vector used to store clipping rectangles, colors etc. [Compile-time configurable type] +struct ImVec4 +{ + float x, y, z, w; + constexpr ImVec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) { } + constexpr ImVec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) { } +#ifdef IM_VEC4_CLASS_EXTRA + IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4. +#endif +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +//----------------------------------------------------------------------------- +// [SECTION] Dear ImGui end-user API functions +// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Context creation and access + // - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for details. + IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL); + IMGUI_API void DestroyContext(ImGuiContext* ctx = NULL); // NULL = destroy current context + IMGUI_API ImGuiContext* GetCurrentContext(); + IMGUI_API void SetCurrentContext(ImGuiContext* ctx); + + // Main + IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) + IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame! + IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). + IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! + IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData(). + IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. + + // Demo, Debug, Information + IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. + IMGUI_API void ShowDebugLogWindow(bool* p_open = NULL); // create Debug Log window. display a simplified log of important dear imgui events. + IMGUI_API void ShowStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID. + IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. + IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) + IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. + IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. + IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as an end-user (mouse/keyboard controls). + IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.80 WIP" (essentially the value for IMGUI_VERSION from the compiled version of imgui.cpp) + + // Styles + IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default) + IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font + IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style + + // Windows + // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack. + // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window, + // which clicking will set the boolean to false when clicked. + // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. + // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). + // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting + // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // - Note that the bottom of window stack always contains a window called "Debug". + IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); + IMGUI_API void End(); + + // Child Windows + // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. + // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). + // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. + // Always call a matching EndChild() for each BeginChild() call, regardless of its return value. + // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, + // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function + // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); + IMGUI_API void EndChild(); + + // Windows Utilities + // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into. + IMGUI_API bool IsWindowAppearing(); + IMGUI_API bool IsWindowCollapsed(); + IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. + IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! + IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) + IMGUI_API ImVec2 GetWindowSize(); // get current window size + IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) + IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) + + // Window manipulation + // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc. + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin() + IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints. + IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin() + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin() + IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() + IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // set next window scrolling value (use < 0.0f to not affect a given axis). + IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). + IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). + IMGUI_API void SetWindowFontScale(float scale); // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state + IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. + + // Content region + // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful. + // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) + IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates + + // Windows Scrolling + // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). + // - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY(). + IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()] + IMGUI_API float GetScrollY(); // get scrolling amount [0 .. GetScrollMaxY()] + IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0 .. GetScrollMaxX()] + IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0 .. GetScrollMaxY()] + IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x + IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y + IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead. + IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. + + // Parameters stacks (shared) + IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font + IMGUI_API void PopFont(); + IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); + IMGUI_API void PopStyleColor(int count = 1); + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API void PushTabStop(bool tab_stop); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopTabStop(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. + IMGUI_API void PopButtonRepeat(); + + // Parameters stacks (current window) + IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side). + IMGUI_API void PopItemWidth(); + IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side) + IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. + IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space + IMGUI_API void PopTextWrapPos(); + + // Style read access + // - Use the ShowStyleEditor() function to interactively see/edit the colors. + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList + IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList + IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList + IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. + + // Cursor / Layout + // - By "cursor" we mean the current output position. + // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. + // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. + // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: + // Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() + // Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. + IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. + IMGUI_API void SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f); // call between widgets or groups to layout them horizontally. X position given in window coordinates. + IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in a horizontal-layout context. + IMGUI_API void Spacing(); // add vertical spacing. + IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by indent_w, or style.IndentSpacing if indent_w <= 0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by indent_w, or style.IndentSpacing if indent_w <= 0 + IMGUI_API void BeginGroup(); // lock horizontal starting position + IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) + IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) + IMGUI_API float GetCursorPosX(); // (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc. + IMGUI_API float GetCursorPosY(); // other functions such as GetCursorScreenPos or everything in ImDrawList:: + IMGUI_API void SetCursorPos(const ImVec2& local_pos); // are using the main, absolute coordinate system. + IMGUI_API void SetCursorPosX(float local_x); // GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.) + IMGUI_API void SetCursorPosY(float local_y); // + IMGUI_API ImVec2 GetCursorStartPos(); // initial cursor position in window coordinates + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (useful to work with ImDrawList API). generally top-left == GetMainViewport()->Pos == (0,0) in single viewport mode, and bottom-right == GetMainViewport()->Pos+Size == io.DisplaySize in single-viewport mode. + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates + IMGUI_API void AlignTextToFramePadding(); // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item) + IMGUI_API float GetTextLineHeight(); // ~ FontSize + IMGUI_API float GetTextLineHeightWithSpacing(); // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text) + IMGUI_API float GetFrameHeight(); // ~ FontSize + style.FramePadding.y * 2 + IMGUI_API float GetFrameHeightWithSpacing(); // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets) + + // ID stack/scopes + // Read the FAQ (docs/FAQ.md or http://dearimgui.com/faq) for more details about how ID are handled in dear imgui. + // - Those questions are answered and impacted by understanding of the ID stack system: + // - "Q: Why is my widget not reacting when I click on it?" + // - "Q: How can I have widgets with an empty label?" + // - "Q: How can I have multiple widgets with the same label?" + // - Short version: ID are hashes of the entire ID stack. If you are creating widgets in a loop you most likely + // want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them. + // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others. + // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed + used as an ID, + // whereas "str_id" denote a string that is only used as an ID and not normally displayed. + IMGUI_API void PushID(const char* str_id); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const char* str_id_begin, const char* str_id_end); // push string into the ID stack (will hash string). + IMGUI_API void PushID(const void* ptr_id); // push pointer into the ID stack (will hash pointer). + IMGUI_API void PushID(int int_id); // push integer into the ID stack (will hash integer). + IMGUI_API void PopID(); // pop from the ID stack. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself + IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); + IMGUI_API ImGuiID GetID(const void* ptr_id); + + // Widgets: Text + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. + IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text + IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void TextDisabled(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor(); + IMGUI_API void TextDisabledV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void TextWrapped(const char* fmt, ...) IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize(). + IMGUI_API void TextWrappedV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void LabelText(const char* label, const char* fmt, ...) IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets + IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() + IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line + + // Widgets: Main + // - Most widgets return true when the value has been changed or when pressed/selected + // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state. + IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0, 0)); // button + IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text + IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.) + IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape + IMGUI_API bool Checkbox(const char* label, bool* v); + IMGUI_API bool CheckboxFlags(const char* label, int* flags, int flags_value); + IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value); + IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; } + IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer + IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); + IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses + + // Widgets: Images + // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0)); + IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + + // Widgets: Combo Box (Dropdown) + // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. + IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); + IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! + IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); + IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1); // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0" + IMGUI_API bool Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1); + + // Widgets: Drag Sliders + // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. + // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every function, note that a 'float v[X]' function argument is the same as 'float* v', + // the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Format string may also be set to NULL or use the default format ("%f" or "%d"). + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. + // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. + // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. + // - Legacy: Pre-1.78 there are DragXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 + IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound + IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); // If v_min >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed = 1.0f, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0); + + // Widgets: Regular Sliders + // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped by default and can go off-bounds. Use ImGuiSliderFlags_AlwaysClamp to always clamp. + // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. + // - Format string may also be set to NULL or use the default format ("%f" or "%d"). + // - Legacy: Pre-1.78 there are SliderXXX() function signatures that take a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument. + // If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361 + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. + IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0); + + // Widgets: Input with Keyboard + // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp. + // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc. + IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + + // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.) + // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. + // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x + IMGUI_API bool ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); + IMGUI_API bool ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); + IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); + IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); + IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed. + IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. + + // Widgets: Trees + // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. + IMGUI_API bool TreeNode(const char* label); + IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2); // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet(). + IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2); // " + IMGUI_API bool TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2); + IMGUI_API bool TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0); + IMGUI_API bool TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3); + IMGUI_API bool TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API bool TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3); + IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired. + IMGUI_API void TreePush(const void* ptr_id); // " + IMGUI_API void TreePop(); // ~ Unindent()+PopId() + IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode + IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). + IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header. + IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. + + // Widgets: Selectables + // - A selectable highlights when hovered, and can display another color when selected. + // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous. + IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height + IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. + + // Widgets: List Boxes + // - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes. + // - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items. + // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. + // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth + // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items + IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region + IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! + IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); + IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); + + // Widgets: Data Plotting + // - Consider using ImPlot (https://github.com/epezent/implot) which is much better! + IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); + IMGUI_API void PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + + // Widgets: Value() Helpers. + // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace) + IMGUI_API void Value(const char* prefix, bool b); + IMGUI_API void Value(const char* prefix, int v); + IMGUI_API void Value(const char* prefix, unsigned int v); + IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); + + // Widgets: Menus + // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. + // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. + // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. + // - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. + IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). + IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! + IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. + IMGUI_API void EndMainMenuBar(); // only call EndMainMenuBar() if BeginMainMenuBar() returns true! + IMGUI_API bool BeginMenu(const char* label, bool enabled = true); // create a sub-menu entry. only call EndMenu() if this returns true! + IMGUI_API void EndMenu(); // only call EndMenu() if BeginMenu() returns true! + IMGUI_API bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true); // return true when activated. + IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL + + // Tooltips + // - Tooltips are windows following the mouse. They do not take focus away. + // - A tooltip window can contain items of any types. SetTooltip() is a shortcut for the 'if (BeginTooltip()) { Text(...); EndTooltip(); }' idiom. + IMGUI_API bool BeginTooltip(); // begin/append a tooltip window. + IMGUI_API void EndTooltip(); // only call EndTooltip() if BeginTooltip()/BeginItemTooltip() returns true! + IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip. Often used after a ImGui::IsItemHovered() check. Override any previous call to SetTooltip(). + IMGUI_API void SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Tooltips: helpers for showing a tooltip when hovering an item + // - BeginItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_Tooltip) && BeginTooltip())' idiom. + // - SetItemTooltip() is a shortcut for the 'if (IsItemHovered(ImGuiHoveredFlags_Tooltip)) { SetTooltip(...); }' idiom. + // - Where 'ImGuiHoveredFlags_Tooltip' itself is a shortcut to use 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on active input type. For mouse it defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. + IMGUI_API bool BeginItemTooltip(); // begin/append a tooltip window if preceding item was hovered. + IMGUI_API void SetItemTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip if preceeding item was hovered. override any previous call to SetTooltip(). + IMGUI_API void SetItemTooltipV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Popups, Modals + // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. + // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. + // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). + // - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack. + // This is sometimes leading to confusing mistakes. May rework this in the future. + + // Popups: begin/end functions + // - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window. + // - BeginPopupModal(): block every interaction behind the window, cannot be closed by user, add a dimming background, has a title bar. + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it. + IMGUI_API void EndPopup(); // only call EndPopup() if BeginPopupXXX() returns true! + + // Popups: open/close functions + // - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options. + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. + // - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually. + // - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options). + // - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup(). + // - Use IsWindowAppearing() after BeginPopup() to tell if a window just opened. + // - IMPORTANT: Notice that for OpenPopupOnItemClick() we exceptionally default flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter + IMGUI_API void OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0); // call to mark popup as open (don't call every frame!). + IMGUI_API void OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags = 0); // id overload to facilitate calling from nested stacks + IMGUI_API void OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // helper to open popup when clicked on last item. Default to ImGuiPopupFlags_MouseButtonRight == 1. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors) + IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into. + + // Popups: open+begin combined functions helpers + // - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking. + // - They are convenient to easily create context menus, hence the name. + // - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future. + // - IMPORTANT: Notice that we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight. + IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked on last item. Use str_id==NULL to associate the popup to previous item. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! + IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window. + IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1); // open+begin popup when clicked in void (where there are no windows). + + // Popups: query functions + // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack. + // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack. + // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open. + IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open. + + // Tables + // - Full-featured replacement for old Columns API. + // - See Demo->Tables for demo code. See top of imgui_tables.cpp for general commentary. + // - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags. + // The typical call flow is: + // - 1. Call BeginTable(), early out if returning false. + // - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults. + // - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows. + // - 4. Optionally call TableHeadersRow() to submit a header row. Names are pulled from TableSetupColumn() data. + // - 5. Populate contents: + // - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column. + // - If you are using tables as a sort of grid, where every column is holding the same type of contents, + // you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex(). + // TableNextColumn() will automatically wrap-around into the next row if needed. + // - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column! + // - Summary of possible call flow: + // -------------------------------------------------------------------------------------------------------- + // TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK + // TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK + // TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row! + // TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! + // -------------------------------------------------------------------------------------------------------- + // - 5. Call EndTable() + IMGUI_API bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); + IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! + IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. + IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible. + IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. + + // Tables: Headers & Columns declaration + // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. + // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. + // Headers are required to perform: reordering, sorting, and opening the context menu. + // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. + // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in + // some advanced use cases (e.g. adding custom widgets in header row). + // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); + IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. + IMGUI_API void TableHeadersRow(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu + IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) + + // Tables: Sorting & Miscellaneous functions + // - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting. + // When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have + // changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting, + // else you may wastefully sort your data every frame! + // - Functions args 'int column_n' treat the default value of -1 as the same as passing the current column index. + IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable(). + IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable) + IMGUI_API int TableGetColumnIndex(); // return current column index. + IMGUI_API int TableGetRowIndex(); // return current row index. + IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column. + IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column. + IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) + IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details. + + // Legacy Columns API (prefer using Tables!) + // - You can also use SameLine(pos_x) to mimic simplified columns. + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); + IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished + IMGUI_API int GetColumnIndex(); // get current column index + IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column + IMGUI_API void SetColumnWidth(int column_index, float width); // set column width (in pixels). pass -1 to use current column + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column + IMGUI_API int GetColumnsCount(); + + // Tab Bars, Tabs + // - Note: Tabs are automatically created by the docking system (when in 'docking' branch). Use this to create tab bars/tabs yourself. + IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar + IMGUI_API void EndTabBar(); // only call EndTabBar() if BeginTabBar() returns true! + IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected. + IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true! + IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar. + IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. + + // Logging/Capture + // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. + IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) + IMGUI_API void LogToFile(int auto_open_depth = -1, const char* filename = NULL); // start logging to file + IMGUI_API void LogToClipboard(int auto_open_depth = -1); // start logging to OS clipboard + IMGUI_API void LogFinish(); // stop logging (close file, etc.) + IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard + IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed) + IMGUI_API void LogTextV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Drag and Drop + // - On source items, call BeginDragDropSource(), if it returns true also call SetDragDropPayload() + EndDragDropSource(). + // - On target candidates, call BeginDragDropTarget(), if it returns true also call AcceptDragDropPayload() + EndDragDropTarget(). + // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip, see #1725) + // - An item can be both drag source and drop target. + IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource() + IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. Return true when payload has been accepted. + IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true! + IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget() + IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released. + IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true! + IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type. + + // Disabling [BETA API] + // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) + // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) + // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. + IMGUI_API void BeginDisabled(bool disabled = true); + IMGUI_API void EndDisabled(); + + // Clipping + // - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only. + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect); + IMGUI_API void PopClipRect(); + + // Focus, Activation + // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. + IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. + + // Overlapping mode + IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this. + + // Item/Widgets Utilities and Query Functions + // - Most of the functions are referring to the previous Item that has been submitted. + // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions. + IMGUI_API bool IsItemHovered(ImGuiHoveredFlags flags = 0); // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options. + IMGUI_API bool IsItemActive(); // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false) + IMGUI_API bool IsItemFocused(); // is the last item focused for keyboard/gamepad navigation? + IMGUI_API bool IsItemClicked(ImGuiMouseButton mouse_button = 0); // is the last item hovered and mouse clicked on? (**) == IsMouseClicked(mouse_button) && IsItemHovered()Important. (**) this is NOT equivalent to the behavior of e.g. Button(). Read comments in function definition. + IMGUI_API bool IsItemVisible(); // is the last item visible? (items may be out of sight because of clipping/scrolling) + IMGUI_API bool IsItemEdited(); // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets. + IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). + IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that require continuous editing. + IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that require continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). + IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode(). + IMGUI_API bool IsAnyItemHovered(); // is any item hovered? + IMGUI_API bool IsAnyItemActive(); // is any item active? + IMGUI_API bool IsAnyItemFocused(); // is any item focused? + IMGUI_API ImGuiID GetItemID(); // get ID of last item (~~ often same ImGui::GetID(label) beforehand) + IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space) + IMGUI_API ImVec2 GetItemRectSize(); // get size of last item + + // Viewports + // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. + // - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. + // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. + IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL. + + // Background/Foreground Draw Lists + IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendered one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + + // Miscellaneous Utilities + IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. + IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side. + IMGUI_API double GetTime(); // get global imgui time. incremented by io.DeltaTime every frame. + IMGUI_API int GetFrameCount(); // get global imgui frame count. incremented by 1 every frame. + IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); // you may use this when creating your own ImDrawList instances. + IMGUI_API const char* GetStyleColorName(ImGuiCol idx); // get a string corresponding to the enum value (for display, saving, etc.). + IMGUI_API void SetStateStorage(ImGuiStorage* storage); // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it) + IMGUI_API ImGuiStorage* GetStateStorage(); + IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame + IMGUI_API void EndChildFrame(); // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window) + + // Text Utilities + IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); + + // Color Utilities + IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in); + IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); + IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); + IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); + + // Inputs Utilities: Keyboard/Mouse/Gamepad + // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). + // - before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. About use of those legacy ImGuiKey values: + // - without IMGUI_DISABLE_OBSOLETE_KEYIO (legacy support): you can still use your legacy native/user indices (< 512) according to how your backend/engine stored them in io.KeysDown[], but need to cast them to ImGuiKey. + // - with IMGUI_DISABLE_OBSOLETE_KEYIO (this is the way forward): any use of ImGuiKey will assert with key < 512. GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined). + IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. + IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? + IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate + IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared. + IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. + + // Inputs Utilities: Mouse specific + // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. + // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. + // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') + IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) + IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). + IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. + IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available + IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. + IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) + IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) + IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you + IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired mouse cursor shape + IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse); // Override io.WantCaptureMouse flag next frame (said flag is left for your application to handle, typical when true it instucts your app to ignore inputs). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse;" after the next NewFrame() call. + + // Clipboard Utilities + // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. + IMGUI_API const char* GetClipboardText(); + IMGUI_API void SetClipboardText(const char* text); + + // Settings/.Ini Utilities + // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini"). + // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually. + // - Important: default value "imgui.ini" is relative to current working dir! Most apps will want to lock this to an absolute path (e.g. same path as executables). + IMGUI_API void LoadIniSettingsFromDisk(const char* ini_filename); // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename). + IMGUI_API void LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source. + IMGUI_API void SaveIniSettingsToDisk(const char* ini_filename); // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext). + IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. + + // Debug Utilities + IMGUI_API void DebugTextEncoding(const char* text); + IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro. + + // Memory Allocators + // - Those functions are not reliant on the current context. + // - DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() + // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. + IMGUI_API void SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data = NULL); + IMGUI_API void GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data); + IMGUI_API void* MemAlloc(size_t size); + IMGUI_API void MemFree(void* ptr); + +} // namespace ImGui + +//----------------------------------------------------------------------------- +// [SECTION] Flags & Enumerations +//----------------------------------------------------------------------------- + +// Flags for ImGui::Begin() +// (Those are per-window flags. There are shared flags in ImGuiIO: io.ConfigWindowsResizeFromEdges and io.ConfigWindowsMoveFromTitleBarOnly) +enum ImGuiWindowFlags_ +{ + ImGuiWindowFlags_None = 0, + ImGuiWindowFlags_NoTitleBar = 1 << 0, // Disable title-bar + ImGuiWindowFlags_NoResize = 1 << 1, // Disable user resizing with the lower-right grip + ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window + ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) + ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as Window Menu Button (e.g. within a docking node). + ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame + ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). + ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file + ImGuiWindowFlags_NoMouseInputs = 1 << 9, // Disable catching mouse, hovering test with pass through. + ImGuiWindowFlags_MenuBar = 1 << 10, // Has a menu-bar + ImGuiWindowFlags_HorizontalScrollbar = 1 << 11, // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section. + ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12, // Disable taking focus when transitioning from hidden to visible state + ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) + ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) + ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16, // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient) + ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, + ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, + + // [Internal] + ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. + ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() + ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() + ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() + ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() +}; + +// Flags for ImGui::InputText() +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive) +enum ImGuiInputTextFlags_ +{ + ImGuiInputTextFlags_None = 0, + ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/ + ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef + ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z + ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs + ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. + ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field + ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter). + ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally + ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode + ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode + ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' + ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) + ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) + ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + ImGuiInputTextFlags_EscapeClearsAll = 1 << 20, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert) + + // Obsolete names + //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior +}; + +// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*() +enum ImGuiTreeNodeFlags_ +{ + ImGuiTreeNodeFlags_None = 0, + ImGuiTreeNodeFlags_Selected = 1 << 0, // Draw as selected + ImGuiTreeNodeFlags_Framed = 1 << 1, // Draw frame with background (e.g. for CollapsingHeader) + ImGuiTreeNodeFlags_AllowOverlap = 1 << 2, // Hit testing to allow subsequent widgets to overlap this one + ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack + ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) + ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. + ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow + ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). + ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default. + ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) + //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible + ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 +#endif +}; + +// Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions. +// - To be backward compatible with older API which took an 'int mouse_button = 1' argument, we need to treat +// small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags. +// It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags. +// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0. +// IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter +// and want to use another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag explicitly. +// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later). +enum ImGuiPopupFlags_ +{ + ImGuiPopupFlags_None = 0, + ImGuiPopupFlags_MouseButtonLeft = 0, // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left) + ImGuiPopupFlags_MouseButtonRight = 1, // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right) + ImGuiPopupFlags_MouseButtonMiddle = 2, // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle) + ImGuiPopupFlags_MouseButtonMask_ = 0x1F, + ImGuiPopupFlags_MouseButtonDefault_ = 1, + ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5, // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack + ImGuiPopupFlags_NoOpenOverItems = 1 << 6, // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space + ImGuiPopupFlags_AnyPopupId = 1 << 7, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup. + ImGuiPopupFlags_AnyPopupLevel = 1 << 8, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level) + ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel, +}; + +// Flags for ImGui::Selectable() +enum ImGuiSelectableFlags_ +{ + ImGuiSelectableFlags_None = 0, + ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this doesn't close parent popup window + ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column) + ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too + ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text + ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7 +#endif +}; + +// Flags for ImGui::BeginCombo() +enum ImGuiComboFlags_ +{ + ImGuiComboFlags_None = 0, + ImGuiComboFlags_PopupAlignLeft = 1 << 0, // Align the popup toward the left by default + ImGuiComboFlags_HeightSmall = 1 << 1, // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo() + ImGuiComboFlags_HeightRegular = 1 << 2, // Max ~8 items visible (default) + ImGuiComboFlags_HeightLarge = 1 << 3, // Max ~20 items visible + ImGuiComboFlags_HeightLargest = 1 << 4, // As many fitting items as possible + ImGuiComboFlags_NoArrowButton = 1 << 5, // Display on the preview box without the square arrow button + ImGuiComboFlags_NoPreview = 1 << 6, // Display only a square arrow button + ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest, +}; + +// Flags for ImGui::BeginTabBar() +enum ImGuiTabBarFlags_ +{ + ImGuiTabBarFlags_None = 0, + ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list + ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll) + ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab + ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit + ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit + ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll, + ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown, +}; + +// Flags for ImGui::BeginTabItem() +enum ImGuiTabItemFlags_ +{ + ImGuiTabItemFlags_None = 0, + ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Display a dot next to the title + tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. + ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programmatically make the tab selected when calling BeginTabItem() + ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. + ImGuiTabItemFlags_NoPushId = 1 << 3, // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() + ImGuiTabItemFlags_NoTooltip = 1 << 4, // Disable tooltip for the given tab + ImGuiTabItemFlags_NoReorder = 1 << 5, // Disable reordering this tab or having another tab cross over this tab + ImGuiTabItemFlags_Leading = 1 << 6, // Enforce the tab position to the left of the tab bar (after the tab list popup button) + ImGuiTabItemFlags_Trailing = 1 << 7, // Enforce the tab position to the right of the tab bar (before the scrolling buttons) +}; + +// Flags for ImGui::BeginTable() +// - Important! Sizing policies have complex and subtle side effects, much more so than you would expect. +// Read comments/demos carefully + experiment with live demos to get acquainted with them. +// - The DEFAULT sizing policies are: +// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. +// - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off. +// - When ScrollX is off: +// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight. +// - Columns sizing policy allowed: Stretch (default), Fixed/Auto. +// - Fixed Columns (if any) will generally obtain their requested width (unless the table cannot fit them all). +// - Stretch Columns will share the remaining width according to their respective weight. +// - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors. +// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). +// - When ScrollX is on: +// - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed +// - Columns sizing policy allowed: Fixed/Auto mostly. +// - Fixed Columns can be enlarged as needed. Table will show a horizontal scrollbar if needed. +// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop. +// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). +// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. +// - Read on documentation at the top of imgui_tables.cpp for details. +enum ImGuiTableFlags_ +{ + // Features + ImGuiTableFlags_None = 0, + ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns. + ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) + ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu. + ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate. + ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. + ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + // Decorations + ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) + ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows. + ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom. + ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns. + ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides. + ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. + ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. + ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. + ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. + ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. + ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appear in Headers). -> May move to style + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appear in Headers). -> May move to style + // Sizing Policy (read above for defaults) + ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. + ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. + ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. + ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). + // Sizing Extra Options + ImGuiTableFlags_NoHostExtendX = 1 << 16, // Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. + ImGuiTableFlags_NoHostExtendY = 1 << 17, // Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. + ImGuiTableFlags_PreciseWidths = 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. + // Clipping + ImGuiTableFlags_NoClip = 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + // Padding + ImGuiTableFlags_PadOuterX = 1 << 21, // Default if BordersOuterV is on. Enable outermost padding. Generally desirable if you have headers. + ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outermost padding. + ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + // Scrolling + ImGuiTableFlags_ScrollX = 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this creates a child window, ScrollY is currently generally recommended when using ScrollX. + ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + // Sorting + ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). + ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + + // [Internal] Combinations and masks + ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame, +}; + +// Flags for ImGui::TableSetupColumn() +enum ImGuiTableColumnFlags_ +{ + // Input configuration flags + ImGuiTableColumnFlags_None = 0, + ImGuiTableColumnFlags_Disabled = 1 << 0, // Overriding/master disable flag: hide column, won't show in context menu (unlike calling TableSetColumnEnabled() which manipulates the user accessible state) + ImGuiTableColumnFlags_DefaultHide = 1 << 1, // Default as a hidden/disabled column. + ImGuiTableColumnFlags_DefaultSort = 1 << 2, // Default as a sorting column. + ImGuiTableColumnFlags_WidthStretch = 1 << 3, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp). + ImGuiTableColumnFlags_WidthFixed = 1 << 4, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable). + ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. + ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column. + ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. + ImGuiTableColumnFlags_NoClip = 1 << 8, // Disable clipping for this column (all NoClip columns will render in a same draw command). + ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). + ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. + ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. + ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit label for this column. Convenient for some small columns. Name will still appear in context menu. + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. + ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). + ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column. + ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0). + ImGuiTableColumnFlags_IndentDisable = 1 << 17, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored. + + // Output status flags, read-only via TableGetColumnFlags() + ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags. + ImGuiTableColumnFlags_IsVisible = 1 << 25, // Status: is visible == is enabled AND not clipped by scrolling. + ImGuiTableColumnFlags_IsSorted = 1 << 26, // Status: is currently part of the sort specs + ImGuiTableColumnFlags_IsHovered = 1 << 27, // Status: is hovered by mouse + + // [Internal] Combinations and masks + ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed, + ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable, + ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered, + ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30, // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) +}; + +// Flags for ImGui::TableNextRow() +enum ImGuiTableRowFlags_ +{ + ImGuiTableRowFlags_None = 0, + ImGuiTableRowFlags_Headers = 1 << 0, // Identify header row (set default background color + width of its contents accounted differently for auto column width) +}; + +// Enum for ImGui::TableSetBgColor() +// Background colors are rendering in 3 layers: +// - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set. +// - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set. +// - Layer 2: draw with CellBg color if set. +// The purpose of the two row/columns layers is to let you decide if a background color change should override or blend with the existing color. +// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows. +// If you set the color of RowBg0 target, your color will override the existing RowBg0 color. +// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color. +enum ImGuiTableBgTarget_ +{ + ImGuiTableBgTarget_None = 0, + ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) + ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking) + ImGuiTableBgTarget_CellBg = 3, // Set cell background color (top-most color) +}; + +// Flags for ImGui::IsWindowFocused() +enum ImGuiFocusedFlags_ +{ + ImGuiFocusedFlags_None = 0, + ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused + ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) + ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! + ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) + //ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows, +}; + +// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered() +// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ! +// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls. +enum ImGuiHoveredFlags_ +{ + ImGuiHoveredFlags_None = 0, // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them. + ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered + ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) + ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered + ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) + //ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) + ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window + //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. + ImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item. + ImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. + ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled + ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse + ImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, + ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, + ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, + + // Tooltips mode + // - typically used in IsItemHovered() + SetTooltip() sequence. + // - this is a shortcut to pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' where you can reconfigure desired behavior. + // e.g. 'TooltipHoveredFlagsForMouse' defaults to 'ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort'. + // - for frequently actioned or hovered items providing a tooltip, you want may to use ImGuiHoveredFlags_ForTooltip (stationary + delay) so the tooltip doesn't show too often. + // - for items which main purpose is to be hovered, or items with low affordance, or in less consistent apps, prefer no delay or shorter delay. + ImGuiHoveredFlags_ForTooltip = 1 << 12, // Shortcut for standard flags when using IsItemHovered() + SetTooltip() sequence. + + // (Advanced) Mouse Hovering delays. + // - generally you can use ImGuiHoveredFlags_ForTooltip to use application-standardized flags. + // - use those if you need specific overrides. + ImGuiHoveredFlags_Stationary = 1 << 13, // Require mouse to be stationary for style.HoverStationaryDelay (~0.15 sec) _at least one time_. After this, can move on same item/window. Using the stationary test tends to reduces the need for a long delay. + ImGuiHoveredFlags_DelayNone = 1 << 14, // IsItemHovered() only: Return true immediately (default). As this is the default you generally ignore this. + ImGuiHoveredFlags_DelayShort = 1 << 15, // IsItemHovered() only: Return true after style.HoverDelayShort elapsed (~0.15 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). + ImGuiHoveredFlags_DelayNormal = 1 << 16, // IsItemHovered() only: Return true after style.HoverDelayNormal elapsed (~0.40 sec) (shared between items) + requires mouse to be stationary for style.HoverStationaryDelay (once per item). + ImGuiHoveredFlags_NoSharedDelay = 1 << 17, // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays) +}; + +// Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() +enum ImGuiDragDropFlags_ +{ + ImGuiDragDropFlags_None = 0, + // BeginDragDropSource() flags + ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, // Disable preview tooltip. By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disables this behavior. + ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disables this behavior so you can still call IsItemHovered() on the source item. + ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item. + ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit. + ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously. + ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged) + // AcceptDragDropPayload() flags + ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered. + ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target. + ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site. + ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery. +}; + +// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. + +// A primary data type +enum ImGuiDataType_ +{ + ImGuiDataType_S8, // signed char / char (with sensible compilers) + ImGuiDataType_U8, // unsigned char + ImGuiDataType_S16, // short + ImGuiDataType_U16, // unsigned short + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long / __int64 + ImGuiDataType_U64, // unsigned long long / unsigned __int64 + ImGuiDataType_Float, // float + ImGuiDataType_Double, // double + ImGuiDataType_COUNT +}; + +// A cardinal direction +enum ImGuiDir_ +{ + ImGuiDir_None = -1, + ImGuiDir_Left = 0, + ImGuiDir_Right = 1, + ImGuiDir_Up = 2, + ImGuiDir_Down = 3, + ImGuiDir_COUNT +}; + +// A sorting direction +enum ImGuiSortDirection_ +{ + ImGuiSortDirection_None = 0, + ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc. + ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. +}; + +// A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. +// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87). +// Since >= 1.89 we increased typing (went from int to enum), some legacy code may need a cast to ImGuiKey. +// Read details about the 1.87 and 1.89 transition : https://github.com/ocornut/imgui/issues/4921 +// Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). +enum ImGuiKey : int +{ + // Keyboard + ImGuiKey_None = 0, + ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN + ImGuiKey_LeftArrow, + ImGuiKey_RightArrow, + ImGuiKey_UpArrow, + ImGuiKey_DownArrow, + ImGuiKey_PageUp, + ImGuiKey_PageDown, + ImGuiKey_Home, + ImGuiKey_End, + ImGuiKey_Insert, + ImGuiKey_Delete, + ImGuiKey_Backspace, + ImGuiKey_Space, + ImGuiKey_Enter, + ImGuiKey_Escape, + ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, + ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper, + ImGuiKey_Menu, + ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9, + ImGuiKey_A, ImGuiKey_B, ImGuiKey_C, ImGuiKey_D, ImGuiKey_E, ImGuiKey_F, ImGuiKey_G, ImGuiKey_H, ImGuiKey_I, ImGuiKey_J, + ImGuiKey_K, ImGuiKey_L, ImGuiKey_M, ImGuiKey_N, ImGuiKey_O, ImGuiKey_P, ImGuiKey_Q, ImGuiKey_R, ImGuiKey_S, ImGuiKey_T, + ImGuiKey_U, ImGuiKey_V, ImGuiKey_W, ImGuiKey_X, ImGuiKey_Y, ImGuiKey_Z, + ImGuiKey_F1, ImGuiKey_F2, ImGuiKey_F3, ImGuiKey_F4, ImGuiKey_F5, ImGuiKey_F6, + ImGuiKey_F7, ImGuiKey_F8, ImGuiKey_F9, ImGuiKey_F10, ImGuiKey_F11, ImGuiKey_F12, + ImGuiKey_Apostrophe, // ' + ImGuiKey_Comma, // , + ImGuiKey_Minus, // - + ImGuiKey_Period, // . + ImGuiKey_Slash, // / + ImGuiKey_Semicolon, // ; + ImGuiKey_Equal, // = + ImGuiKey_LeftBracket, // [ + ImGuiKey_Backslash, // \ (this text inhibit multiline comment caused by backslash) + ImGuiKey_RightBracket, // ] + ImGuiKey_GraveAccent, // ` + ImGuiKey_CapsLock, + ImGuiKey_ScrollLock, + ImGuiKey_NumLock, + ImGuiKey_PrintScreen, + ImGuiKey_Pause, + ImGuiKey_Keypad0, ImGuiKey_Keypad1, ImGuiKey_Keypad2, ImGuiKey_Keypad3, ImGuiKey_Keypad4, + ImGuiKey_Keypad5, ImGuiKey_Keypad6, ImGuiKey_Keypad7, ImGuiKey_Keypad8, ImGuiKey_Keypad9, + ImGuiKey_KeypadDecimal, + ImGuiKey_KeypadDivide, + ImGuiKey_KeypadMultiply, + ImGuiKey_KeypadSubtract, + ImGuiKey_KeypadAdd, + ImGuiKey_KeypadEnter, + ImGuiKey_KeypadEqual, + + // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION + // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) + ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) + ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) + ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) + ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // Cancel / Close / Exit + ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // Text Input / On-screen Keyboard + ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // Activate / Open / Toggle / Tweak + ImGuiKey_GamepadDpadLeft, // D-pad Left // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadRight, // D-pad Right // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadUp, // D-pad Up // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadDown, // D-pad Down // Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // Tweak Slower / Focus Previous (in Windowing mode) + ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // Tweak Faster / Focus Next (in Windowing mode) + ImGuiKey_GamepadL2, // L Trig. (Xbox) ZL (Switch) L2 (PS) [Analog] + ImGuiKey_GamepadR2, // R Trig. (Xbox) ZR (Switch) R2 (PS) [Analog] + ImGuiKey_GamepadL3, // L Stick (Xbox) L3 (Switch) L3 (PS) + ImGuiKey_GamepadR3, // R Stick (Xbox) R3 (Switch) R3 (PS) + ImGuiKey_GamepadLStickLeft, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickRight, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickUp, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadLStickDown, // [Analog] // Move Window (in Windowing mode) + ImGuiKey_GamepadRStickLeft, // [Analog] + ImGuiKey_GamepadRStickRight, // [Analog] + ImGuiKey_GamepadRStickUp, // [Analog] + ImGuiKey_GamepadRStickDown, // [Analog] + + // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) + // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. + ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY, + + // [Internal] Reserved for mod storage + ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, + ImGuiKey_COUNT, + + // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) + // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing + // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc. + // - Code polling every key (e.g. an interface to detect a key press for input mapping) might want to ignore those + // and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiMod_Ctrl). + // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys. + // In practice: it's complicated; mods are often provided from different sources. Keyboard layout, IME, sticky keys and + // backends tend to interfere and break that equivalence. The safer decision is to relay that ambiguity down to the end-user... + ImGuiMod_None = 0, + ImGuiMod_Ctrl = 1 << 12, // Ctrl + ImGuiMod_Shift = 1 << 13, // Shift + ImGuiMod_Alt = 1 << 14, // Option/Menu + ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows + ImGuiMod_Shortcut = 1 << 11, // Alias for Ctrl (non-macOS) _or_ Super (macOS). + ImGuiMod_Mask_ = 0xF800, // 5-bits + + // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. + // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) + // If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. + ImGuiKey_NamedKey_BEGIN = 512, + ImGuiKey_NamedKey_END = ImGuiKey_COUNT, + ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. +#else + ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys + ImGuiKey_KeysData_OFFSET = 0, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. +#endif + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89 + ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter, // Renamed in 1.87 +#endif +}; + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +// OBSOLETED in 1.88 (from July 2022): ImGuiNavInput and io.NavInputs[]. +// Official backends between 1.60 and 1.86: will keep working and feed gamepad inputs as long as IMGUI_DISABLE_OBSOLETE_KEYIO is not set. +// Custom backends: feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. +enum ImGuiNavInput +{ + ImGuiNavInput_Activate, ImGuiNavInput_Cancel, ImGuiNavInput_Input, ImGuiNavInput_Menu, ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight, ImGuiNavInput_DpadUp, ImGuiNavInput_DpadDown, + ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight, ImGuiNavInput_LStickUp, ImGuiNavInput_LStickDown, ImGuiNavInput_FocusPrev, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakSlow, ImGuiNavInput_TweakFast, + ImGuiNavInput_COUNT, +}; +#endif + +// Configuration flags stored in io.ConfigFlags. Set by user/application. +enum ImGuiConfigFlags_ +{ + ImGuiConfigFlags_None = 0, + ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. Enable full Tabbing + directional arrows + space/enter to activate. + ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth. + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. + ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the backend. + ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. + + // User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui) + ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. + ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. +}; + +// Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend. +enum ImGuiBackendFlags_ +{ + ImGuiBackendFlags_None = 0, + ImGuiBackendFlags_HasGamepad = 1 << 0, // Backend Platform supports gamepad and currently has one connected. + ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. + ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). + ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. +}; + +// Enumeration for PushStyleColor() / PopStyleColor() +enum ImGuiCol_ +{ + ImGuiCol_Text, + ImGuiCol_TextDisabled, + ImGuiCol_WindowBg, // Background of normal windows + ImGuiCol_ChildBg, // Background of child windows + ImGuiCol_PopupBg, // Background of popups, menus, tooltips windows + ImGuiCol_Border, + ImGuiCol_BorderShadow, + ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input + ImGuiCol_FrameBgHovered, + ImGuiCol_FrameBgActive, + ImGuiCol_TitleBg, + ImGuiCol_TitleBgActive, + ImGuiCol_TitleBgCollapsed, + ImGuiCol_MenuBarBg, + ImGuiCol_ScrollbarBg, + ImGuiCol_ScrollbarGrab, + ImGuiCol_ScrollbarGrabHovered, + ImGuiCol_ScrollbarGrabActive, + ImGuiCol_CheckMark, + ImGuiCol_SliderGrab, + ImGuiCol_SliderGrabActive, + ImGuiCol_Button, + ImGuiCol_ButtonHovered, + ImGuiCol_ButtonActive, + ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem + ImGuiCol_HeaderHovered, + ImGuiCol_HeaderActive, + ImGuiCol_Separator, + ImGuiCol_SeparatorHovered, + ImGuiCol_SeparatorActive, + ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows. + ImGuiCol_ResizeGripHovered, + ImGuiCol_ResizeGripActive, + ImGuiCol_Tab, // TabItem in a TabBar + ImGuiCol_TabHovered, + ImGuiCol_TabActive, + ImGuiCol_TabUnfocused, + ImGuiCol_TabUnfocusedActive, + ImGuiCol_PlotLines, + ImGuiCol_PlotLinesHovered, + ImGuiCol_PlotHistogram, + ImGuiCol_PlotHistogramHovered, + ImGuiCol_TableHeaderBg, // Table header background + ImGuiCol_TableBorderStrong, // Table outer and header borders (prefer using Alpha=1.0 here) + ImGuiCol_TableBorderLight, // Table inner borders (prefer using Alpha=1.0 here) + ImGuiCol_TableRowBg, // Table row background (even rows) + ImGuiCol_TableRowBgAlt, // Table row background (odd rows) + ImGuiCol_TextSelectedBg, + ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target + ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item + ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB + ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active + ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active + ImGuiCol_COUNT +}; + +// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure. +// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. +// During initialization or between frames, feel free to just poke into ImGuiStyle directly. +// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description. +// In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. +// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type. +enum ImGuiStyleVar_ +{ + // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions) + ImGuiStyleVar_Alpha, // float Alpha + ImGuiStyleVar_DisabledAlpha, // float DisabledAlpha + ImGuiStyleVar_WindowPadding, // ImVec2 WindowPadding + ImGuiStyleVar_WindowRounding, // float WindowRounding + ImGuiStyleVar_WindowBorderSize, // float WindowBorderSize + ImGuiStyleVar_WindowMinSize, // ImVec2 WindowMinSize + ImGuiStyleVar_WindowTitleAlign, // ImVec2 WindowTitleAlign + ImGuiStyleVar_ChildRounding, // float ChildRounding + ImGuiStyleVar_ChildBorderSize, // float ChildBorderSize + ImGuiStyleVar_PopupRounding, // float PopupRounding + ImGuiStyleVar_PopupBorderSize, // float PopupBorderSize + ImGuiStyleVar_FramePadding, // ImVec2 FramePadding + ImGuiStyleVar_FrameRounding, // float FrameRounding + ImGuiStyleVar_FrameBorderSize, // float FrameBorderSize + ImGuiStyleVar_ItemSpacing, // ImVec2 ItemSpacing + ImGuiStyleVar_ItemInnerSpacing, // ImVec2 ItemInnerSpacing + ImGuiStyleVar_IndentSpacing, // float IndentSpacing + ImGuiStyleVar_CellPadding, // ImVec2 CellPadding + ImGuiStyleVar_ScrollbarSize, // float ScrollbarSize + ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding + ImGuiStyleVar_GrabMinSize, // float GrabMinSize + ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_TabRounding, // float TabRounding + ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign + ImGuiStyleVar_SelectableRounding, // float SelectableRounding + ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize + ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign + ImGuiStyleVar_SeparatorTextPadding,// ImVec2 SeparatorTextPadding + ImGuiStyleVar_COUNT +}; + +// Flags for InvisibleButton() [extended in imgui_internal.h] +enum ImGuiButtonFlags_ +{ + ImGuiButtonFlags_None = 0, + ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default) + ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button + ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button + + // [Internal] + ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, + ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft, +}; + +// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() +enum ImGuiColorEditFlags_ +{ + ImGuiColorEditFlags_None = 0, + ImGuiColorEditFlags_NoAlpha = 1 << 1, // // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer). + ImGuiColorEditFlags_NoPicker = 1 << 2, // // ColorEdit: disable picker when clicking on color square. + ImGuiColorEditFlags_NoOptions = 1 << 3, // // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. + ImGuiColorEditFlags_NoSmallPreview = 1 << 4, // // ColorEdit, ColorPicker: disable color square preview next to the inputs. (e.g. to show only the inputs) + ImGuiColorEditFlags_NoInputs = 1 << 5, // // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview color square). + ImGuiColorEditFlags_NoTooltip = 1 << 6, // // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. + ImGuiColorEditFlags_NoLabel = 1 << 7, // // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). + ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. + ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. + ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) + ImGuiColorEditFlags_Round = 1 << 11, // // ColorButton: display round button [NOT NATIVE] + + // User Options (right-click on widget to change some of them). + ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. + ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. + ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). + ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. + ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " + ImGuiColorEditFlags_DisplayHex = 1 << 22, // [Display] // " + ImGuiColorEditFlags_Uint8 = 1 << 23, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255. + ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. + ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. + ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. + ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + + // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to + // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. + ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, + + // [Internal] Masks + ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, + ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, + ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, + ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, + + // Obsolete names + //ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] +}; + +// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. +// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigDragClickToInputText) +enum ImGuiSliderFlags_ +{ + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. + ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits) + ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget + ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + + // Obsolete names + //ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79] +}; + +// Identify a mouse button. +// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience. +enum ImGuiMouseButton_ +{ + ImGuiMouseButton_Left = 0, + ImGuiMouseButton_Right = 1, + ImGuiMouseButton_Middle = 2, + ImGuiMouseButton_COUNT = 5 +}; + +// Enumeration for GetMouseCursor() +// User code may request backend to display given cursor by calling SetMouseCursor(), which is why we have some cursors that are marked unused here +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_None = -1, + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, // When hovering over InputText, etc. + ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions) + ImGuiMouseCursor_ResizeNS, // When hovering over a horizontal border + ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column + ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window + ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window + ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. + ImGuiMouseCursor_COUNT +}; + +// Enumeration for AddMouseSourceEvent() actual source of Mouse Input data. +// Historically we use "Mouse" terminology everywhere to indicate pointer data, e.g. MousePos, IsMousePressed(), io.AddMousePosEvent() +// But that "Mouse" data can come from different source which occasionally may be useful for application to know about. +// You can submit a change of pointer type using io.AddMouseSourceEvent(). +enum ImGuiMouseSource : int +{ + ImGuiMouseSource_Mouse = 0, // Input is coming from an actual mouse. + ImGuiMouseSource_TouchScreen, // Input is coming from a touch screen (no hovering prior to initial press, less precise initial press aiming, dual-axis wheeling possible). + ImGuiMouseSource_Pen, // Input is coming from a pressure/magnetic pen (often used in conjunction with high-sampling rates). + ImGuiMouseSource_COUNT +}; + +// Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions +// Represent a condition. +// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always. +enum ImGuiCond_ +{ + ImGuiCond_None = 0, // No condition (always set the variable), same as _Always + ImGuiCond_Always = 1 << 0, // No condition (always set the variable), same as _None + ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) + ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) + ImGuiCond_Appearing = 1 << 3, // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) +}; + +//----------------------------------------------------------------------------- +// [SECTION] Helpers: Memory allocations macros, ImVector<> +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() +// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. +// Defining a custom placement new() with a custom parameter allows us to bypass including which on some platforms complains when user has disabled exceptions. +//----------------------------------------------------------------------------- + +struct ImNewWrapper {}; +inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } +inline void operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new() +#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) +#define IM_FREE(_PTR) ImGui::MemFree(_PTR) +#define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) +#define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE +template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } + +//----------------------------------------------------------------------------- +// ImVector<> +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +//----------------------------------------------------------------------------- +// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it. +// - We use std-like naming convention here, which is a little unusual for this codebase. +// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. +// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, +// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. +//----------------------------------------------------------------------------- + +IM_MSVC_RUNTIME_CHECKS_OFF +template +struct ImVector +{ + int Size; + int Capacity; + T* Data; + + // Provide standard typedefs but we don't use them ourselves. + typedef T value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + + // Constructors, destructor + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); if (src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything + + inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything + inline void clear_delete() { for (int n = 0; n < Size; n++) IM_DELETE(Data[n]); clear(); } // Important: never called automatically! always explicit. + inline void clear_destruct() { for (int n = 0; n < Size; n++) Data[n].~T(); clear(); } // Important: never called automatically! always explicit. + + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int size_in_bytes() const { return Size * (int)sizeof(T); } + inline int max_size() const { return 0x7FFFFFFF / (int)sizeof(T); } + inline int capacity() const { return Capacity; } + inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Data[i]; } + + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return Data + Size; } + inline const T* end() const { return Data + Size; } + inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline void shrink(int new_size) { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; } + inline void reserve_discard(int new_capacity) { if (new_capacity <= Capacity) return; if (Data) IM_FREE(Data); Data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); Capacity = new_capacity; } + + // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. + inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data + Size && it_last >= it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - (size_t)count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } + inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; } + inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; } + inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; } + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; } +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiStyle +//----------------------------------------------------------------------------- +// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame(). +// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, +// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors. +//----------------------------------------------------------------------------- + +struct ImGuiStyle +{ + float Alpha; // Global alpha applies to everything in Dear ImGui. + float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. + ImVec2 WindowPadding; // Padding within a window. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. + float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints(). + ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. + ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. + float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows. + float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding) + float PopupBorderSize; // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets). + float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets). + float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. + ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). + ImVec2 CellPadding; // Padding within a table cell + ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! + float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). + float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). + float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar. + float ScrollbarRounding; // Radius of grab corners for scrollbar. + float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. + float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + float TabBorderSize; // Thickness of border around tabs. + float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). + float SelectableRounding; // Radius of selectable/menuitem corners rounding. Set to 0.0f to have rectangular selection. + ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + float SeparatorTextBorderSize; // Thickkness of border in SeparatorText() + ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. + ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. + ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! + float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. + bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList). + bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. + float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + ImVec4 Colors[ImGuiCol_COUNT]; + + // Behaviors + // (It is possible to modify those fields mid-frame if specific behavior need it, unlike e.g. configuration fields in ImGuiIO) + float HoverStationaryDelay; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary. + float HoverDelayShort; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay. + float HoverDelayNormal; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayNormal). " + ImGuiHoveredFlags HoverFlagsForTooltipMouse;// Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. + ImGuiHoveredFlags HoverFlagsForTooltipNav; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. + + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiIO +//----------------------------------------------------------------------------- +// Communicate most settings and inputs/outputs to Dear ImGui using this structure. +// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage. +//----------------------------------------------------------------------------- + +// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. +// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. +struct ImGuiKeyData +{ + bool Down; // True for if key is down + float DownDuration; // Duration the key has been down (<0.0f: not pressed, 0.0f: just pressed, >0.0f: time held) + float DownDurationPrev; // Last frame duration the key has been down + float AnalogValue; // 0.0f..1.0f for gamepad values +}; + +struct ImGuiIO +{ + //------------------------------------------------------------------ + // Configuration // Default value + //------------------------------------------------------------------ + + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. + ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. + ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size). May change every frame. + float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. + float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. + const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. + const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). + void* UserData; // = NULL // Store your own data. + + ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. + float FontGlobalScale; // = 1.0f // Global scale all fonts + bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. + + // Miscellaneous options + bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. + bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). + bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. + float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. + + // Inputs Behaviors + // (other variables, ones which are expected to be tweaked within UI code, are exposed in ImGuiStyle) + float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. + float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. + float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. + float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. + + //------------------------------------------------------------------ + // Debug options + //------------------------------------------------------------------ + + // Tools to test correct Begin/End and BeginChild/EndChild behaviors. + // Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() + // This is inconsistent with other BeginXXX functions and create confusion for many users. + // We expect to update the API eventually. In the meanwhile we provide tools to facilitate checking user-code behavior. + bool ConfigDebugBeginReturnValueOnce;// = false // First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows. + bool ConfigDebugBeginReturnValueLoop;// = false // Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running. + + // Option to deactivate io.AddFocusEvent(false) handling. May facilitate interactions with a debugger when focus loss leads to clearing inputs data. + // Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them. + // Consider using e.g. Win32's IsDebuggerPresent() as an additional filter (or see ImOsIsDebuggerPresent() in imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). + bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys() in input processing. + + // Options to audit .ini data + bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) + + //------------------------------------------------------------------ + // Platform Functions + // (the imgui_impl_xxxx backend files are setting those up for you) + //------------------------------------------------------------------ + + // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff. + const char* BackendPlatformName; // = NULL + const char* BackendRendererName; // = NULL + void* BackendPlatformUserData; // = NULL // User data for platform backend + void* BackendRendererUserData; // = NULL // User data for renderer backend + void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend + + // Optional: Access OS clipboard + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) + // (default to use native imm32 api on Windows) + void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + void* ImeWindowHandle; // = NULL // [Obsolete] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. +#else + void* _UnusedPadding; // Unused field to keep data structure the same size. +#endif + + //------------------------------------------------------------------ + // Input - Call before calling NewFrame() + //------------------------------------------------------------------ + + // Input Functions + IMGUI_API void AddKeyEvent(ImGuiKey key, bool down); // Queue a new key down/up event. Key should be "translated" (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character) + IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend. + IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered) + IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change + IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left. + IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen) + IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) + IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input + IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate + IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue a new characters input from a UTF-8 string + + IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode. + IMGUI_API void SetAppAcceptingEvents(bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. + IMGUI_API void ClearEventsQueue(); // Clear all incoming events. + IMGUI_API void ClearInputKeys(); // Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + IMGUI_API void ClearInputCharacters(); // [Obsolete] Clear the current frame text input buffer. Now included within ClearInputKeys(). +#endif + + //------------------------------------------------------------------ + // Output - Updated by NewFrame() or EndFrame()/Render() + // (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is + // generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!) + //------------------------------------------------------------------ + + bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). + bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). + bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). + bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. + bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! + bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. + bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). + float Framerate; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally. + int MetricsRenderVertices; // Vertices output during last call to Render() + int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 + int MetricsRenderWindows; // Number of visible windows + int MetricsActiveWindows; // Number of active windows + int MetricsActiveAllocations; // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts. + ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta. + + // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. + // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). + // Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. + bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. + float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. +#endif + + //------------------------------------------------------------------ + // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! + //------------------------------------------------------------------ + + ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). + + // Main Input State + // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead) + // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) + ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.) + bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API. + float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll. + float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. + ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). + bool KeyCtrl; // Keyboard modifier down: Control + bool KeyShift; // Keyboard modifier down: Shift + bool KeyAlt; // Keyboard modifier down: Alt + bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows + + // Other state maintained from data above + IO function calls + ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame() + ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. + bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. + ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) + ImVec2 MouseClickedPos[5]; // Position at time of clicking + double MouseClickedTime[5]; // Time of last click (used to figure out double-click) + bool MouseClicked[5]; // Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0) + bool MouseDoubleClicked[5]; // Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2) + ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down + ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. + bool MouseReleased[5]; // Mouse button went from Down to !Down + bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. + bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. + bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. + float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) + float MouseDownDurationPrev[5]; // Previous time the mouse button has been down + float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) + float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. + bool AppFocusLost; // Only modify via AddFocusEvent() + bool AppAcceptingEvents; // Only modify via SetAppAcceptingEvents() + ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[] + bool BackendUsingLegacyNavInputArray; // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly + ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() + ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. + + IMGUI_API ImGuiIO(); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Misc data structures +//----------------------------------------------------------------------------- + +// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. +// The callback function should return 0 by default. +// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) +// - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration +// - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB +// - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows +// - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. +// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. +struct ImGuiInputTextCallbackData +{ + ImGuiContext* Ctx; // Parent UI context + ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only + ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only + void* UserData; // What user passed to InputText() // Read-only + + // Arguments for the different callback events + // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. + // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. + ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() + int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 + bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] + int CursorPos; // // Read-write // [Completion,History,Always] + int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection) + int SelectionEnd; // // Read-write // [Completion,History,Always] + + // Helper functions for text manipulation. + // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection. + IMGUI_API ImGuiInputTextCallbackData(); + IMGUI_API void DeleteChars(int pos, int bytes_count); + IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); + void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; } + void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } + bool HasSelection() const { return SelectionStart != SelectionEnd; } +}; + +// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). +// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. +struct ImGuiSizeCallbackData +{ + void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here (need reinterpret_cast<>). + ImVec2 Pos; // Read-only. Window position, for reference. + ImVec2 CurrentSize; // Read-only. Current window size. + ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. +}; + +// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() +struct ImGuiPayload +{ + // Members + void* Data; // Data (copied and owned by dear imgui) + int DataSize; // Data size + + // [Internal] + ImGuiID SourceId; // Source item id + ImGuiID SourceParentId; // Source parent id (if available) + int DataFrameCount; // Data timestamp + char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max) + bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets) + bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item. + + ImGuiPayload() { Clear(); } + void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; } + bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; } + bool IsPreview() const { return Preview; } + bool IsDelivery() const { return Delivery; } +}; + +// Sorting specification for one column of a table (sizeof == 12 bytes) +struct ImGuiTableColumnSortSpecs +{ + ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) + ImS16 ColumnIndex; // Index of the column + ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) + ImGuiSortDirection SortDirection : 8; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending (you can use this or SortSign, whichever is more convenient for your sort function) + + ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +// Sorting specifications for a table (often handling sort specs for a single column, occasionally more) +// Obtained by calling TableGetSortSpecs(). +// When 'SpecsDirty == true' you can sort your data. It will be true with sorting specs have changed since last call, or the first time. +// Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame! +struct ImGuiTableSortSpecs +{ + const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array. + int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled. + bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. + + ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) +//----------------------------------------------------------------------------- + +// Helper: Unicode defines +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). +#ifdef IMGUI_USE_WCHAR32 +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. +#else +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. +#endif + +// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within deep-nested code that runs multiple times every frame. +// Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); +struct ImGuiOnceUponAFrame +{ + ImGuiOnceUponAFrame() { RefFrame = -1; } + mutable int RefFrame; + operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } +}; + +// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" +struct ImGuiTextFilter +{ + IMGUI_API ImGuiTextFilter(const char* default_filter = ""); + IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const; + IMGUI_API void Build(); + void Clear() { InputBuf[0] = 0; Build(); } + bool IsActive() const { return !Filters.empty(); } + + // [Internal] + struct ImGuiTextRange + { + const char* b; + const char* e; + + ImGuiTextRange() { b = e = NULL; } + ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; } + bool empty() const { return b == e; } + IMGUI_API void split(char separator, ImVector* out) const; + }; + char InputBuf[256]; + ImVectorFilters; + int CountGrep; +}; + +// Helper: Growable text buffer for logging/accumulating text +// (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder') +struct ImGuiTextBuffer +{ + ImVector Buf; + IMGUI_API static char EmptyString[1]; + + ImGuiTextBuffer() { } + inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } + const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } + const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } + bool empty() const { return Buf.Size <= 1; } + void clear() { Buf.clear(); } + void reserve(int capacity) { Buf.reserve(capacity); } + const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } + IMGUI_API void append(const char* str, const char* str_end = NULL); + IMGUI_API void appendf(const char* fmt, ...) IM_FMTARGS(2); + IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2); +}; + +// Helper: Key->Value storage +// Typically you don't have to worry about this since a storage is held within each Window. +// We use it to e.g. store collapse state for a tree (Int 0/1) +// This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) +// You can use it as custom user storage for temporary values. Declare your own storage if, for example: +// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). +// - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) +// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. +struct ImGuiStorage +{ + // [Internal] + struct ImGuiStoragePair + { + ImGuiID key; + union { int val_i; float val_f; void* val_p; }; + ImGuiStoragePair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } + ImGuiStoragePair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } + ImGuiStoragePair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } + }; + + ImVector Data; + + // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) + // - Set***() functions find pair, insertion on demand if missing. + // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. + void Clear() { Data.clear(); } + IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; + IMGUI_API void SetInt(ImGuiID key, int val); + IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; + IMGUI_API void SetBool(ImGuiID key, bool val); + IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; + IMGUI_API void SetFloat(ImGuiID key, float val); + IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL + IMGUI_API void SetVoidPtr(ImGuiID key, void* val); + + // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set. + // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. + // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct) + // float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar; + IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0); + IMGUI_API bool* GetBoolRef(ImGuiID key, bool default_val = false); + IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0.0f); + IMGUI_API void** GetVoidPtrRef(ImGuiID key, void* default_val = NULL); + + // Use on your own storage if you know only integer are being stored (open/close all tree nodes) + IMGUI_API void SetAllInt(int val); + + // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + IMGUI_API void BuildSortByKey(); +}; + +// Helper: Manually clip large list of items. +// If you have lots evenly spaced items and you have random access to the list, you can perform coarse +// clipping based on visibility to only submit items that are in view. +// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped. +// (Dear ImGui already clip items based on their bounds but: it needs to first layout the item to do so, and generally +// fetching/submitting your own data incurs additional cost. Coarse clipping using ImGuiListClipper allows you to easily +// scale using lists with tens of thousands of items without a problem) +// Usage: +// ImGuiListClipper clipper; +// clipper.Begin(1000); // We have 1000 elements, evenly spaced. +// while (clipper.Step()) +// for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) +// ImGui::Text("line number %d", i); +// Generally what happens is: +// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not. +// - User code submit that one element. +// - Clipper can measure the height of the first element +// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element. +// - User code submit visible elements. +// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. +struct ImGuiListClipper +{ + ImGuiContext* Ctx; // Parent UI context + int DisplayStart; // First item to display, updated by each call to Step() + int DisplayEnd; // End of items to display (exclusive) + int ItemsCount; // [Internal] Number of items + float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it + float StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed + void* TempData; // [Internal] Internal data + + // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step) + // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). + IMGUI_API ImGuiListClipper(); + IMGUI_API ~ImGuiListClipper(); + IMGUI_API void Begin(int items_count, float items_height = -1.0f); + IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. + IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. + + // Call IncludeRangeByIndices() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility. + // (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range). + IMGUI_API void IncludeRangeByIndices(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped. + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeRangeByIndices(item_begin, item_end); } // [renamed in 1.89.6] + //inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] +#endif +}; + +// Helpers: ImVec2/ImVec4 operators +// - It is important that we are keeping those disabled by default so they don't leak in user space. +// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) +// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. +#ifdef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED +IM_MSVC_RUNTIME_CHECKS_OFF +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + +// Helpers macros to generate 32-bit encoded colors +// User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. +#ifndef IM_COL32_R_SHIFT +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#endif +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)<> IM_COL32_R_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * (1.0f / 255.0f), (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * (1.0f / 255.0f)) {} + inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); } + inline operator ImVec4() const { return Value; } + + // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers. + inline void SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; } + static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) +// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList. +//----------------------------------------------------------------------------- + +// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. +#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) +#endif + +// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] +// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, +// you can poke into the draw list for that! Draw callback may be useful for example to: +// A) Change your GPU render state, +// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc. +// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }' +// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering backend accordingly. +#ifndef ImDrawCallback +typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd); +#endif + +// Special Draw callback value to request renderer backend to reset the graphics/render state. +// The renderer backend needs to handle this special value, otherwise it will crash trying to call a function at this address. +// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored. +// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call). +#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) + +// Typically, 1 command = 1 GPU draw call (unless command is a callback) +// - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, +// this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// Backends made for <1.71. will typically ignore the VtxOffset fields. +// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). +struct ImDrawCmd +{ + ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates + ImTextureID TextureId; // 4-8 // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. + unsigned int IdxOffset; // 4 // Start offset in index buffer. + unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. + ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. + void* UserCallbackData; // 4-8 // The draw callback code can access this. + + ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed + + // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) + inline ImTextureID GetTexID() const { return TextureId; } +}; + +// Vertex layout +#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT +struct ImDrawVert +{ + ImVec2 pos; + ImVec2 uv; + ImU32 col; +}; +#else +// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h +// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine. +// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared at the time you'd want to set your type up. +// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. +IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; +#endif + +// [Internal] For use by ImDrawList +struct ImDrawCmdHeader +{ + ImVec4 ClipRect; + ImTextureID TextureId; + unsigned int VtxOffset; +}; + +// [Internal] For use by ImDrawListSplitter +struct ImDrawChannel +{ + ImVector _CmdBuffer; + ImVector _IdxBuffer; +}; + + +// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. +// This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. +struct ImDrawListSplitter +{ + int _Current; // Current channel number (0) + int _Count; // Number of active channels (1+) + ImVector _Channels; // Draw channels (not resized down so _Count might be < Channels.Size) + + inline ImDrawListSplitter() { memset(this, 0, sizeof(*this)); } + inline ~ImDrawListSplitter() { ClearFreeMemory(); } + inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame + IMGUI_API void ClearFreeMemory(); + IMGUI_API void Split(ImDrawList* draw_list, int count); + IMGUI_API void Merge(ImDrawList* draw_list); + IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx); +}; + +// Flags for ImDrawList functions +// (Legacy: bit 0 must always correspond to ImDrawFlags_Closed to be backward compatible with old API using a bool. Bits 1..3 must be unused) +enum ImDrawFlags_ +{ + ImDrawFlags_None = 0, + ImDrawFlags_Closed = 1 << 0, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason) + ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01. + ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02. + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04. + ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08. + ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! + ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, + ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified. + ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone, +}; + +// Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. +// It is however possible to temporarily alter flags between calls to ImDrawList:: functions. +enum ImDrawListFlags_ +{ + ImDrawListFlags_None = 0, + ImDrawListFlags_AntiAliasedLines = 1 << 0, // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles) + ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). + ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). + ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. +}; + +// Draw command list +// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame, +// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. +// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to +// access the current window draw list and draw custom primitives. +// You can interleave normal ImGui:: calls and adding primitives to the current draw list. +// In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). +// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) +// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. +struct ImDrawList +{ + // This is what you have to render + ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. + ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those + ImVector VtxBuffer; // Vertex buffer. + ImDrawListFlags Flags; // Flags, you may poke into these to adjust anti-aliasing settings per-primitive. + + // [Internal, used while building lists] + unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. + ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) + const char* _OwnerName; // Pointer to owner window's name for debugging + ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) + ImVector _ClipRectStack; // [Internal] + ImVector _TextureIdStack; // [Internal] + ImVector _Path; // [Internal] current path building + ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). + ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) + float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content + + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) + ImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } + + ~ImDrawList() { _ClearFreeMemory(); } + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) + IMGUI_API void PushClipRectFullScreen(); + IMGUI_API void PopClipRect(); + IMGUI_API void PushTextureID(ImTextureID texture_id); + IMGUI_API void PopTextureID(); + inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } + inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } + + // Primitives + // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. + // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners. + // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred). + // In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12. + // In future versions we will use textures to provide cheaper and higher-quality circles. + // Use AddNgon() and AddNgonFilled() functions if you need to guarantee a specific number of sides. + IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0); // a: upper-left, b: lower-right (== upper-left + size) + IMGUI_API void AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left); + IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col); + IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f); + IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col); + IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f); + IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0); + IMGUI_API void AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); + IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); + IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); + IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness); + IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); + IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) + + // Image primitives + // - Read FAQ to understand what ImTextureID is. + // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. + // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. + IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); + + // Stateful path API, add points then finish with PathFillConvex() or PathStroke() + // - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. + inline void PathClear() { _Path.Size = 0; } + inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); } + inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } + inline void PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0; } + IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 0); + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) + IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0); + + // Advanced + IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. + IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible + IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. + + // Advanced: Channels + // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) + // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) + // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! + // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. + // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. + inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } + inline void ChannelsMerge() { _Splitter.Merge(this); } + inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } + + // Advanced: Primitives allocations + // - We render triangles (three vertices) + // - All primitives needs to be reserved via PrimReserve() beforehand. + IMGUI_API void PrimReserve(int idx_count, int vtx_count); + IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); + IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) + IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); + IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); + inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } + inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index + + // Obsolete names + //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + + // [Internal helpers] + IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _ClearFreeMemory(); + IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _TryMergeDrawCmds(); + IMGUI_API void _OnChangedClipRect(); + IMGUI_API void _OnChangedTextureID(); + IMGUI_API void _OnChangedVtxOffset(); + IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; + IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); + IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); +}; + +// All draw data to render a Dear ImGui frame +// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose, +// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList) +struct ImDrawData +{ + bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. + int CmdListsCount; // Number of ImDrawList* to render (should always be == CmdLists.size) + int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size + int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. + ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) + ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. + ImGuiViewport* OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). + + // Functions + ImDrawData() { Clear(); } + IMGUI_API void Clear(); + IMGUI_API void AddDrawList(ImDrawList* draw_list); // Helper to add an external draw list into an existing ImDrawData. + IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! + IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. +}; + +//----------------------------------------------------------------------------- +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) +//----------------------------------------------------------------------------- + +struct ImFontConfig +{ + void* FontData; // // TTF/OTF data + int FontDataSize; // // TTF/OTF data size + bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + int FontNo; // 0 // Index of font within TTF/OTF file + float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). + int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. + bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. + ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. + const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). + float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font + float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. + unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. + float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. + ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + + // [Internal] + char Name[40]; // Name (strictly to ease debugging) + ImFont* DstFont; + + IMGUI_API ImFontConfig(); +}; + +// Hold rendering data for one glyph. +// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) +struct ImFontGlyph +{ + unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) + unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + unsigned int Codepoint : 30; // 0x0000..0x10FFFF + float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float X0, Y0, X1, Y1; // Glyph corners + float U0, V0, U1, V1; // Texture coordinates +}; + +// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. +struct ImFontGlyphRangesBuilder +{ + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + + ImFontGlyphRangesBuilder() { Clear(); } + inline void Clear() { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); } + inline bool GetBit(size_t n) const { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + inline void SetBit(size_t n) { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array + inline void AddChar(ImWchar c) { SetBit(c); } // Add character + IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) + IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext + IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges +}; + +// See ImFontAtlas::AddCustomRectXXX functions. +struct ImFontAtlasCustomRect +{ + unsigned short Width, Height; // Input // Desired rectangle dimension + unsigned short X, Y; // Output // Packed position in Atlas + unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) + float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset + ImFont* Font; // Input // For custom font glyphs only: target font + ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } + bool IsPacked() const { return X != 0xFFFF; } +}; + +// Flags for ImFontAtlas build +enum ImFontAtlasFlags_ +{ + ImFontAtlasFlags_None = 0, + ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0, // Don't round the height to next power of two + ImFontAtlasFlags_NoMouseCursors = 1 << 1, // Don't build software mouse cursors into the atlas (save a little texture memory) + ImFontAtlasFlags_NoBakedLines = 1 << 2, // Don't build thick line textures into the atlas (save a little texture memory, allow support for point/nearest filtering). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU). +}; + +// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding: +// - One or more fonts. +// - Custom graphics data needed to render the shapes needed by Dear ImGui. +// - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). +// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api. +// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. +// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. +// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) +// - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. +// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. +// Common pitfalls: +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. +// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. +// You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, +// - Even though many functions are suffixed with "TTF", OTF data is supported just as well. +// - This is an old API and it is currently awkward for those and various other reasons! We will address them in the future! +struct ImFontAtlas +{ + IMGUI_API ImFontAtlas(); + IMGUI_API ~ImFontAtlas(); + IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); + IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); + IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); + IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. + IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. + IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). + IMGUI_API void Clear(); // Clear all input and output. + + // Build atlas, retrieve pixel data. + // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // The pitch is always = Width * BytesPerPixels (1 or 4) + // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... + void SetTexID(ImTextureID id) { TexID = id; } + + //------------------------------------------- + // Glyph Ranges + //------------------------------------------- + + // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) + // NB: Make sure that your string are UTF-8 and NOT in your local code page. + // Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details. + // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. + IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin + IMGUI_API const ImWchar* GetGlyphRangesGreek(); // Default + Greek and Coptic + IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters + IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseFull(); // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese + IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters + IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters + IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters + + //------------------------------------------- + // [BETA] Custom Rectangles/Glyphs API + //------------------------------------------- + + // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. + // - After calling Build(), you can query the rectangle position and render your pixels. + // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of prefered texture format. + // - You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), + // so you can render e.g. custom colorful icons and use them as regular glyphs. + // - Read docs/FONTS.md for more details about using colorful icons. + // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. + IMGUI_API int AddCustomRectRegular(int width, int height); + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + ImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; } + + // [Internal] + IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; + IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); + + //------------------------------------------- + // Members + //------------------------------------------- + + ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) + ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). + + // [Internal] + // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + bool TexReady; // Set when texture was built matching current font input + bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. + unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight + unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + int TexWidth; // Texture width calculated during Build(). + int TexHeight; // Texture height calculated during Build(). + ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. + ImVector ConfigData; // Configuration data + ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines + + // [Internal] Font builder + const ImFontBuilderIO* FontBuilderIO; // Opaque interface to a font builder (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). + unsigned int FontBuilderFlags; // Shared flags (for all fonts) for custom font builder. THIS IS BUILD IMPLEMENTATION DEPENDENT. Per-font override is also available in ImFontConfig. + + // [Internal] Packing data + int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors + int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines + + // [Obsolete] + //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ +}; + +// Font runtime data and rendering +// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). +struct ImFont +{ + // Members: Hot ~20/24 bytes (for CalcTextSize) + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). + float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX + float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) + + // Members: Hot ~28/40 bytes (for CalcTextSize + render loop) + ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // // All glyphs. + const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + + // Members: Cold ~32/40 bytes + ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into + const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData + short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. + ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. + short EllipsisCharCount; // 1 // out // 1 or 3 + float EllipsisWidth; // 4 // out // Width + float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 + bool DirtyLookupTables; // 1 // out // + float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] + int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + + // Methods + IMGUI_API ImFont(); + IMGUI_API ~ImFont(); + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; + IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + bool IsLoaded() const { return ContainerAtlas != NULL; } + const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + + // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. + // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + + // [Internal] Don't use! + IMGUI_API void BuildLookupTable(); + IMGUI_API void ClearOutputData(); + IMGUI_API void GrowIndex(int new_size); + IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); + IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. + IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); + IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Viewports +//----------------------------------------------------------------------------- + +// Flags stored in ImGuiViewport::Flags, giving indications to the platform backends. +enum ImGuiViewportFlags_ +{ + ImGuiViewportFlags_None = 0, + ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window + ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) + ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: is created/managed by the application (rather than a dear imgui backend) +}; + +// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. +// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. +// - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. +// - About Main Area vs Work Area: +// - Main Area = entire viewport. +// - Work Area = entire viewport minus sections used by main menu bars (for platform windows), or by task bar (for platform monitor). +// - Windows are generally trying to stay within the Work Area of their host viewport. +struct ImGuiViewport +{ + ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ + ImVec2 Pos; // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) + ImVec2 Size; // Main Area: Size of the viewport. + ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) + ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) + + // Platform/Backend Dependent Data + void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms) + + ImGuiViewport() { memset(this, 0, sizeof(*this)); } + + // Helpers + ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } + ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Platform Dependent Interfaces +//----------------------------------------------------------------------------- + +// (Optional) Support for IME (Input Method Editor) via the io.SetPlatformImeDataFn() function. +struct ImGuiPlatformImeData +{ + bool WantVisible; // A widget wants the IME to be visible + ImVec2 InputPos; // Position of the input cursor + float InputLineHeight; // Line height + + ImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Obsolete functions and types +// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) +// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead. +//----------------------------------------------------------------------------- + +namespace ImGui +{ +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // map ImGuiKey_* values into legacy native key index. == io.KeyMap[key] +#else + static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END && "ImGuiKey and native_index was merged together and native_index is disabled by IMGUI_DISABLE_OBSOLETE_KEYIO. Please switch to ImGuiKey."); return key; } +#endif +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +namespace ImGui +{ + // OBSOLETED in 1.89.7 (from June 2023) + IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item. + // OBSOLETED in 1.89.4 (from March 2023) + static inline void PushAllowKeyboardFocus(bool tab_stop) { PushTabStop(tab_stop); } + static inline void PopAllowKeyboardFocus() { PopTabStop(); } + // OBSOLETED in 1.89 (from August 2022) + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding) + // OBSOLETED in 1.88 (from May 2022) + static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. + static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. + // OBSOLETED in 1.86 (from November 2021) + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Calculate coarse clipping for large list of evenly sized items. Prefer using ImGuiListClipper. + // OBSOLETED in 1.85 (from August 2021) + static inline float GetWindowContentRegionWidth() { return GetWindowContentRegionMax().x - GetWindowContentRegionMin().x; } + + // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) + //-- OBSOLETED in 1.81 (from February 2021) + //static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + //static inline bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1) { float height = GetTextLineHeightWithSpacing() * ((height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f) + GetStyle().FramePadding.y * 2.0f; return BeginListBox(label, ImVec2(0.0f, height)); } // Helper to calculate size from items_count and height_in_items + //static inline void ListBoxFooter() { EndListBox(); } + //-- OBSOLETED in 1.79 (from August 2020) + //static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! + //-- OBSOLETED in 1.78 (from June 2020): Old drag/sliders functions that took a 'float power > 1.0f' argument instead of ImGuiSliderFlags_Logarithmic. See github.com/ocornut/imgui/issues/3361 for details. + //IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power = 1.0f) // OBSOLETED in 1.78 (from June 2020) + //IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power = 1.0f); // OBSOLETED in 1.78 (from June 2020) + //IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power = 1.0f); // OBSOLETED in 1.78 (from June 2020) + //IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power = 1.0f); // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power = 1.0f) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //static inline bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power = 1.0f) { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } // OBSOLETED in 1.78 (from June 2020) + //-- OBSOLETED in 1.77 and before + //static inline bool BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); } // OBSOLETED in 1.77 (from June 2020) + //static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); } // OBSOLETED in 1.72 (from July 2019) + //static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); } // OBSOLETED in 1.71 (from June 2019) + //static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; } // OBSOLETED in 1.70 (from May 2019) + //static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); } // OBSOLETED in 1.69 (from Mar 2019) + //static inline void SetScrollHere(float ratio = 0.5f) { SetScrollHereY(ratio); } // OBSOLETED in 1.66 (from Nov 2018) + //static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); } // OBSOLETED in 1.63 (from Aug 2018) + //-- OBSOLETED in 1.60 and before + //static inline bool IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } // OBSOLETED in 1.60 (from Apr 2018) + //static inline bool IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018) + //static inline void ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) + //IMGUI_API bool Begin(char* name, bool* p_open, ImVec2 size_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags=0); // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017): Equivalent of using SetNextWindowSize(size, ImGuiCond_FirstUseEver) and SetNextWindowBgAlpha(). + //static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + //static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + //static inline void SetNextWindowPosCenter(ImGuiCond c=0) { SetNextWindowPos(GetMainViewport()->GetCenter(), c, ImVec2(0.5f,0.5f)); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017) + //static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + //static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017): This was misleading and partly broken. You probably want to use the io.WantCaptureMouse flag instead. + //static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + //static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017) + //-- OBSOLETED in 1.50 and before + //static inline bool CollapsingHeader(char* label, const char* str_id, bool framed = true, bool default_open = false) { return CollapsingHeader(label, (default_open ? (1 << 5) : 0)); } // OBSOLETED in 1.49 + //static inline ImFont*GetWindowFont() { return GetFont(); } // OBSOLETED in 1.48 + //static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETED in 1.48 + //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 +} + +// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() +typedef ImDrawFlags ImDrawCornerFlags; +enum ImDrawCornerFlags_ +{ + ImDrawCornerFlags_None = ImDrawFlags_RoundCornersNone, // Was == 0 prior to 1.82, this is now == ImDrawFlags_RoundCornersNone which is != 0 and not implicit + ImDrawCornerFlags_TopLeft = ImDrawFlags_RoundCornersTopLeft, // Was == 0x01 (1 << 0) prior to 1.82. Order matches ImDrawFlags_NoRoundCorner* flag (we exploit this internally). + ImDrawCornerFlags_TopRight = ImDrawFlags_RoundCornersTopRight, // Was == 0x02 (1 << 1) prior to 1.82. + ImDrawCornerFlags_BotLeft = ImDrawFlags_RoundCornersBottomLeft, // Was == 0x04 (1 << 2) prior to 1.82. + ImDrawCornerFlags_BotRight = ImDrawFlags_RoundCornersBottomRight, // Was == 0x08 (1 << 3) prior to 1.82. + ImDrawCornerFlags_All = ImDrawFlags_RoundCornersAll, // Was == 0x0F prior to 1.82 + ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight, + ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight, + ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft, + ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight, +}; + +// RENAMED and MERGED both ImGuiKey_ModXXX and ImGuiModFlags_XXX into ImGuiMod_XXX (from September 2022) +// RENAMED ImGuiKeyModFlags -> ImGuiModFlags in 1.88 (from April 2022). Exceptionally commented out ahead of obscolescence schedule to reduce confusion and because they were not meant to be used in the first place. +typedef ImGuiKeyChord ImGuiModFlags; // == int. We generally use ImGuiKeyChord to mean "a ImGuiKey or-ed with any number of ImGuiMod_XXX value", but you may store only mods in there. +enum ImGuiModFlags_ { ImGuiModFlags_None = 0, ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, ImGuiModFlags_Super = ImGuiMod_Super }; +//typedef ImGuiKeyChord ImGuiKeyModFlags; // == int +//enum ImGuiKeyModFlags_ { ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super }; + +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +// RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022) +#if defined(IMGUI_DISABLE_METRICS_WINDOW) && !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS) +#define IMGUI_DISABLE_DEBUG_TOOLS +#endif +#if defined(IMGUI_DISABLE_METRICS_WINDOW) && defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) +#error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name. +#endif + +//----------------------------------------------------------------------------- + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +// Include imgui_user.h at the end of imgui.h (convenient for user to only explicitly include vanilla imgui.h) +#ifdef IMGUI_INCLUDE_IMGUI_USER_H +#include "imgui_user.h" +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_draw.cpp b/Amalgam/include/ImGui/imgui_draw.cpp new file mode 100644 index 0000000..44371f8 --- /dev/null +++ b/Amalgam/include/ImGui/imgui_draw.cpp @@ -0,0 +1,4232 @@ +// dear imgui, v1.89.8 +// (drawing and font code) + +/* + +Index of this file: + +// [SECTION] STB libraries implementation +// [SECTION] Style functions +// [SECTION] ImDrawList +// [SECTION] ImDrawListSplitter +// [SECTION] ImDrawData +// [SECTION] Helpers ShadeVertsXXX functions +// [SECTION] ImFontConfig +// [SECTION] ImFontAtlas +// [SECTION] ImFontAtlas glyph ranges helpers +// [SECTION] ImFontGlyphRangesBuilder +// [SECTION] ImFont +// [SECTION] ImGui Internal Render Helpers +// [SECTION] Decompression code +// [SECTION] Default font data (ProggyClean.ttf) + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_internal.h" +#ifdef IMGUI_ENABLE_FREETYPE +#include "misc/freetype/imgui_freetype.h" +#endif + +#include // vsnprintf, sscanf, printf + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok. +#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wcomma" // warning: possible misuse of comma operator here +#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack) +//------------------------------------------------------------------------- + +// Compile time options: +//#define IMGUI_STB_NAMESPACE ImStb +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION + +#ifdef IMGUI_STB_NAMESPACE +namespace IMGUI_STB_NAMESPACE +{ +#endif + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration +#pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'. +#pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read. +#pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did. +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier +#endif + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#endif + +#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in another compilation unit +#define STBRP_STATIC +#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) +#define STBRP_SORT ImQsort +#define STB_RECT_PACK_IMPLEMENTATION +#endif +#ifdef IMGUI_STB_RECT_PACK_FILENAME +#include IMGUI_STB_RECT_PACK_FILENAME +#else +#include "imstb_rectpack.h" +#endif +#endif + +#ifdef IMGUI_ENABLE_STB_TRUETYPE +#ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) +#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in another compilation unit +#define STBTT_malloc(x,u) ((void)(u), IM_ALLOC(x)) +#define STBTT_free(x,u) ((void)(u), IM_FREE(x)) +#define STBTT_assert(x) do { IM_ASSERT(x); } while(0) +#define STBTT_fmod(x,y) ImFmod(x,y) +#define STBTT_sqrt(x) ImSqrt(x) +#define STBTT_pow(x,y) ImPow(x,y) +#define STBTT_fabs(x) ImFabs(x) +#define STBTT_ifloor(x) ((int)ImFloorSigned(x)) +#define STBTT_iceil(x) ((int)ImCeil(x)) +#define STBTT_STATIC +#define STB_TRUETYPE_IMPLEMENTATION +#else +#define STBTT_DEF extern +#endif +#ifdef IMGUI_STB_TRUETYPE_FILENAME +#include IMGUI_STB_TRUETYPE_FILENAME +#else +#include "imstb_truetype.h" +#endif +#endif +#endif // IMGUI_ENABLE_STB_TRUETYPE + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif + +#ifdef IMGUI_STB_NAMESPACE +} // namespace ImStb +using namespace IMGUI_STB_NAMESPACE; +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Style functions +//----------------------------------------------------------------------------- + +void ImGui::StyleColorsDark(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); + colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = colors[ImGuiCol_Border]; + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); +} + +void ImGui::StyleColorsClassic(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f); + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.27f, 0.27f, 0.38f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.45f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +// Those light colors are better suited with a thicker font than the default one + FrameBorder +void ImGui::StyleColorsLight(ImGuiStyle* dst) +{ + ImGuiStyle* style = dst ? dst : &ImGui::GetStyle(); + ImVec4* colors = style->Colors; + + colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f); + colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f); + colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); + colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); + colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); + colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f); + colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); + colors[ImGuiCol_TableHeaderBg] = ImVec4(0.78f, 0.87f, 0.98f, 1.00f); + colors[ImGuiCol_TableBorderStrong] = ImVec4(0.57f, 0.57f, 0.64f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here + colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawList +//----------------------------------------------------------------------------- + +ImDrawListSharedData::ImDrawListSharedData() +{ + memset(this, 0, sizeof(*this)); + for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) + { + const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); + ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); + } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); +} + +void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) +{ + if (CircleSegmentMaxError == max_error) + return; + + IM_ASSERT(max_error > 0.0f); + CircleSegmentMaxError = max_error; + for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) + { + const float radius = (float)i; + CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX); + } + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); +} + +// Initialize before use in a new frame. We always have a command ready in the buffer. +void ImDrawList::_ResetForNewFrame() +{ + // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); + IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + if (_Splitter._Count > 1) + _Splitter.Merge(this); + + CmdBuffer.resize(0); + IdxBuffer.resize(0); + VtxBuffer.resize(0); + Flags = _Data->InitialFlags; + memset(&_CmdHeader, 0, sizeof(_CmdHeader)); + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.resize(0); + _TextureIdStack.resize(0); + _Path.resize(0); + _Splitter.Clear(); + CmdBuffer.push_back(ImDrawCmd()); + _FringeScale = 1.0f; +} + +void ImDrawList::_ClearFreeMemory() +{ + CmdBuffer.clear(); + IdxBuffer.clear(); + VtxBuffer.clear(); + Flags = ImDrawListFlags_None; + _VtxCurrentIdx = 0; + _VtxWritePtr = NULL; + _IdxWritePtr = NULL; + _ClipRectStack.clear(); + _TextureIdStack.clear(); + _Path.clear(); + _Splitter.ClearFreeMemory(); +} + +ImDrawList* ImDrawList::CloneOutput() const +{ + ImDrawList* dst = IM_NEW(ImDrawList(_Data)); + dst->CmdBuffer = CmdBuffer; + dst->IdxBuffer = IdxBuffer; + dst->VtxBuffer = VtxBuffer; + dst->Flags = Flags; + return dst; +} + +void ImDrawList::AddDrawCmd() +{ + ImDrawCmd draw_cmd; + draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() + draw_cmd.TextureId = _CmdHeader.TextureId; + draw_cmd.VtxOffset = _CmdHeader.VtxOffset; + draw_cmd.IdxOffset = IdxBuffer.Size; + + IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); + CmdBuffer.push_back(draw_cmd); +} + +// Pop trailing draw command (used before merging or presenting to user) +// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL +void ImDrawList::_PopUnusedDrawCmd() +{ + while (CmdBuffer.Size > 0) + { + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) + return;// break; + CmdBuffer.pop_back(); + } +} + +void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) +{ + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + IM_ASSERT(curr_cmd->UserCallback == NULL); + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + } + curr_cmd->UserCallback = callback; + curr_cmd->UserCallbackData = callback_data; + + AddDrawCmd(); // Force a new command after us (see comment below) +} + +// Compare ClipRect, TextureId and VtxOffset with a single memcmp() +#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset +#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset) + +// Try to merge two last draw commands +void ImDrawList::_TryMergeDrawCmds() +{ + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL) + { + prev_cmd->ElemCount += curr_cmd->ElemCount; + CmdBuffer.pop_back(); + } +} + +// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. +// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. +void ImDrawList::_OnChangedClipRect() +{ + // If current command is used with different settings we need to add a new command + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) + { + CmdBuffer.pop_back(); + return; + } + + curr_cmd->ClipRect = _CmdHeader.ClipRect; +} + +void ImDrawList::_OnChangedTextureID() +{ + // If current command is used with different settings we need to add a new command + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + + // Try to merge with previous command if it matches, else use current command + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL) + { + CmdBuffer.pop_back(); + return; + } + + curr_cmd->TextureId = _CmdHeader.TextureId; +} + +void ImDrawList::_OnChangedVtxOffset() +{ + // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this. + _VtxCurrentIdx = 0; + IM_ASSERT_PARANOID(CmdBuffer.Size > 0); + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349 + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + curr_cmd->VtxOffset = _CmdHeader.VtxOffset; +} + +int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const +{ + // Automatic segment count + const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy + if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) + return _Data->CircleSegmentCounts[radius_idx]; // Use cached value + else + return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); +} + +// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) +void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect) +{ + ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); + if (intersect_with_current_clip_rect) + { + ImVec4 current = _CmdHeader.ClipRect; + if (cr.x < current.x) cr.x = current.x; + if (cr.y < current.y) cr.y = current.y; + if (cr.z > current.z) cr.z = current.z; + if (cr.w > current.w) cr.w = current.w; + } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); + + _ClipRectStack.push_back(cr); + _CmdHeader.ClipRect = cr; + _OnChangedClipRect(); +} + +void ImDrawList::PushClipRectFullScreen() +{ + PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); +} + +void ImDrawList::PopClipRect() +{ + _ClipRectStack.pop_back(); + _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; + _OnChangedClipRect(); +} + +void ImDrawList::PushTextureID(ImTextureID texture_id) +{ + _TextureIdStack.push_back(texture_id); + _CmdHeader.TextureId = texture_id; + _OnChangedTextureID(); +} + +void ImDrawList::PopTextureID() +{ + _TextureIdStack.pop_back(); + _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; + _OnChangedTextureID(); +} + +// Reserve space for a number of vertices and indices. +// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or +// submit the intermediate results. PrimUnreserve() can be used to release unused allocations. +void ImDrawList::PrimReserve(int idx_count, int vtx_count) +{ + // Large mesh support (when enabled) + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) + { + // FIXME: In theory we should be testing that vtx_count <64k here. + // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us + // to not make that check until we rework the text functions to handle clipping and large horizontal lines better. + _CmdHeader.VtxOffset = VtxBuffer.Size; + _OnChangedVtxOffset(); + } + + ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd->ElemCount += idx_count; + + int vtx_buffer_old_size = VtxBuffer.Size; + VtxBuffer.resize(vtx_buffer_old_size + vtx_count); + _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size; + + int idx_buffer_old_size = IdxBuffer.Size; + IdxBuffer.resize(idx_buffer_old_size + idx_count); + _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size; +} + +// Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve(). +void ImDrawList::PrimUnreserve(int idx_count, int vtx_count) +{ + IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); + + ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + draw_cmd->ElemCount -= idx_count; + VtxBuffer.shrink(VtxBuffer.Size - vtx_count); + IdxBuffer.shrink(IdxBuffer.Size - idx_count); +} + +// Fully unrolled with inline call to keep our debug builds decently fast. +void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col) +{ + ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y); + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col) +{ + ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; + _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); + _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); + _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + _VtxCurrentIdx += 4; + _IdxWritePtr += 6; +} + +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds. +// - Those macros expects l-values and need to be used as their own statement. +// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0 +#define IM_FIXNORMAL2F_MAX_INVLEN2 100.0f // 500.0f (see #4053, #3366) +#define IM_FIXNORMAL2F(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0 + +// TODO: Thickness anti-aliased lines cap are missing their AA fringe. +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. +void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness) +{ + if (points_count < 2 || (col & IM_COL32_A_MASK) == 0) + return; + + const bool closed = (flags & ImDrawFlags_Closed) != 0; + const ImVec2 opaque_uv = _Data->TexUvWhitePixel; + const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw + const bool thick_line = (thickness > _FringeScale); + + if (Flags & ImDrawListFlags_AntiAliasedLines) + { + // Anti-aliased stroke + const float AA_SIZE = _FringeScale; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + + // Thicknesses <1.0 should behave like thickness 1.0 + thickness = ImMax(thickness, 1.0f); + const int integer_thickness = (int)thickness; + const float fractional_thickness = thickness - integer_thickness; + + // Do we want to draw this line using a texture? + // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved. + // - If AA_SIZE is not 1.0f we cannot use the texture path. + const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f); + + // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off + IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines)); + + const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12); + const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3); + PrimReserve(idx_count, vtx_count); + + // Temporary buffer + // The first items are normals at each line point, then after that there are either 2 or 4 temp points for each line point + _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5)); + ImVec2* temp_normals = _Data->TempBuffer.Data; + ImVec2* temp_points = temp_normals + points_count; + + // Calculate normals (tangents) for each line segment + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; + float dx = points[i2].x - points[i1].x; + float dy = points[i2].y - points[i1].y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i1].x = dy; + temp_normals[i1].y = -dx; + } + if (!closed) + temp_normals[points_count - 1] = temp_normals[points_count - 2]; + + // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point + if (use_texture || !thick_line) + { + // [PATH 1] Texture-based lines (thick or non-thick) + // [PATH 2] Non texture-based lines (non-thick) + + // The width of the geometry we need to draw - this is essentially pixels for the line itself, plus "one pixel" for AA. + // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture + // (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code. + // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to + // allow scaling geometry while preserving one-screen-pixel AA fringe). + const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE; + + // If line is not closed, the first and last points need to be generated differently as there are no normals to blend + if (!closed) + { + temp_points[0] = points[0] + temp_normals[0] * half_draw_size; + temp_points[1] = points[0] - temp_normals[0] * half_draw_size; + temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size; + temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size; + } + + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges + // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment + const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area + dm_y *= half_draw_size; + + // Add temporary vertexes for the outer edges + ImVec2* out_vtx = &temp_points[i2 * 2]; + out_vtx[0].x = points[i2].x + dm_x; + out_vtx[0].y = points[i2].y + dm_y; + out_vtx[1].x = points[i2].x - dm_x; + out_vtx[1].y = points[i2].y - dm_y; + + if (use_texture) + { + // Add indices for two triangles + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri + _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri + _IdxWritePtr += 6; + } + else + { + // Add indexes for four triangles + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1 + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2 + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1 + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2 + _IdxWritePtr += 12; + } + + idx1 = idx2; + } + + // Add vertexes for each point on the line + if (use_texture) + { + // If we're using textures we only need to emit the left/right edge vertices + ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness]; + /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false! + { + const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1]; + tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp() + tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness; + tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness; + tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness; + }*/ + ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y); + ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w); + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge + _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge + _VtxWritePtr += 2; + } + } + else + { + // If we're not using a texture, we need the center vertex as well + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Center of line + _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge + _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge + _VtxWritePtr += 3; + } + } + } + else + { + // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point + const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f; + + // If line is not closed, the first and last points need to be generated differently as there are no normals to blend + if (!closed) + { + const int points_last = points_count - 1; + temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness); + temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness); + temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness); + temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE); + } + + // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges + // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps) + // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer. + unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment + for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment + { + const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment + const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment + + // Average normals + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); + float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); + float dm_in_x = dm_x * half_inner_thickness; + float dm_in_y = dm_y * half_inner_thickness; + + // Add temporary vertices + ImVec2* out_vtx = &temp_points[i2 * 4]; + out_vtx[0].x = points[i2].x + dm_out_x; + out_vtx[0].y = points[i2].y + dm_out_y; + out_vtx[1].x = points[i2].x + dm_in_x; + out_vtx[1].y = points[i2].y + dm_in_y; + out_vtx[2].x = points[i2].x - dm_in_x; + out_vtx[2].y = points[i2].y - dm_in_y; + out_vtx[3].x = points[i2].x - dm_out_x; + out_vtx[3].y = points[i2].y - dm_out_y; + + // Add indexes + _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); + _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); + _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); + _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3); + _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2); + _IdxWritePtr += 18; + + idx1 = idx2; + } + + // Add vertices + for (int i = 0; i < points_count; i++) + { + _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans; + _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans; + _VtxWritePtr += 4; + } + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // [PATH 4] Non texture-based, Non anti-aliased lines + const int idx_count = count * 6; + const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges + PrimReserve(idx_count, vtx_count); + + for (int i1 = 0; i1 < count; i1++) + { + const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; + const ImVec2& p1 = points[i1]; + const ImVec2& p2 = points[i2]; + + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (thickness * 0.5f); + dy *= (thickness * 0.5f); + + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; + _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col; + _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col; + _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col; + _VtxWritePtr += 4; + + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2); + _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3); + _IdxWritePtr += 6; + _VtxCurrentIdx += 4; + } + } +} + +// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. +// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. +void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) +{ + if (points_count < 3 || (col & IM_COL32_A_MASK) == 0) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + + if (Flags & ImDrawListFlags_AntiAliasedFill) + { + // Anti-aliased Fill + const float AA_SIZE = _FringeScale; + const ImU32 col_trans = col & ~IM_COL32_A_MASK; + const int idx_count = (points_count - 2)*3 + points_count * 6; + const int vtx_count = (points_count * 2); + PrimReserve(idx_count, vtx_count); + + // Add indexes for fill + unsigned int vtx_inner_idx = _VtxCurrentIdx; + unsigned int vtx_outer_idx = _VtxCurrentIdx + 1; + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1)); + _IdxWritePtr += 3; + } + + // Compute normals + _Data->TempBuffer.reserve_discard(points_count); + ImVec2* temp_normals = _Data->TempBuffer.Data; + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + { + const ImVec2& p0 = points[i0]; + const ImVec2& p1 = points[i1]; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i0].x = dy; + temp_normals[i0].y = -dx; + } + + for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++) + { + // Average normals + const ImVec2& n0 = temp_normals[i0]; + const ImVec2& n1 = temp_normals[i1]; + float dm_x = (n0.x + n1.x) * 0.5f; + float dm_y = (n0.y + n1.y) * 0.5f; + IM_FIXNORMAL2F(dm_x, dm_y); + dm_x *= AA_SIZE * 0.5f; + dm_y *= AA_SIZE * 0.5f; + + // Add vertices + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr += 2; + + // Add indexes for fringes + _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); + _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); + _IdxWritePtr += 6; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } + else + { + // Non Anti-aliased Fill + const int idx_count = (points_count - 2)*3; + const int vtx_count = points_count; + PrimReserve(idx_count, vtx_count); + for (int i = 0; i < vtx_count; i++) + { + _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; + _VtxWritePtr++; + } + for (int i = 2; i < points_count; i++) + { + _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i); + _IdxWritePtr += 3; + } + _VtxCurrentIdx += (ImDrawIdx)vtx_count; + } +} + +void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step) +{ + if (radius < 0.5f) + { + _Path.push_back(center); + return; + } + + // Calculate arc auto segment step size + if (a_step <= 0) + a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius); + + // Make sure we never do steps larger than one quarter of the circle + a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4); + + const int sample_range = ImAbs(a_max_sample - a_min_sample); + const int a_next_step = a_step; + + int samples = sample_range + 1; + bool extra_max_sample = false; + if (a_step > 1) + { + samples = sample_range / a_step + 1; + const int overstep = sample_range % a_step; + + if (overstep > 0) + { + extra_max_sample = true; + samples++; + + // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end, + // distribute first step range evenly between them by reducing first step size. + if (sample_range > 0) + a_step -= (a_step - overstep) / 2; + } + } + + _Path.resize(_Path.Size + samples); + ImVec2* out_ptr = _Path.Data + (_Path.Size - samples); + + int sample_index = a_min_sample; + if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + { + sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + } + + if (a_max_sample >= a_min_sample) + { + for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX) + sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + } + else + { + for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step) + { + // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more + if (sample_index < 0) + sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[sample_index]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + } + + if (extra_max_sample) + { + int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + if (normalized_max_sample < 0) + normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + + const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample]; + out_ptr->x = center.x + s.x * radius; + out_ptr->y = center.y + s.y * radius; + out_ptr++; + } + + IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr); +} + +void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius < 0.5f) + { + _Path.push_back(center); + return; + } + + // Note that we are adding a point at both a_min and a_max. + // If you are trying to draw a full closed circle you don't want the overlapping points! + _Path.reserve(_Path.Size + (num_segments + 1)); + for (int i = 0; i <= num_segments; i++) + { + const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min); + _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius)); + } +} + +// 0: East, 3: South, 6: West, 9: North, 12: East +void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) +{ + if (radius < 0.5f) + { + _Path.push_back(center); + return; + } + _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0); +} + +void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments) +{ + if (radius < 0.5f) + { + _Path.push_back(center); + return; + } + + if (num_segments > 0) + { + _PathArcToN(center, radius, a_min, a_max, num_segments); + return; + } + + // Automatic segment count + if (radius <= _Data->ArcFastRadiusCutoff) + { + const bool a_is_reverse = a_max < a_min; + + // We are going to use precomputed values for mid samples. + // Determine first and last sample in lookup table that belong to the arc. + const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f); + const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f); + + const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f); + const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f); + const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0); + + const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX; + const bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f; + const bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f; + + _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0))); + if (a_emit_start) + _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius)); + if (a_mid_samples > 0) + _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0); + if (a_emit_end) + _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius)); + } + else + { + const float arc_length = ImAbs(a_max - a_min); + const int circle_segment_count = _CalcCircleAutoSegmentCount(radius); + const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length)); + _PathArcToN(center, radius, a_min, a_max, arc_segment_count); + } +} + +ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t) +{ + float u = 1.0f - t; + float w1 = u * u * u; + float w2 = 3 * u * u * t; + float w3 = 3 * u * t * t; + float w4 = t * t * t; + return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y); +} + +ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t) +{ + float u = 1.0f - t; + float w1 = u * u; + float w2 = 2 * u * t; + float w3 = t * t; + return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y); +} + +// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp +static void PathBezierCubicCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level) +{ + float dx = x4 - x1; + float dy = y4 - y1; + float d2 = (x2 - x4) * dy - (y2 - y4) * dx; + float d3 = (x3 - x4) * dy - (y3 - y4) * dx; + d2 = (d2 >= 0) ? d2 : -d2; + d3 = (d3 >= 0) ? d3 : -d3; + if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy)) + { + path->push_back(ImVec2(x4, y4)); + } + else if (level < 10) + { + float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; + float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; + float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f; + float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; + float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f; + float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f; + PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1); + PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1); + } +} + +static void PathBezierQuadraticCurveToCasteljau(ImVector* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level) +{ + float dx = x3 - x1, dy = y3 - y1; + float det = (x2 - x3) * dy - (y2 - y3) * dx; + if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy)) + { + path->push_back(ImVec2(x3, y3)); + } + else if (level < 10) + { + float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f; + float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f; + float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f; + PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1); + PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1); + } +} + +void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments) +{ + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + IM_ASSERT(_Data->CurveTessellationTol > 0.0f); + PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step)); + } +} + +void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments) +{ + ImVec2 p1 = _Path.back(); + if (num_segments == 0) + { + IM_ASSERT(_Data->CurveTessellationTol > 0.0f); + PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated + } + else + { + float t_step = 1.0f / (float)num_segments; + for (int i_step = 1; i_step <= num_segments; i_step++) + _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step)); + } +} + +IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4)); +static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags) +{ +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // Obsoleted in 1.82 (from February 2021) + // Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All) + // ~0 --> ImDrawFlags_RoundCornersAll or 0 + if (flags == ~0) + return ImDrawFlags_RoundCornersAll; + + // Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations) + // 0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!) + // 0x02 --> ImDrawFlags_RoundCornersTopRight + // 0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight + // 0x04 --> ImDrawFlags_RoundCornersBotLeft + // 0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft + // ... + // 0x0F --> ImDrawFlags_RoundCornersAll or 0 + // (See all values in ImDrawCornerFlags_) + if (flags >= 0x01 && flags <= 0x0F) + return (flags << 4); + + // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f' +#endif + + // If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values. + // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc... + IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!"); + + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags |= ImDrawFlags_RoundCornersAll; + + return flags; +} + +void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) +{ + flags = FixRectCornerFlags(flags); + rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f); + rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f); + + if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + { + PathLineTo(a); + PathLineTo(ImVec2(b.x, a.y)); + PathLineTo(b); + PathLineTo(ImVec2(a.x, b.y)); + } + else + { + const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft) ? rounding : 0.0f; + const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight) ? rounding : 0.0f; + const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f; + const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft) ? rounding : 0.0f; + PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9); + PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12); + PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3); + PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6); + } +} + +void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + PathLineTo(p1 + ImVec2(0.5f, 0.5f)); + PathLineTo(p2 + ImVec2(0.5f, 0.5f)); + PathStroke(col, 0, thickness); +} + +// p_min = upper-left, p_max = lower-right +// Note we don't render 1 pixels sized rectangles properly. +void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (Flags & ImDrawListFlags_AntiAliasedLines) + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags); + else + PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes. + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + { + PrimReserve(6, 4); + PrimRect(p_min, p_max, col); + } + else + { + PathRect(p_min, p_max, rounding, flags); + PathFillConvex(col); + } +} + +// p_min = upper-left, p_max = lower-right +void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left) +{ + if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) + return; + + const ImVec2 uv = _Data->TexUvWhitePixel; + PrimReserve(6, 4); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); + PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3)); + PrimWriteVtx(p_min, uv, col_upr_left); + PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right); + PrimWriteVtx(p_max, uv, col_bot_right); + PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left); +} + +void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathLineTo(p4); + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathLineTo(p4); + PathFillConvex(col); +} + +void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathLineTo(p2); + PathLineTo(p3); + PathFillConvex(col); +} + +void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) + return; + + if (num_segments <= 0) + { + // Use arc with automatic segment count + _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + _Path.Size--; + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + } + + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f) + return; + + if (num_segments <= 0) + { + // Use arc with automatic segment count + _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0); + _Path.Size--; + } + else + { + // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes) + num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX); + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + } + + PathFillConvex(col); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1); + PathStroke(col, ImDrawFlags_Closed, thickness); +} + +// Guaranteed to honor 'num_segments' +void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2) + return; + + // Because we are filling a closed shape we remove 1 from the count of segments/points + const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments; + PathArcTo(center, radius, 0.0f, a_max, num_segments - 1); + PathFillConvex(col); +} + +// Cubic Bezier takes 4 controls points +void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathBezierCubicCurveTo(p2, p3, p4, num_segments); + PathStroke(col, 0, thickness); +} + +// Quadratic Bezier takes 3 controls points +void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + PathLineTo(p1); + PathBezierQuadraticCurveTo(p2, p3, num_segments); + PathStroke(col, 0, thickness); +} + +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + if (text_end == NULL) + text_end = text_begin + strlen(text_begin); + if (text_begin == text_end) + return; + + // Pull default font/size from the shared ImDrawListSharedData instance + if (font == NULL) + font = _Data->Font; + if (font_size == 0.0f) + font_size = _Data->FontSize; + + IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + + ImVec4 clip_rect = _CmdHeader.ClipRect; + if (cpu_fine_clip_rect) + { + clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); + clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y); + clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); + clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); + } + font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL); +} + +void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) +{ + AddText(NULL, 0.0f, pos, col, text_begin, text_end); +} + +void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimRectUV(p_min, p_max, uv_min, uv_max, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + if (push_texture_id) + PushTextureID(user_texture_id); + + PrimReserve(6, 4); + PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col); + + if (push_texture_id) + PopTextureID(); +} + +void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) +{ + if ((col & IM_COL32_A_MASK) == 0) + return; + + flags = FixRectCornerFlags(flags); + if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) + { + AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); + return; + } + + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + if (push_texture_id) + PushTextureID(user_texture_id); + + int vert_start_idx = VtxBuffer.Size; + PathRect(p_min, p_max, rounding, flags); + PathFillConvex(col); + int vert_end_idx = VtxBuffer.Size; + ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); + + if (push_texture_id) + PopTextureID(); +} + + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawListSplitter +//----------------------------------------------------------------------------- +// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap.. +//----------------------------------------------------------------------------- + +void ImDrawListSplitter::ClearFreeMemory() +{ + for (int i = 0; i < _Channels.Size; i++) + { + if (i == _Current) + memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again + _Channels[i]._CmdBuffer.clear(); + _Channels[i]._IdxBuffer.clear(); + } + _Current = 0; + _Count = 1; + _Channels.clear(); +} + +void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) +{ + IM_UNUSED(draw_list); + IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); + int old_channels_count = _Channels.Size; + if (old_channels_count < channels_count) + { + _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable + _Channels.resize(channels_count); + } + _Count = channels_count; + + // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer + // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. + // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer + memset(&_Channels[0], 0, sizeof(ImDrawChannel)); + for (int i = 1; i < channels_count; i++) + { + if (i >= old_channels_count) + { + IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel(); + } + else + { + _Channels[i]._CmdBuffer.resize(0); + _Channels[i]._IdxBuffer.resize(0); + } + } +} + +void ImDrawListSplitter::Merge(ImDrawList* draw_list) +{ + // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + if (_Count <= 1) + return; + + SetCurrentChannel(draw_list, 0); + draw_list->_PopUnusedDrawCmd(); + + // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. + int new_cmd_buffer_count = 0; + int new_idx_buffer_count = 0; + ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL; + int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0; + for (int i = 1; i < _Count; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() + ch._CmdBuffer.pop_back(); + + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) + { + // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves. + // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter. + ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; + if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) + { + // Merge previous channel last draw command with current channel first draw command if matching. + last_cmd->ElemCount += next_cmd->ElemCount; + idx_offset += next_cmd->ElemCount; + ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. + } + } + if (ch._CmdBuffer.Size > 0) + last_cmd = &ch._CmdBuffer.back(); + new_cmd_buffer_count += ch._CmdBuffer.Size; + new_idx_buffer_count += ch._IdxBuffer.Size; + for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++) + { + ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset; + idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount; + } + } + draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count); + draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count); + + // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices) + ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count; + ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count; + for (int i = 1; i < _Count; i++) + { + ImDrawChannel& ch = _Channels[i]; + if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; } + if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } + } + draw_list->_IdxWritePtr = idx_write; + + // Ensure there's always a non-callback draw command trailing the command-buffer + if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) + draw_list->AddDrawCmd(); + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); + + _Count = 1; +} + +void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) +{ + IM_ASSERT(idx >= 0 && idx < _Count); + if (_Current == idx) + return; + + // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() + memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); + memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer)); + _Current = idx; + memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer)); + memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer)); + draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd == NULL) + draw_list->AddDrawCmd(); + else if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawData +//----------------------------------------------------------------------------- + +void ImDrawData::Clear() +{ + Valid = false; + CmdListsCount = TotalIdxCount = TotalVtxCount = 0; + CmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them. + DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f); + OwnerViewport = NULL; +} + +// Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list +// as long at it is expected that the result will be later merged into draw_data->CmdLists[]. +void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector* out_list, ImDrawList* draw_list) +{ + if (draw_list->CmdBuffer.Size == 0) + return; + if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL) + return; + + // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. + // May trigger for you if you are using PrimXXX functions incorrectly. + IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); + IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size); + if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) + IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); + + // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) + // If this assert triggers because you are drawing lots of stuff manually: + // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. + // Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. + // - If you want large meshes with more than 64K vertices, you can either: + // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. + // Most example backends already support this from 1.71. Pre-1.71 backends won't. + // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them. + // (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h. + // Most example backends already support this. For example, the OpenGL example code detect index size at compile-time: + // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); + // Your own engine or render API may use different parameters or function calls to specify index sizes. + // 2 and 4 bytes indices are generally supported by most graphics API. + // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching + // the 64K limit to split your draw commands in multiple draw lists. + if (sizeof(ImDrawIdx) == 2) + IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); + + // Add to output list + records state in ImDrawData + out_list->push_back(draw_list); + draw_data->CmdListsCount++; + draw_data->TotalVtxCount += draw_list->VtxBuffer.Size; + draw_data->TotalIdxCount += draw_list->IdxBuffer.Size; +} + +void ImDrawData::AddDrawList(ImDrawList* draw_list) +{ + IM_ASSERT(CmdLists.Size == CmdListsCount); + draw_list->_PopUnusedDrawCmd(); + ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list); +} + +// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! +void ImDrawData::DeIndexAllBuffers() +{ + ImVector new_vtx_buffer; + TotalVtxCount = TotalIdxCount = 0; + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + if (cmd_list->IdxBuffer.empty()) + continue; + new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); + for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) + new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; + cmd_list->VtxBuffer.swap(new_vtx_buffer); + cmd_list->IdxBuffer.resize(0); + TotalVtxCount += cmd_list->VtxBuffer.Size; + } +} + +// Helper to scale the ClipRect field of each ImDrawCmd. +// Use if your final output buffer is at a different scale than draw_data->DisplaySize, +// or if there is a difference between your window resolution and framebuffer resolution. +void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) +{ + for (int i = 0; i < CmdListsCount; i++) + { + ImDrawList* cmd_list = CmdLists[i]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i]; + cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Helpers ShadeVertsXXX functions +//----------------------------------------------------------------------------- + +// Generic linear color gradient, write to RGB fields, leave A untouched. +void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) +{ + ImVec2 gradient_extent = gradient_p1 - gradient_p0; + float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent); + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF; + const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF; + const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF; + const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r; + const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g; + const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b; + for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) + { + float d = ImDot(vert->pos - gradient_p0, gradient_extent); + float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f); + int r = (int)(col0_r + col_delta_r * t); + int g = (int)(col0_g + col_delta_g * t); + int b = (int)(col0_b + col_delta_b * t); + vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); + } +} + +// Distribute UV over (a, b) rectangle +void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp) +{ + const ImVec2 size = b - a; + const ImVec2 uv_size = uv_b - uv_a; + const ImVec2 scale = ImVec2( + size.x != 0.0f ? (uv_size.x / size.x) : 0.0f, + size.y != 0.0f ? (uv_size.y / size.y) : 0.0f); + + ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx; + ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx; + if (clamp) + { + const ImVec2 min = ImMin(uv_a, uv_b); + const ImVec2 max = ImMax(uv_a, uv_b); + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max); + } + else + { + for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex) + vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontConfig +//----------------------------------------------------------------------------- + +ImFontConfig::ImFontConfig() +{ + memset(this, 0, sizeof(*this)); + FontDataOwnedByAtlas = true; + OversampleH = 2; + OversampleV = 1; + GlyphMaxAdvanceX = FLT_MAX; + RasterizerMultiply = 1.0f; + EllipsisChar = (ImWchar)-1; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas +//----------------------------------------------------------------------------- + +// A work of art lies ahead! (. = white layer, X = black layer, others are blank) +// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. +// (This is used when io.MouseDrawCursor = true) +const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing. +const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; +static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = +{ + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X" + "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " + " X..X - - X...X - X...X - X..X X..X - - X........X - " + " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " + "------------- - X - X -X.....................X- ------------------- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " +}; + +static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = +{ + // Pos ........ Size ......... Offset ...... + { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW + { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE + { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand + { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed +}; + +ImFontAtlas::ImFontAtlas() +{ + memset(this, 0, sizeof(*this)); + TexGlyphPadding = 1; + PackIdMouseCursors = PackIdLines = -1; +} + +ImFontAtlas::~ImFontAtlas() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + Clear(); +} + +void ImFontAtlas::ClearInputData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + for (int i = 0; i < ConfigData.Size; i++) + if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) + { + IM_FREE(ConfigData[i].FontData); + ConfigData[i].FontData = NULL; + } + + // When clearing this we lose access to the font name and other information used to build the font. + for (int i = 0; i < Fonts.Size; i++) + if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) + { + Fonts[i]->ConfigData = NULL; + Fonts[i]->ConfigDataCount = 0; + } + ConfigData.clear(); + CustomRects.clear(); + PackIdMouseCursors = PackIdLines = -1; + // Important: we leave TexReady untouched +} + +void ImFontAtlas::ClearTexData() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + if (TexPixelsAlpha8) + IM_FREE(TexPixelsAlpha8); + if (TexPixelsRGBA32) + IM_FREE(TexPixelsRGBA32); + TexPixelsAlpha8 = NULL; + TexPixelsRGBA32 = NULL; + TexPixelsUseColors = false; + // Important: we leave TexReady untouched +} + +void ImFontAtlas::ClearFonts() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + Fonts.clear_delete(); + TexReady = false; +} + +void ImFontAtlas::Clear() +{ + ClearInputData(); + ClearTexData(); + ClearFonts(); +} + +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Build atlas on demand + if (TexPixelsAlpha8 == NULL) + Build(); + + *out_pixels = TexPixelsAlpha8; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 1; +} + +void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + // Convert to RGBA32 format on demand + // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp + if (!TexPixelsRGBA32) + { + unsigned char* pixels = NULL; + GetTexDataAsAlpha8(&pixels, NULL, NULL); + if (pixels) + { + TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4); + const unsigned char* src = pixels; + unsigned int* dst = TexPixelsRGBA32; + for (int n = TexWidth * TexHeight; n > 0; n--) + *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); + } + } + + *out_pixels = (unsigned char*)TexPixelsRGBA32; + if (out_width) *out_width = TexWidth; + if (out_height) *out_height = TexHeight; + if (out_bytes_per_pixel) *out_bytes_per_pixel = 4; +} + +ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); + IM_ASSERT(font_cfg->SizePixels > 0.0f); + + // Create new font + if (!font_cfg->MergeMode) + Fonts.push_back(IM_NEW(ImFont)); + else + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + + ConfigData.push_back(*font_cfg); + ImFontConfig& new_font_cfg = ConfigData.back(); + if (new_font_cfg.DstFont == NULL) + new_font_cfg.DstFont = Fonts.back(); + if (!new_font_cfg.FontDataOwnedByAtlas) + { + new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); + new_font_cfg.FontDataOwnedByAtlas = true; + memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); + } + + if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) + new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; + + // Invalidate texture + TexReady = false; + ClearTexData(); + return new_font_cfg.DstFont; +} + +// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) +static unsigned int stb_decompress_length(const unsigned char* input); +static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); +static const char* GetDefaultCompressedFontDataTTFBase85(); +static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } +static void Decode85(const unsigned char* src, unsigned char* dst) +{ + while (*src) + { + unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4])))); + dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness. + src += 5; + dst += 4; + } +} + +// Load embedded ProggyClean.ttf at size 13, disable oversampling +ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) +{ + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (!font_cfg_template) + { + font_cfg.OversampleH = font_cfg.OversampleV = 1; + font_cfg.PixelSnapH = true; + } + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); + font_cfg.EllipsisChar = (ImWchar)0x0085; + font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units + + const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); + const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); + ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); + return font; +} + +ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + size_t data_size = 0; + void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); + if (!data) + { + IM_ASSERT_USER_ERROR(0, "Could not load font file!"); + return NULL; + } + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + if (font_cfg.Name[0] == '\0') + { + // Store a short copy of filename into into the font name for convenience + const char* p; + for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); + } + return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); +} + +// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). +ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontData = ttf_data; + font_cfg.FontDataSize = ttf_size; + font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels; + if (glyph_ranges) + font_cfg.GlyphRanges = glyph_ranges; + return AddFont(&font_cfg); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) +{ + const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data); + unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size); + stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size); + + ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); + IM_ASSERT(font_cfg.FontData == NULL); + font_cfg.FontDataOwnedByAtlas = true; + return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges); +} + +ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) +{ + int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; + void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); + Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); + ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); + IM_FREE(compressed_ttf); + return font; +} + +int ImFontAtlas::AddCustomRectRegular(int width, int height) +{ + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) +{ +#ifdef IMGUI_USE_WCHAR32 + IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX); +#endif + IM_ASSERT(font != NULL); + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + r.GlyphID = id; + r.GlyphAdvanceX = advance_x; + r.GlyphOffset = offset; + r.Font = font; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +{ + IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates + IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed + *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); + *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); +} + +bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +{ + if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) + return false; + if (Flags & ImFontAtlasFlags_NoMouseCursors) + return false; + + IM_ASSERT(PackIdMouseCursors != -1); + ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors); + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y); + ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; + *out_size = size; + *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; + out_uv_border[0] = (pos) * TexUvScale; + out_uv_border[1] = (pos + size) * TexUvScale; + pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + out_uv_fill[0] = (pos) * TexUvScale; + out_uv_fill[1] = (pos + size) * TexUvScale; + return true; +} + +bool ImFontAtlas::Build() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + + // Default font is none are specified + if (ConfigData.Size == 0) + AddFontDefault(); + + // Select builder + // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which + // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are + // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere + // and point to it instead of pointing directly to return value of the GetBuilderXXX functions. + const ImFontBuilderIO* builder_io = FontBuilderIO; + if (builder_io == NULL) + { +#ifdef IMGUI_ENABLE_FREETYPE + builder_io = ImGuiFreeType::GetBuilderForFreeType(); +#elif defined(IMGUI_ENABLE_STB_TRUETYPE) + builder_io = ImFontAtlasGetBuilderForStbTruetype(); +#else + IM_ASSERT(0); // Invalid Build function +#endif + } + + // Build + return builder_io->FontBuilder_Build(this); +} + +void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) +{ + for (unsigned int i = 0; i < 256; i++) + { + unsigned int value = (unsigned int)(i * in_brighten_factor); + out_table[i] = value > 255 ? 255 : (value & 0xFF); + } +} + +void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) +{ + IM_ASSERT_PARANOID(w <= stride); + unsigned char* data = pixels + x + y * stride; + for (int j = h; j > 0; j--, data += stride - w) + for (int i = w; i > 0; i--, data++) + *data = table[*data]; +} + +#ifdef IMGUI_ENABLE_STB_TRUETYPE +// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) +// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) +struct ImFontBuildSrcData +{ + stbtt_fontinfo FontInfo; + stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) + stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. + stbtt_packedchar* PackedChars; // Output glyphs + const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) + int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] + int GlyphsHighest; // Highest requested codepoint + int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) + ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) + ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsSet) +}; + +// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) +struct ImFontBuildDstData +{ + int SrcCount; // Number of source fonts targeting this destination font. + int GlyphsHighest; + int GlyphsCount; + ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. +}; + +static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out) +{ + IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); + const ImU32* it_begin = in->Storage.begin(); + const ImU32* it_end = in->Storage.end(); + for (const ImU32* it = it_begin; it < it_end; it++) + if (ImU32 entries_32 = *it) + for (ImU32 bit_n = 0; bit_n < 32; bit_n++) + if (entries_32 & ((ImU32)1 << bit_n)) + out->push_back((int)(((it - it_begin) << 5) + bit_n)); +} + +static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +{ + IM_ASSERT(atlas->ConfigData.Size > 0); + + ImFontAtlasBuildInit(atlas); + + // Clear atlas + atlas->TexID = (ImTextureID)NULL; + atlas->TexWidth = atlas->TexHeight = 0; + atlas->TexUvScale = ImVec2(0.0f, 0.0f); + atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); + atlas->ClearTexData(); + + // Temporary storage for building + ImVector src_tmp_array; + ImVector dst_tmp_array; + src_tmp_array.resize(atlas->ConfigData.Size); + dst_tmp_array.resize(atlas->Fonts.Size); + memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); + memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); + + // 1. Initialize font loading structure, check font data validity + for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + + // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + src_tmp.DstIndex = -1; + for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) + if (cfg.DstFont == atlas->Fonts[output_i]) + src_tmp.DstIndex = output_i; + if (src_tmp.DstIndex == -1) + { + IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + return false; + } + // Initialize helper structure for font loading and verify that the TTF/OTF data is correct + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); + IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) + return false; + + // Measure highest codepoints + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + { + // Check for valid range. This may also help detect *some* dangling pointers, because a common + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. + IM_ASSERT(src_range[0] <= src_range[1]); + src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); + } + dst_tmp.SrcCount++; + dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); + } + + // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. + int total_glyphs_count = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; + src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); + if (dst_tmp.GlyphsSet.Storage.empty()) + dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); + + for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) + for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) + { + if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) + continue; + if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? + continue; + + // Add to avail set/counters + src_tmp.GlyphsCount++; + dst_tmp.GlyphsCount++; + src_tmp.GlyphsSet.SetBit(codepoint); + dst_tmp.GlyphsSet.SetBit(codepoint); + total_glyphs_count++; + } + } + + // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); + UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); + src_tmp.GlyphsSet.Clear(); + IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); + } + for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) + dst_tmp_array[dst_i].GlyphsSet.Clear(); + dst_tmp_array.clear(); + + // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) + // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) + ImVector buf_rects; + ImVector buf_packedchars; + buf_rects.resize(total_glyphs_count); + buf_packedchars.resize(total_glyphs_count); + memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); + memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); + + // 4. Gather glyphs sizes so we can pack them in our virtual canvas. + int total_surface = 0; + int buf_rects_out_n = 0; + int buf_packedchars_out_n = 0; + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + src_tmp.Rects = &buf_rects[buf_rects_out_n]; + src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; + buf_rects_out_n += src_tmp.GlyphsCount; + buf_packedchars_out_n += src_tmp.GlyphsCount; + + // Convert our ranges in the format stb_truetype wants + ImFontConfig& cfg = atlas->ConfigData[src_i]; + src_tmp.PackRange.font_size = cfg.SizePixels; + src_tmp.PackRange.first_unicode_codepoint_in_range = 0; + src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; + src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; + src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; + src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; + src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; + + // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) + const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels); + const int padding = atlas->TexGlyphPadding; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) + { + int x0, y0, x1, y1; + const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); + IM_ASSERT(glyph_index_in_font != 0); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); + total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; + } + } + + // We need a width for the skyline algorithm, any width! + // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. + // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. + const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; + atlas->TexHeight = 0; + if (atlas->TexDesiredWidth > 0) + atlas->TexWidth = atlas->TexDesiredWidth; + else + atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512; + + // 5. Start packing + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + const int TEX_HEIGHT_MAX = 1024 * 32; + stbtt_pack_context spc = {}; + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); + ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); + + // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); + + // Extend texture height and mark missing glyphs as non-packed so we won't render them. + // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + if (src_tmp.Rects[glyph_i].was_packed) + atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); + } + + // 7. Allocate texture + atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); + atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); + memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + spc.pixels = atlas->TexPixelsAlpha8; + spc.height = atlas->TexHeight; + + // 8. Render/rasterize font characters into the texture + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; + + stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); + + // Apply multiply operator + if (cfg.RasterizerMultiply != 1.0f) + { + unsigned char multiply_table[256]; + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + stbrp_rect* r = &src_tmp.Rects[0]; + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) + if (r->was_packed) + ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); + } + src_tmp.Rects = NULL; + } + + // End packing + stbtt_PackEnd(&spc); + buf_rects.clear(); + + // 9. Setup ImFont and glyphs for runtime + for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + { + // When merging fonts with MergeMode=true: + // - We can have multiple input fonts writing into a same destination font. + // - dst_font->ConfigData is != from cfg which is our source configuration. + ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; + ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFont* dst_font = cfg.DstFont; + + const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + + const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1)); + const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1)); + ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); + const float font_off_x = cfg.GlyphOffset.x; + const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); + + for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) + { + // Register glyph + const int codepoint = src_tmp.GlyphsList[glyph_i]; + const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; + stbtt_aligned_quad q; + float unused_x = 0.0f, unused_y = 0.0f; + stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0); + dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); + } + } + + // Cleanup + src_tmp_array.clear_destruct(); + + ImFontAtlasBuildFinish(atlas); + return true; +} + +const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() +{ + static ImFontBuilderIO io; + io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype; + return &io; +} + +#endif // IMGUI_ENABLE_STB_TRUETYPE + +void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) +{ + if (!font_config->MergeMode) + { + font->ClearOutputData(); + font->FontSize = font_config->SizePixels; + font->ConfigData = font_config; + font->ConfigDataCount = 0; + font->ContainerAtlas = atlas; + font->Ascent = ascent; + font->Descent = descent; + } + font->ConfigDataCount++; +} + +void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) +{ + stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; + IM_ASSERT(pack_context != NULL); + + ImVector& user_rects = atlas->CustomRects; + IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. +#ifdef __GNUC__ + if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343) +#endif + + ImVector pack_rects; + pack_rects.resize(user_rects.Size); + memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); + for (int i = 0; i < user_rects.Size; i++) + { + pack_rects[i].w = user_rects[i].Width; + pack_rects[i].h = user_rects[i].Height; + } + stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); + for (int i = 0; i < pack_rects.Size; i++) + if (pack_rects[i].was_packed) + { + user_rects[i].X = (unsigned short)pack_rects[i].x; + user_rects[i].Y = (unsigned short)pack_rects[i].y; + IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); + atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); + } +} + +void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; +} + +void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS; +} + +static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) +{ + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); + IM_ASSERT(r->IsPacked()); + + const int w = atlas->TexWidth; + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + { + // Render/copy pixels + IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); + const int x_for_white = r->X; + const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + if (atlas->TexPixelsAlpha8 != NULL) + { + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + } + else + { + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + } + } + else + { + // Render 4 white pixels + IM_ASSERT(r->Width == 2 && r->Height == 2); + const int offset = (int)r->X + (int)r->Y * w; + if (atlas->TexPixelsAlpha8 != NULL) + { + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + else + { + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + } + } + atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); +} + +static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) +{ + if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) + return; + + // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); + IM_ASSERT(r->IsPacked()); + for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row + { + // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle + unsigned int y = n; + unsigned int line_width = n; + unsigned int pad_left = (r->Width - line_width) / 2; + unsigned int pad_right = r->Width - (pad_left + line_width); + + // Write each slice + IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels + if (atlas->TexPixelsAlpha8 != NULL) + { + unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else + { + unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); + } + + // Calculate UVs for this line + ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale; + float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts + atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); + } +} + +// Note: this is called / shared by both the stb_truetype and the FreeType builder +void ImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + // Register texture region for mouse cursors or standard white pixels + if (atlas->PackIdMouseCursors < 0) + { + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + else + atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2); + } + + // Register texture region for thick lines + // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row + if (atlas->PackIdLines < 0) + { + if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines)) + atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + } +} + +// This is called/shared by both the stb_truetype and the FreeType builder. +void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + // Render into our custom data blocks + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); + ImFontAtlasBuildRenderDefaultTexData(atlas); + ImFontAtlasBuildRenderLinesTexData(atlas); + + // Register custom rectangle glyphs + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; + if (r->Font == NULL || r->GlyphID == 0) + continue; + + // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH + IM_ASSERT(r->Font->ContainerAtlas == atlas); + ImVec2 uv0, uv1; + atlas->CalcCustomRectUV(r, &uv0, &uv1); + r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); + } + + // Build all fonts lookup tables + for (int i = 0; i < atlas->Fonts.Size; i++) + if (atlas->Fonts[i]->DirtyLookupTables) + atlas->Fonts[i]->BuildLookupTable(); + + atlas->TexReady = true; +} + +// Retrieve list of range (2 int per range, values are inclusive) +const ImWchar* ImFontAtlas::GetGlyphRangesDefault() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesGreek() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0370, 0x03FF, // Greek and Coptic + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesKorean() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3131, 0x3163, // Korean alphabets + 0xAC00, 0xD7A3, // Korean characters + 0xFFFD, 0xFFFD, // Invalid + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD, // Invalid + 0x4e00, 0x9FAF, // CJK Ideograms + 0, + }; + return &ranges[0]; +} + +static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges) +{ + for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2) + { + out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]); + base_codepoint += accumulative_offsets[n]; + } + out_ranges[0] = 0; +} + +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas glyph ranges helpers +//------------------------------------------------------------------------- + +const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() +{ + // Store 2500 regularly used characters for Simplified Chinese. + // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8 + // This table covers 97.97% of all characters used during the month in July, 1987. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2, + 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4, + 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1, + 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2, + 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6, + 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1, + 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3, + 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4, + 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12, + 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1, + 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23, + 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6, + 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6, + 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1, + 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5, + 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15, + 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6, + 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4, + 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5, + 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2, + 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16, + 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31, + 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7, + 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2, + 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13, + 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3, + 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4, + 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1, + 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3, + 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11, + 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9, + 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2, + 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3, + 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12, + 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8, + 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5, + 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1, + 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5, + 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6, + 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6 + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x2000, 0x206F, // General Punctuation + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesJapanese() +{ + // 2999 ideograms code points for Japanese + // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points + // - 863 Jinmeiyo (meaning "for personal name") Kanji code points + // - Sourced from official information provided by the government agencies of Japan: + // - List of Joyo Kanji by the Agency for Cultural Affairs + // - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/ + // - List of Jinmeiyo Kanji by the Ministry of Justice + // - http://www.moj.go.jp/MINJI/minji86.html + // - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0). + // - https://creativecommons.org/licenses/by/4.0/legalcode + // - You can generate this code by the script at: + // - https://github.com/vaiorabbit/everyday_use_kanji + // - References: + // - List of Joyo Kanji + // - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji + // - List of Jinmeiyo Kanji + // - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji + // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details. + // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters. + // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.) + static const short accumulative_offsets_from_0x4E00[] = + { + 0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1, + 1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3, + 2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8, + 2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5, + 2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1, + 1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30, + 2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3, + 13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4, + 5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14, + 2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1, + 1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1, + 7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1, + 1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1, + 6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2, + 10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7, + 2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5, + 3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1, + 6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7, + 4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2, + 4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5, + 1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6, + 12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2, + 1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16, + 22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11, + 2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18, + 18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9, + 14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3, + 1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6, + 40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1, + 12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8, + 2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1, + 1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10, + 1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5, + 3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2, + 14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5, + 12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1, + 2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5, + 1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4, + 3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7, + 2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5, + 13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13, + 18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21, + 37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1, + 5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38, + 32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4, + 1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4, + 4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1, + 3,2,1,1,1,1,2,1,1, + }; + static ImWchar base_ranges[] = // not zero-terminated + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0xFF00, 0xFFEF, // Half-width characters + 0xFFFD, 0xFFFD // Invalid + }; + static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 }; + if (!full_ranges[0]) + { + memcpy(full_ranges, base_ranges, sizeof(base_ranges)); + UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges)); + } + return &full_ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement + 0x2DE0, 0x2DFF, // Cyrillic Extended-A + 0xA640, 0xA69F, // Cyrillic Extended-B + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesThai() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x2010, 0x205E, // Punctuations + 0x0E00, 0x0E7F, // Thai + 0, + }; + return &ranges[0]; +} + +const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() +{ + static const ImWchar ranges[] = + { + 0x0020, 0x00FF, // Basic Latin + 0x0102, 0x0103, + 0x0110, 0x0111, + 0x0128, 0x0129, + 0x0168, 0x0169, + 0x01A0, 0x01A1, + 0x01AF, 0x01B0, + 0x1EA0, 0x1EF9, + 0, + }; + return &ranges[0]; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontGlyphRangesBuilder +//----------------------------------------------------------------------------- + +void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end) +{ + while (text_end ? (text < text_end) : *text) + { + unsigned int c = 0; + int c_len = ImTextCharFromUtf8(&c, text, text_end); + text += c_len; + if (c_len == 0) + break; + AddChar((ImWchar)c); + } +} + +void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges) +{ + for (; ranges[0]; ranges += 2) + for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 + AddChar((ImWchar)c); +} + +void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) +{ + const int max_codepoint = IM_UNICODE_CODEPOINT_MAX; + for (int n = 0; n <= max_codepoint; n++) + if (GetBit(n)) + { + out_ranges->push_back((ImWchar)n); + while (n < max_codepoint && GetBit(n + 1)) + n++; + out_ranges->push_back((ImWchar)n); + } + out_ranges->push_back(0); +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFont +//----------------------------------------------------------------------------- + +ImFont::ImFont() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + FallbackChar = (ImWchar)-1; + EllipsisChar = (ImWchar)-1; + EllipsisWidth = EllipsisCharStep = 0.0f; + EllipsisCharCount = 0; + FallbackGlyph = NULL; + ContainerAtlas = NULL; + ConfigData = NULL; + ConfigDataCount = 0; + DirtyLookupTables = false; + Scale = 1.0f; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); +} + +ImFont::~ImFont() +{ + ClearOutputData(); +} + +void ImFont::ClearOutputData() +{ + FontSize = 0.0f; + FallbackAdvanceX = 0.0f; + Glyphs.clear(); + IndexAdvanceX.clear(); + IndexLookup.clear(); + FallbackGlyph = NULL; + ContainerAtlas = NULL; + DirtyLookupTables = true; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; +} + +static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) +{ + for (int n = 0; n < candidate_chars_count; n++) + if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL) + return candidate_chars[n]; + return (ImWchar)-1; +} + +void ImFont::BuildLookupTable() +{ + int max_codepoint = 0; + for (int i = 0; i != Glyphs.Size; i++) + max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); + + // Build lookup table + IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved + IndexAdvanceX.clear(); + IndexLookup.clear(); + DirtyLookupTables = false; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); + GrowIndex(max_codepoint + 1); + for (int i = 0; i < Glyphs.Size; i++) + { + int codepoint = (int)Glyphs[i].Codepoint; + IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; + IndexLookup[codepoint] = (ImWchar)i; + + // Mark 4K page as used + const int page_n = codepoint / 4096; + Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + } + + // Create a glyph to handle TAB + // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) + if (FindGlyph((ImWchar)' ')) + { + if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times (FIXME: Flaky) + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& tab_glyph = Glyphs.back(); + tab_glyph = *FindGlyph((ImWchar)' '); + tab_glyph.Codepoint = '\t'; + tab_glyph.AdvanceX *= IM_TABSIZE; + IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; + IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1); + } + + // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) + SetGlyphVisible((ImWchar)' ', false); + SetGlyphVisible((ImWchar)'\t', false); + + // Setup Fallback character + const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + if (FallbackGlyph == NULL) + { + FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars)); + FallbackGlyph = FindGlyphNoFallback(FallbackChar); + if (FallbackGlyph == NULL) + { + FallbackGlyph = &Glyphs.back(); + FallbackChar = (ImWchar)FallbackGlyph->Codepoint; + } + } + FallbackAdvanceX = FallbackGlyph->AdvanceX; + for (int i = 0; i < max_codepoint + 1; i++) + if (IndexAdvanceX[i] < 0.0f) + IndexAdvanceX[i] = FallbackAdvanceX; + + // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). + // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. + // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. + const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; + if (EllipsisChar == (ImWchar)-1) + EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); + const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); + if (EllipsisChar != (ImWchar)-1) + { + EllipsisCharCount = 1; + EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; + } + else if (dot_char != (ImWchar)-1) + { + const ImFontGlyph* glyph = FindGlyph(dot_char); + EllipsisChar = dot_char; + EllipsisCharCount = 3; + EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f; + EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f; + } +} + +// API is designed this way to avoid exposing the 4K page size +// e.g. use with IsGlyphRangeUnused(0, 255) +bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) +{ + unsigned int page_begin = (c_begin / 4096); + unsigned int page_last = (c_last / 4096); + for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) + if ((page_n >> 3) < sizeof(Used4kPagesMap)) + if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) + return false; + return true; +} + +void ImFont::SetGlyphVisible(ImWchar c, bool visible) +{ + if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) + glyph->Visible = visible ? 1 : 0; +} + +void ImFont::GrowIndex(int new_size) +{ + IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); + if (new_size <= IndexLookup.Size) + return; + IndexAdvanceX.resize(new_size, -1.0f); + IndexLookup.resize(new_size, (ImWchar)-1); +} + +// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. +// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). +// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font. +void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +{ + if (cfg != NULL) + { + // Clamp & recenter if needed + const float advance_x_original = advance_x; + advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX); + if (advance_x != advance_x_original) + { + float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; + x0 += char_off_x; + x1 += char_off_x; + } + + // Snap to pixel + if (cfg->PixelSnapH) + advance_x = IM_ROUND(advance_x); + + // Bake spacing + advance_x += cfg->GlyphExtraSpacing.x; + } + + Glyphs.resize(Glyphs.Size + 1); + ImFontGlyph& glyph = Glyphs.back(); + glyph.Codepoint = (unsigned int)codepoint; + glyph.Visible = (x0 != x1) && (y0 != y1); + glyph.Colored = false; + glyph.X0 = x0; + glyph.Y0 = y0; + glyph.X1 = x1; + glyph.Y1 = y1; + glyph.U0 = u0; + glyph.V0 = v0; + glyph.U1 = u1; + glyph.V1 = v1; + glyph.AdvanceX = advance_x; + + // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) + // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. + float pad = ContainerAtlas->TexGlyphPadding + 0.99f; + DirtyLookupTables = true; + MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad); +} + +void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) +{ + IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. + unsigned int index_size = (unsigned int)IndexLookup.Size; + + if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists + return; + if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op + return; + + GrowIndex(dst + 1); + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; + IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; +} + +const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const +{ + if (c >= (size_t)IndexLookup.Size) + return FallbackGlyph; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return FallbackGlyph; + return &Glyphs.Data[i]; +} + +const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const +{ + if (c >= (size_t)IndexLookup.Size) + return NULL; + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) + return NULL; + return &Glyphs.Data[i]; +} + +// Wrapping skips upcoming blanks +static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) +{ + while (text < text_end && ImCharIsBlankA(*text)) + text++; + if (*text == '\n') + text++; + return text; +} + +// Simple word-wrapping for English, not full-featured. Please submit failing cases! +// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. +// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +{ + // For references, possible wrap point marked with ^ + // "aaa bbb, ccc,ddd. eee fff. ggg!" + // ^ ^ ^ ^ ^__ ^ ^ + + // List of hardcoded separators: .,;!?'" + + // Skip extra blanks after a line returns (that includes not counting them in width computation) + // e.g. "Hello world" --> "Hello" "World" + + // Cut words that cannot possibly fit within one line. + // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" + float line_width = 0.0f; + float word_width = 0.0f; + float blank_width = 0.0f; + wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters + + const char* word_end = text; + const char* prev_word_end = NULL; + bool inside_word = true; + + const char* s = text; + IM_ASSERT(text_end != NULL); + while (s < text_end) + { + unsigned int c = (unsigned int)*s; + const char* next_s; + if (c < 0x80) + next_s = s + 1; + else + next_s = s + ImTextCharFromUtf8(&c, s, text_end); + + if (c < 32) + { + if (c == '\n') + { + line_width = word_width = blank_width = 0.0f; + inside_word = true; + s = next_s; + continue; + } + if (c == '\r') + { + s = next_s; + continue; + } + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); + if (ImCharIsBlankW(c)) + { + if (inside_word) + { + line_width += blank_width; + blank_width = 0.0f; + word_end = s; + } + blank_width += char_width; + inside_word = false; + } + else + { + word_width += char_width; + if (inside_word) + { + word_end = next_s; + } + else + { + prev_word_end = word_end; + line_width += word_width + blank_width; + word_width = blank_width = 0.0f; + } + + // Allow wrapping after punctuation. + inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"'); + } + + // We ignore blank width at the end of the line (they can be skipped) + if (line_width + word_width > wrap_width) + { + // Words that cannot possibly fit within an entire line will be cut anywhere. + if (word_width < wrap_width) + s = prev_word_end ? prev_word_end : word_end; + break; + } + + s = next_s; + } + + // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. + // +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol). + if (s == text && text < text_end) + return s + 1; + return s; +} + +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. + + const float line_height = size; + const float scale = size / FontSize; + + ImVec2 text_size = ImVec2(0, 0); + float line_width = 0.0f; + + const bool word_wrap_enabled = (wrap_width > 0.0f); + const char* word_wrap_eol = NULL; + + const char* s = text_begin; + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); + + if (s >= word_wrap_eol) + { + if (text_size.x < line_width) + text_size.x = line_width; + text_size.y += line_height; + line_width = 0.0f; + word_wrap_eol = NULL; + s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks + continue; + } + } + + // Decode and advance source + const char* prev_s = s; + unsigned int c = (unsigned int)*s; + if (c < 0x80) + s += 1; + else + s += ImTextCharFromUtf8(&c, s, text_end); + + if (c < 32) + { + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + continue; + } + if (c == '\r') + continue; + } + + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; + if (line_width + char_width >= max_width) + { + s = prev_s; + break; + } + + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (line_width > 0 || text_size.y == 0.0f) + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. +void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const +{ + const ImFontGlyph* glyph = FindGlyph(c); + if (!glyph || !glyph->Visible) + return; + if (glyph->Colored) + col |= ~IM_COL32_A_MASK; + float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + float x = IM_FLOOR(pos.x); + float y = IM_FLOOR(pos.y); + draw_list->PrimReserve(6, 4); + draw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); +} + +// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. +void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const +{ + if (!text_end) + text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + + // Align to be pixel perfect + float x = IM_FLOOR(pos.x); + float y = IM_FLOOR(pos.y); + if (y > clip_rect.w) + return; + + const float start_x = x; + const float scale = size / FontSize; + const float line_height = FontSize * scale; + const bool word_wrap_enabled = (wrap_width > 0.0f); + + // Fast-forward to first visible line + const char* s = text_begin; + if (y + line_height < clip_rect.y) + while (y + line_height < clip_rect.y && s < text_end) + { + const char* line_end = (const char*)memchr(s, '\n', text_end - s); + if (word_wrap_enabled) + { + // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). + // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. + // However it is still better than nothing performing the fast-forward! + s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width); + s = CalcWordWrapNextLineStartA(s, text_end); + } + else + { + s = line_end ? line_end + 1 : text_end; + } + y += line_height; + } + + // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve() + // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm) + if (text_end - s > 10000 && !word_wrap_enabled) + { + const char* s_end = s; + float y_end = y; + while (y_end < clip_rect.w && s_end < text_end) + { + s_end = (const char*)memchr(s_end, '\n', text_end - s_end); + s_end = s_end ? s_end + 1 : text_end; + y_end += line_height; + } + text_end = s_end; + } + if (s == text_end) + return; + + // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) + const int vtx_count_max = (int)(text_end - s) * 4; + const int idx_count_max = (int)(text_end - s) * 6; + const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; + draw_list->PrimReserve(idx_count_max, vtx_count_max); + ImDrawVert* vtx_write = draw_list->_VtxWritePtr; + ImDrawIdx* idx_write = draw_list->_IdxWritePtr; + unsigned int vtx_index = draw_list->_VtxCurrentIdx; + + const ImU32 col_untinted = col | ~IM_COL32_A_MASK; + const char* word_wrap_eol = NULL; + + while (s < text_end) + { + if (word_wrap_enabled) + { + // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. + if (!word_wrap_eol) + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x)); + + if (s >= word_wrap_eol) + { + x = start_x; + y += line_height; + word_wrap_eol = NULL; + s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks + continue; + } + } + + // Decode and advance source + unsigned int c = (unsigned int)*s; + if (c < 0x80) + s += 1; + else + s += ImTextCharFromUtf8(&c, s, text_end); + + if (c < 32) + { + if (c == '\n') + { + x = start_x; + y += line_height; + if (y > clip_rect.w) + break; // break out of main loop + continue; + } + if (c == '\r') + continue; + } + + const ImFontGlyph* glyph = FindGlyph((ImWchar)c); + if (glyph == NULL) + continue; + + float char_width = glyph->AdvanceX * scale; + if (glyph->Visible) + { + // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; + if (x1 <= clip_rect.z && x2 >= clip_rect.x) + { + // Render a character + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + if (cpu_fine_clip) + { + if (x1 < clip_rect.x) + { + u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1); + x1 = clip_rect.x; + } + if (y1 < clip_rect.y) + { + v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1); + y1 = clip_rect.y; + } + if (x2 > clip_rect.z) + { + u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1); + x2 = clip_rect.z; + } + if (y2 > clip_rect.w) + { + v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1); + y2 = clip_rect.w; + } + if (y1 >= y2) + { + x += char_width; + continue; + } + } + + // Support for untinted glyphs + ImU32 glyph_col = glyph->Colored ? col_untinted : col; + + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: + { + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2); + idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3); + vtx_write += 4; + vtx_index += 4; + idx_write += 6; + } + } + } + x += char_width; + } + + // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. + draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() + draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); + draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size); + draw_list->_VtxWritePtr = vtx_write; + draw_list->_IdxWritePtr = idx_write; + draw_list->_VtxCurrentIdx = vtx_index; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImGui Internal Render Helpers +//----------------------------------------------------------------------------- +// Vaguely redesigned to stop accessing ImGui global state: +// - RenderArrow() +// - RenderBullet() +// - RenderCheckMark() +// - RenderArrowPointingAt() +// - RenderRectFilledRangeH() +// - RenderRectFilledWithHole() +//----------------------------------------------------------------------------- +// Function in need of a redesign (legacy mess) +// - RenderColorRectWithAlphaCheckerboard() +//----------------------------------------------------------------------------- + +// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state +void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale) +{ + const float h = draw_list->_Data->FontSize * 1.00f; + float r = h * 0.40f * scale; + ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale); + + ImVec2 a, b, c; + switch (dir) + { + case ImGuiDir_Up: + case ImGuiDir_Down: + if (dir == ImGuiDir_Up) r = -r; + a = ImVec2(+0.000f, +0.750f) * r; + b = ImVec2(-0.866f, -0.750f) * r; + c = ImVec2(+0.866f, -0.750f) * r; + break; + case ImGuiDir_Left: + case ImGuiDir_Right: + if (dir == ImGuiDir_Left) r = -r; + a = ImVec2(+0.750f, +0.000f) * r; + b = ImVec2(-0.750f, +0.866f) * r; + c = ImVec2(-0.750f, -0.866f) * r; + break; + case ImGuiDir_None: + case ImGuiDir_COUNT: + IM_ASSERT(0); + break; + } + draw_list->AddTriangleFilled(center + a, center + b, center + c, col); +} + +void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col) +{ + // FIXME-OPT: This should be baked in font. + draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8); +} + +void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) +{ + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness * 0.5f; + pos += ImVec2(thickness * 0.25f, thickness * 0.25f); + + float third = sz / 3.0f; + float bx = pos.x + third; + float by = pos.y + sz - third * 0.5f; + draw_list->PathLineTo(ImVec2(bx - third, by - third)); + draw_list->PathLineTo(ImVec2(bx, by)); + draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f)); + draw_list->PathStroke(col, 0, thickness); +} + +// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side. +void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col) +{ + switch (direction) + { + case ImGuiDir_Left: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_Up: draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return; + case ImGuiDir_Down: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return; + case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings + } +} + +static inline float ImAcos01(float x) +{ + if (x <= 0.0f) return IM_PI * 0.5f; + if (x >= 1.0f) return 0.0f; + return ImAcos(x); + //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do. +} + +// FIXME: Cleanup and move code to ImDrawList. +void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding) +{ + if (x_end_norm == x_start_norm) + return; + if (x_start_norm > x_end_norm) + ImSwap(x_start_norm, x_end_norm); + + ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y); + ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y); + if (rounding == 0.0f) + { + draw_list->AddRectFilled(p0, p1, col, 0.0f); + return; + } + + rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding); + const float inv_rounding = 1.0f / rounding; + const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding); + const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding); + const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return. + const float x0 = ImMax(p0.x, rect.Min.x + rounding); + if (arc0_b == arc0_e) + { + draw_list->PathLineTo(ImVec2(x0, p1.y)); + draw_list->PathLineTo(ImVec2(x0, p0.y)); + } + else if (arc0_b == 0.0f && arc0_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL + draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR + } + else + { + draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL + draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR + } + if (p1.x > rect.Min.x + rounding) + { + const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding); + const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding); + const float x1 = ImMin(p1.x, rect.Max.x - rounding); + if (arc1_b == arc1_e) + { + draw_list->PathLineTo(ImVec2(x1, p0.y)); + draw_list->PathLineTo(ImVec2(x1, p1.y)); + } + else if (arc1_b == 0.0f && arc1_e == half_pi) + { + draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR + draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR + } + else + { + draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR + draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR + } + } + draw_list->PathFillConvex(col); +} + +void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding) +{ + const bool fill_L = (inner.Min.x > outer.Min.x); + const bool fill_R = (inner.Max.x < outer.Max.x); + const bool fill_U = (inner.Min.y > outer.Min.y); + const bool fill_D = (inner.Max.y < outer.Max.y); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft); + if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight); + if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft); + if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight); +} + +// Helper for ColorPicker4() +// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that. +// Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether. +// FIXME: uses ImGui::GetColorU32 +void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags) +{ + if ((flags & ImDrawFlags_RoundCornersMask_) == 0) + flags = ImDrawFlags_RoundCornersDefault_; + if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) + { + ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); + ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); + draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); + + int yi = 0; + for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++) + { + float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); + if (y2 <= y1) + continue; + for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) + { + float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); + if (x2 <= x1) + continue; + ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; + if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; } + if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; } + + // Combine flags + cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags); + draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags); + } + } + } + else + { + draw_list->AddRectFilled(p_min, p_max, col, rounding, flags); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Decompression code +//----------------------------------------------------------------------------- +// Compressed with stb_compress() then converted to a C array and encoded as base85. +// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file. +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +// Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h +//----------------------------------------------------------------------------- + +static unsigned int stb_decompress_length(const unsigned char *input) +{ + return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]; +} + +static unsigned char *stb__barrier_out_e, *stb__barrier_out_b; +static const unsigned char *stb__barrier_in_b; +static unsigned char *stb__dout; +static void stb__match(const unsigned char *data, unsigned int length) +{ + // INVERSE of memmove... write each byte before copying the next... + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; } + while (length--) *stb__dout++ = *data++; +} + +static void stb__lit(const unsigned char *data, unsigned int length) +{ + IM_ASSERT(stb__dout + length <= stb__barrier_out_e); + if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; } + if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; } + memcpy(stb__dout, data, length); + stb__dout += length; +} + +#define stb__in2(x) ((i[x] << 8) + i[(x)+1]) +#define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1)) +#define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1)) + +static const unsigned char *stb_decompress_token(const unsigned char *i) +{ + if (*i >= 0x20) { // use fewer if's for cases that expand small + if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2; + else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3; + else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1); + } else { // more ifs for cases that expand large, since overhead is amortized + if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4; + else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5; + else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1); + else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1); + else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5; + else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6; + } + return i; +} + +static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen) +{ + const unsigned long ADLER_MOD = 65521; + unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; + unsigned long blocklen = buflen % 5552; + + unsigned long i; + while (buflen) { + for (i=0; i + 7 < blocklen; i += 8) { + s1 += buffer[0], s2 += s1; + s1 += buffer[1], s2 += s1; + s1 += buffer[2], s2 += s1; + s1 += buffer[3], s2 += s1; + s1 += buffer[4], s2 += s1; + s1 += buffer[5], s2 += s1; + s1 += buffer[6], s2 += s1; + s1 += buffer[7], s2 += s1; + + buffer += 8; + } + + for (; i < blocklen; ++i) + s1 += *buffer++, s2 += s1; + + s1 %= ADLER_MOD, s2 %= ADLER_MOD; + buflen -= blocklen; + blocklen = 5552; + } + return (unsigned int)(s2 << 16) + (unsigned int)s1; +} + +static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/) +{ + if (stb__in4(0) != 0x57bC0000) return 0; + if (stb__in4(4) != 0) return 0; // error! stream is > 4GB + const unsigned int olen = stb_decompress_length(i); + stb__barrier_in_b = i; + stb__barrier_out_e = output + olen; + stb__barrier_out_b = output; + i += 16; + + stb__dout = output; + for (;;) { + const unsigned char *old_i = i; + i = stb_decompress_token(i); + if (i == old_i) { + if (*i == 0x05 && i[1] == 0xfa) { + IM_ASSERT(stb__dout == output + olen); + if (stb__dout != output + olen) return 0; + if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2)) + return 0; + return olen; + } else { + IM_ASSERT(0); /* NOTREACHED */ + return 0; + } + } + IM_ASSERT(stb__dout <= output + olen); + if (stb__dout > output + olen) + return 0; + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Default font data (ProggyClean.ttf) +//----------------------------------------------------------------------------- +// ProggyClean.ttf +// Copyright (c) 2004, 2005 Tristan Grimmer +// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip) +// Download and more information at http://upperbounds.net +//----------------------------------------------------------------------------- +// File: 'ProggyClean.ttf' (41208 bytes) +// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +//----------------------------------------------------------------------------- +static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = + "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" + "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" + "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." + "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" + "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" + "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" + "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" + "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" + "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" + "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" + "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" + "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" + "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" + "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" + "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" + "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" + "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" + "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" + "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" + "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" + "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" + ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" + "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" + "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" + "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" + "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" + "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" + "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" + "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" + "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" + "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" + "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" + "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" + "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" + "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" + "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" + "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" + ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" + "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" + "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" + "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" + "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" + "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" + "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" + ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" + "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" + "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" + "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" + "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" + "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; + +static const char* GetDefaultCompressedFontDataTTFBase85() +{ + return proggy_clean_ttf_compressed_data_base85; +} + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_impl_dx9.cpp b/Amalgam/include/ImGui/imgui_impl_dx9.cpp new file mode 100644 index 0000000..8940dfe --- /dev/null +++ b/Amalgam/include/ImGui/imgui_impl_dx9.cpp @@ -0,0 +1,385 @@ +// dear imgui: Renderer Backend for DirectX9 +// This needs to be used along with a Platform Backend (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. +// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). +// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1. +// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) +// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states. +// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857). +// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file. +// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer. +// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. +// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. +// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). +// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288. +// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. +// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example. +// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. +// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud. +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself. +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_impl_dx9.h" + +// DirectX +#include + +// DirectX data +struct ImGui_ImplDX9_Data +{ + LPDIRECT3DDEVICE9 pd3dDevice; + LPDIRECT3DVERTEXBUFFER9 pVB; + LPDIRECT3DINDEXBUFFER9 pIB; + LPDIRECT3DTEXTURE9 FontTexture; + int VertexBufferSize; + int IndexBufferSize; + + ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } +}; + +struct CUSTOMVERTEX +{ + float pos[3]; + D3DCOLOR col; + float uv[2]; +}; +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) + +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL) +#else +#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16)) +#endif + +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; +} + +// Functions +static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) +{ + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + + // Setup viewport + D3DVIEWPORT9 vp; + vp.X = vp.Y = 0; + vp.Width = (DWORD)draw_data->DisplaySize.x; + vp.Height = (DWORD)draw_data->DisplaySize.y; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + bd->pd3dDevice->SetViewport(&vp); + + // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. + bd->pd3dDevice->SetPixelShader(nullptr); + bd->pd3dDevice->SetVertexShader(nullptr); + bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + // Setup orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() + { + float L = draw_data->DisplayPos.x + 0.5f; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f; + float T = draw_data->DisplayPos.y + 0.5f; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f; + D3DMATRIX mat_identity = { { { 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 } } }; + D3DMATRIX mat_projection = + { { { + 2.0f/(R-L), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f/(T-B), 0.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f, + (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f + } } }; + bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); + bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); + bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); + } +} + +// Render function. +void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized + if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) + return; + + // Create and grow buffers if needed + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) + { + if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } + bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; + if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0) + return; + } + if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) + { + if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } + bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; + if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0) + return; + } + + // Backup the DX9 state + IDirect3DStateBlock9* d3d9_state_block = nullptr; + if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) + return; + if (d3d9_state_block->Capture() < 0) + { + d3d9_state_block->Release(); + return; + } + + // Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to) + D3DMATRIX last_world, last_view, last_projection; + bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); + bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); + bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); + + // Allocate buffers + CUSTOMVERTEX* vtx_dst; + ImDrawIdx* idx_dst; + if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) + { + d3d9_state_block->Release(); + return; + } + if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0) + { + bd->pVB->Unlock(); + d3d9_state_block->Release(); + return; + } + + // Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format. + // FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and + // 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR + // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; } + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) + { + vtx_dst->pos[0] = vtx_src->pos.x; + vtx_dst->pos[1] = vtx_src->pos.y; + vtx_dst->pos[2] = 0.0f; + vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col); + vtx_dst->uv[0] = vtx_src->uv.x; + vtx_dst->uv[1] = vtx_src->uv.y; + vtx_dst++; + vtx_src++; + } + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + idx_dst += cmd_list->IdxBuffer.Size; + } + bd->pVB->Unlock(); + bd->pIB->Unlock(); + bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX)); + bd->pd3dDevice->SetIndices(bd->pIB); + bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); + + // Setup desired DX state + ImGui_ImplDX9_SetupRenderState(draw_data); + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + int global_vtx_offset = 0; + int global_idx_offset = 0; + ImVec2 clip_off = draw_data->DisplayPos; + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != nullptr) + { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplDX9_SetupRenderState(draw_data); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); + ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply Scissor/clipping rectangle, Bind texture, Draw + const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; + const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID(); + bd->pd3dDevice->SetTexture(0, texture); + bd->pd3dDevice->SetScissorRect(&r); + bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); + } + } + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; + } + + // Restore the DX9 transform + bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world); + bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view); + bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection); + + // Restore the DX9 state + d3d9_state_block->Apply(); + d3d9_state_block->Release(); +} + +bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Setup backend capabilities flags + ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_dx9"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + + bd->pd3dDevice = device; + bd->pd3dDevice->AddRef(); + + return true; +} + +void ImGui_ImplDX9_Shutdown() +{ + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplDX9_InvalidateDeviceObjects(); + if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + IM_DELETE(bd); +} + +static bool ImGui_ImplDX9_CreateFontsTexture() +{ + // Build texture atlas + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + unsigned char* pixels; + int width, height, bytes_per_pixel; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); + + // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + if (io.Fonts->TexPixelsUseColors) + { + ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); + for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) + *dst = IMGUI_COL_TO_DX9_ARGB(*src); + pixels = (unsigned char*)dst_start; + } +#endif + + // Upload texture to graphics system + bd->FontTexture = nullptr; + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) + return false; + D3DLOCKED_RECT tex_locked_rect; + if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) + return false; + for (int y = 0; y < height; y++) + memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); + bd->FontTexture->UnlockRect(0); + + // Store our identifier + io.Fonts->SetTexID((ImTextureID)bd->FontTexture); + +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + if (io.Fonts->TexPixelsUseColors) + ImGui::MemFree(pixels); +#endif + + return true; +} + +bool ImGui_ImplDX9_CreateDeviceObjects() +{ + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + if (!bd || !bd->pd3dDevice) + return false; + if (!ImGui_ImplDX9_CreateFontsTexture()) + return false; + return true; +} + +void ImGui_ImplDX9_InvalidateDeviceObjects() +{ + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + if (!bd || !bd->pd3dDevice) + return; + if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } + if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } + if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. +} + +void ImGui_ImplDX9_NewFrame() +{ + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX9_Init()?"); + + if (!bd->FontTexture) + ImGui_ImplDX9_CreateDeviceObjects(); +} + +//----------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_impl_dx9.h b/Amalgam/include/ImGui/imgui_impl_dx9.h new file mode 100644 index 0000000..95e64c6 --- /dev/null +++ b/Amalgam/include/ImGui/imgui_impl_dx9.h @@ -0,0 +1,28 @@ +// dear imgui: Renderer Backend for DirectX9 +// This needs to be used along with a Platform Backend (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API +#ifndef IMGUI_DISABLE + +struct IDirect3DDevice9; + +IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device); +IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); + +// Use if you want to reset your rendering device without losing Dear ImGui state. +IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects(); + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_impl_win32.cpp b/Amalgam/include/ImGui/imgui_impl_win32.cpp new file mode 100644 index 0000000..0993ecf --- /dev/null +++ b/Amalgam/include/ImGui/imgui_impl_win32.cpp @@ -0,0 +1,864 @@ +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) +// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_impl_win32.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include // GET_X_LPARAM(), GET_Y_LPARAM() +#include +#include + +// Configuration flags to add in your imconfig.h file: +//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant. + +// Using XInput for gamepad (will load DLL dynamically) +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +#include +typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*); +typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); +#endif + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2023-04-19: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw Win32/Winapi with OpenGL. (#3218) +// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen. (#2702) +// 2023-02-15: Inputs: Use WM_NCMOUSEMOVE / WM_NCMOUSELEAVE to track mouse position over non-client area (e.g. OS decorations) when app is not focused. (#6045, #6162) +// 2023-02-02: Inputs: Flipping WM_MOUSEHWHEEL (horizontal mouse-wheel) value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463) +// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. +// 2022-09-28: Inputs: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode). +// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). +// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion. +// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[]. +// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). +// 2022-01-17: Inputs: always update key mods next and before a key event (not in NewFrame) to fix input queue with very low framerates. +// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API. +// 2022-01-12: Inputs: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. +// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. +// 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness. +// 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages. +// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus. +// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events). +// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). +// 2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1). +// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS). +// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi). +// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1. +// 2021-01-25: Inputs: Dynamically loading XInput DLL. +// 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed. +// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs) +// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions. +// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT. +// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor. +// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter(). +// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent. +// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages. +// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application). +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads). +// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert. +// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag. +// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read. +// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging. +// 2016-11-12: Inputs: Only call Win32 ::SetCursor(nullptr) when io.MouseDrawCursor is set. + +struct ImGui_ImplWin32_Data +{ + HWND hWnd; + HWND MouseHwnd; + int MouseTrackedArea; // 0: not tracked, 1: client are, 2: non-client area + int MouseButtonsDown; + INT64 Time; + INT64 TicksPerSecond; + ImGuiMouseCursor LastMouseCursor; + +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + bool HasGamepad; + bool WantUpdateHasGamepad; + HMODULE XInputDLL; + PFN_XInputGetCapabilities XInputGetCapabilities; + PFN_XInputGetState XInputGetState; +#endif + + ImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); } +}; + +// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support is not well tested and probably dysfunctional in this backend. +// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; +} + +// Functions +static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); + + INT64 perf_frequency, perf_counter; + if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency)) + return false; + if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter)) + return false; + + // Setup backend capabilities flags + ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)(); + io.BackendPlatformUserData = (void*)bd; + io.BackendPlatformName = "imgui_impl_win32"; + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + + bd->hWnd = (HWND)hwnd; + bd->TicksPerSecond = perf_frequency; + bd->Time = perf_counter; + bd->LastMouseCursor = ImGuiMouseCursor_COUNT; + + // Set platform dependent data in viewport + ImGui::GetMainViewport()->PlatformHandleRaw = (void*)hwnd; + IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch + + // Dynamically load XInput library +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + bd->WantUpdateHasGamepad = true; + const char* xinput_dll_names[] = + { + "xinput1_4.dll", // Windows 8+ + "xinput1_3.dll", // DirectX SDK + "xinput9_1_0.dll", // Windows Vista, Windows 7 + "xinput1_2.dll", // DirectX SDK + "xinput1_1.dll" // DirectX SDK + }; + for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++) + if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n])) + { + bd->XInputDLL = dll; + bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities"); + bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState"); + break; + } +#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + + return true; +} + +IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd) +{ + return ImGui_ImplWin32_InitEx(hwnd, false); +} + +IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd) +{ + // OpenGL needs CS_OWNDC + return ImGui_ImplWin32_InitEx(hwnd, true); +} + +void ImGui_ImplWin32_Shutdown() +{ + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + // Unload XInput library +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + if (bd->XInputDLL) + ::FreeLibrary(bd->XInputDLL); +#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + + io.BackendPlatformName = nullptr; + io.BackendPlatformUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + IM_DELETE(bd); +} + +static bool ImGui_ImplWin32_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return false; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(nullptr); + } + else + { + // Show OS mouse cursor + LPTSTR win32_cursor = IDC_ARROW; + switch (imgui_cursor) + { + case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; + case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; + case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; + case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; + case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; + case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; + case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; + case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; + case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break; + } + ::SetCursor(::LoadCursor(nullptr, win32_cursor)); + } + return true; +} + +static bool IsVkDown(int vk) +{ + return (::GetKeyState(vk) & 0x8000) != 0; +} + +static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddKeyEvent(key, down); + io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code) + IM_UNUSED(native_scancode); +} + +static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds() +{ + // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one. + if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT)) + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT); + if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT)) + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT); + + // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW). + if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN)) + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN); + if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN)) + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN); +} + +static void ImGui_ImplWin32_UpdateKeyModifiers() +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL)); + io.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT)); + io.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU)); + io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_APPS)); +} + +static void ImGui_ImplWin32_UpdateMouseData() +{ + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(bd->hWnd != 0); + + HWND focused_window = ::GetForegroundWindow(); + const bool is_app_focused = (focused_window == bd->hWnd); + if (is_app_focused) + { + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + { + POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; + if (::ClientToScreen(bd->hWnd, &pos)) + ::SetCursorPos(pos.x, pos.y); + } + + // (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured) + // This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE + if (!io.WantSetMousePos && bd->MouseTrackedArea == 0) + { + POINT pos; + if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos)) + io.AddMousePosEvent((float)pos.x, (float)pos.y); + } + } +} + +// Gamepad navigation mapping +static void ImGui_ImplWin32_UpdateGamepads() +{ +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. + // return; + + // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. + // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. + if (bd->WantUpdateHasGamepad) + { + XINPUT_CAPABILITIES caps = {}; + bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false; + bd->WantUpdateHasGamepad = false; + } + + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + XINPUT_STATE xinput_state; + XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; + if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS) + return; + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + + #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) + #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); } + #define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); } + MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START); + MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK); + MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X); + MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B); + MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y); + MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A); + MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); + MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); + MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP); + MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN); + MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER); + MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER); + MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255); + MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255); + MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB); + MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB); + MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767); + MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); + #undef MAP_BUTTON + #undef MAP_ANALOG +#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +} + +void ImGui_ImplWin32_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplWin32_Init()?"); + + // Setup display size (every frame to accommodate for window resizing) + RECT rect = { 0, 0, 0, 0 }; + ::GetClientRect(bd->hWnd, &rect); + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + + // Setup time step + INT64 current_time = 0; + ::QueryPerformanceCounter((LARGE_INTEGER*)¤t_time); + io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond; + bd->Time = current_time; + + // Update OS mouse position + ImGui_ImplWin32_UpdateMouseData(); + + // Process workarounds for known Windows key handling issues + ImGui_ImplWin32_ProcessKeyEventsWorkarounds(); + + // Update OS mouse cursor with the cursor requested by imgui + ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (bd->LastMouseCursor != mouse_cursor) + { + bd->LastMouseCursor = mouse_cursor; + ImGui_ImplWin32_UpdateMouseCursor(); + } + + // Update game controllers (if enabled and available) + ImGui_ImplWin32_UpdateGamepads(); +} + +// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255) +#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256) + +// Map VK_xxx to ImGuiKey_xxx. +static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam) +{ + switch (wParam) + { + case VK_TAB: return ImGuiKey_Tab; + case VK_LEFT: return ImGuiKey_LeftArrow; + case VK_RIGHT: return ImGuiKey_RightArrow; + case VK_UP: return ImGuiKey_UpArrow; + case VK_DOWN: return ImGuiKey_DownArrow; + case VK_PRIOR: return ImGuiKey_PageUp; + case VK_NEXT: return ImGuiKey_PageDown; + case VK_HOME: return ImGuiKey_Home; + case VK_END: return ImGuiKey_End; + case VK_INSERT: return ImGuiKey_Insert; + case VK_DELETE: return ImGuiKey_Delete; + case VK_BACK: return ImGuiKey_Backspace; + case VK_SPACE: return ImGuiKey_Space; + case VK_RETURN: return ImGuiKey_Enter; + case VK_ESCAPE: return ImGuiKey_Escape; + case VK_OEM_7: return ImGuiKey_Apostrophe; + case VK_OEM_COMMA: return ImGuiKey_Comma; + case VK_OEM_MINUS: return ImGuiKey_Minus; + case VK_OEM_PERIOD: return ImGuiKey_Period; + case VK_OEM_2: return ImGuiKey_Slash; + case VK_OEM_1: return ImGuiKey_Semicolon; + case VK_OEM_PLUS: return ImGuiKey_Equal; + case VK_OEM_4: return ImGuiKey_LeftBracket; + case VK_OEM_5: return ImGuiKey_Backslash; + case VK_OEM_6: return ImGuiKey_RightBracket; + case VK_OEM_3: return ImGuiKey_GraveAccent; + case VK_CAPITAL: return ImGuiKey_CapsLock; + case VK_SCROLL: return ImGuiKey_ScrollLock; + case VK_NUMLOCK: return ImGuiKey_NumLock; + case VK_SNAPSHOT: return ImGuiKey_PrintScreen; + case VK_PAUSE: return ImGuiKey_Pause; + case VK_NUMPAD0: return ImGuiKey_Keypad0; + case VK_NUMPAD1: return ImGuiKey_Keypad1; + case VK_NUMPAD2: return ImGuiKey_Keypad2; + case VK_NUMPAD3: return ImGuiKey_Keypad3; + case VK_NUMPAD4: return ImGuiKey_Keypad4; + case VK_NUMPAD5: return ImGuiKey_Keypad5; + case VK_NUMPAD6: return ImGuiKey_Keypad6; + case VK_NUMPAD7: return ImGuiKey_Keypad7; + case VK_NUMPAD8: return ImGuiKey_Keypad8; + case VK_NUMPAD9: return ImGuiKey_Keypad9; + case VK_DECIMAL: return ImGuiKey_KeypadDecimal; + case VK_DIVIDE: return ImGuiKey_KeypadDivide; + case VK_MULTIPLY: return ImGuiKey_KeypadMultiply; + case VK_SUBTRACT: return ImGuiKey_KeypadSubtract; + case VK_ADD: return ImGuiKey_KeypadAdd; + case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter; + case VK_LSHIFT: return ImGuiKey_LeftShift; + case VK_LCONTROL: return ImGuiKey_LeftCtrl; + case VK_LMENU: return ImGuiKey_LeftAlt; + case VK_LWIN: return ImGuiKey_LeftSuper; + case VK_RSHIFT: return ImGuiKey_RightShift; + case VK_RCONTROL: return ImGuiKey_RightCtrl; + case VK_RMENU: return ImGuiKey_RightAlt; + case VK_RWIN: return ImGuiKey_RightSuper; + case VK_APPS: return ImGuiKey_Menu; + case '0': return ImGuiKey_0; + case '1': return ImGuiKey_1; + case '2': return ImGuiKey_2; + case '3': return ImGuiKey_3; + case '4': return ImGuiKey_4; + case '5': return ImGuiKey_5; + case '6': return ImGuiKey_6; + case '7': return ImGuiKey_7; + case '8': return ImGuiKey_8; + case '9': return ImGuiKey_9; + case 'A': return ImGuiKey_A; + case 'B': return ImGuiKey_B; + case 'C': return ImGuiKey_C; + case 'D': return ImGuiKey_D; + case 'E': return ImGuiKey_E; + case 'F': return ImGuiKey_F; + case 'G': return ImGuiKey_G; + case 'H': return ImGuiKey_H; + case 'I': return ImGuiKey_I; + case 'J': return ImGuiKey_J; + case 'K': return ImGuiKey_K; + case 'L': return ImGuiKey_L; + case 'M': return ImGuiKey_M; + case 'N': return ImGuiKey_N; + case 'O': return ImGuiKey_O; + case 'P': return ImGuiKey_P; + case 'Q': return ImGuiKey_Q; + case 'R': return ImGuiKey_R; + case 'S': return ImGuiKey_S; + case 'T': return ImGuiKey_T; + case 'U': return ImGuiKey_U; + case 'V': return ImGuiKey_V; + case 'W': return ImGuiKey_W; + case 'X': return ImGuiKey_X; + case 'Y': return ImGuiKey_Y; + case 'Z': return ImGuiKey_Z; + case VK_F1: return ImGuiKey_F1; + case VK_F2: return ImGuiKey_F2; + case VK_F3: return ImGuiKey_F3; + case VK_F4: return ImGuiKey_F4; + case VK_F5: return ImGuiKey_F5; + case VK_F6: return ImGuiKey_F6; + case VK_F7: return ImGuiKey_F7; + case VK_F8: return ImGuiKey_F8; + case VK_F9: return ImGuiKey_F9; + case VK_F10: return ImGuiKey_F10; + case VK_F11: return ImGuiKey_F11; + case VK_F12: return ImGuiKey_F12; + default: return ImGuiKey_None; + } +} + +// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif +#ifndef DBT_DEVNODES_CHANGED +#define DBT_DEVNODES_CHANGED 0x0007 +#endif + +// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) +// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. +// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. +// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. +#if 0 +// Copy this line into your .cpp file to forward declare the function. +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +// See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages +// Prefer to call this at the top of the message handler to avoid the possibility of other Win32 calls interfering with this. +static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() +{ + LPARAM extra_info = ::GetMessageExtraInfo(); + if ((extra_info & 0xFFFFFF80) == 0xFF515700) + return ImGuiMouseSource_Pen; + if ((extra_info & 0xFFFFFF80) == 0xFF515780) + return ImGuiMouseSource_TouchScreen; + return ImGuiMouseSource_Mouse; +} + +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui::GetCurrentContext() == nullptr) + return 0; + + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + + switch (msg) + { + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + { + // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events + ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); + const int area = (msg == WM_MOUSEMOVE) ? 1 : 2; + bd->MouseHwnd = hwnd; + if (bd->MouseTrackedArea != area) + { + TRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 }; + TRACKMOUSEEVENT tme_track = { sizeof(tme_track), (DWORD)((area == 2) ? (TME_LEAVE | TME_NONCLIENT) : TME_LEAVE), hwnd, 0 }; + if (bd->MouseTrackedArea != 0) + ::TrackMouseEvent(&tme_cancel); + ::TrackMouseEvent(&tme_track); + bd->MouseTrackedArea = area; + } + POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) }; + if (msg == WM_NCMOUSEMOVE && ::ScreenToClient(hwnd, &mouse_pos) == FALSE) // WM_NCMOUSEMOVE are provided in absolute coordinates. + break; + io.AddMouseSourceEvent(mouse_source); + io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y); + break; + } + case WM_MOUSELEAVE: + case WM_NCMOUSELEAVE: + { + const int area = (msg == WM_MOUSELEAVE) ? 1 : 2; + if (bd->MouseTrackedArea == area) + { + if (bd->MouseHwnd == hwnd) + bd->MouseHwnd = nullptr; + bd->MouseTrackedArea = 0; + io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); + } + break; + } + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: + { + ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); + int button = 0; + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } + if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } + if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } + if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } + if (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr) + ::SetCapture(hwnd); + bd->MouseButtonsDown |= 1 << button; + io.AddMouseSourceEvent(mouse_source); + io.AddMouseButtonEvent(button, true); + return 0; + } + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + { + ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); + int button = 0; + if (msg == WM_LBUTTONUP) { button = 0; } + if (msg == WM_RBUTTONUP) { button = 1; } + if (msg == WM_MBUTTONUP) { button = 2; } + if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } + bd->MouseButtonsDown &= ~(1 << button); + if (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd) + ::ReleaseCapture(); + io.AddMouseSourceEvent(mouse_source); + io.AddMouseButtonEvent(button, false); + return 0; + } + case WM_MOUSEWHEEL: + io.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA); + return 0; + case WM_MOUSEHWHEEL: + io.AddMouseWheelEvent(-(float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f); + return 0; + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + { + const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN); + if (wParam < 256) + { + // Submit modifiers + ImGui_ImplWin32_UpdateKeyModifiers(); + + // Obtain virtual key code + // (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.) + int vk = (int)wParam; + if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED)) + vk = IM_VK_KEYPAD_ENTER; + + // Submit key event + const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk); + const int scancode = (int)LOBYTE(HIWORD(lParam)); + if (key != ImGuiKey_None) + ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode); + + // Submit individual left/right modifier events + if (vk == VK_SHIFT) + { + // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds() + if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } + if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } + } + else if (vk == VK_CONTROL) + { + if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } + if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } + } + else if (vk == VK_MENU) + { + if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } + if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } + } + } + return 0; + } + case WM_SETFOCUS: + case WM_KILLFOCUS: + io.AddFocusEvent(msg == WM_SETFOCUS); + return 0; + case WM_CHAR: + if (::IsWindowUnicode(hwnd)) + { + // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + if (wParam > 0 && wParam < 0x10000) + io.AddInputCharacterUTF16((unsigned short)wParam); + } + else + { + wchar_t wch = 0; + ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char*)&wParam, 1, &wch, 1); + io.AddInputCharacter(wch); + } + return 0; + case WM_SETCURSOR: + // This is required to restore cursor when transitioning from e.g resize borders to client area. + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + return 1; + return 0; + case WM_DEVICECHANGE: +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + if ((UINT)wParam == DBT_DEVNODES_CHANGED) + bd->WantUpdateHasGamepad = true; +#endif + return 0; + } + return 0; +} + + +//-------------------------------------------------------------------------------------------------------- +// DPI-related helpers (optional) +//-------------------------------------------------------------------------------------------------------- +// - Use to enable DPI awareness without having to create an application manifest. +// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. +// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. +// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, +// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. +//--------------------------------------------------------------------------------------------------------- +// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable. +// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically. +// If you are trying to implement your own backend for your own engine, you may ignore that noise. +//--------------------------------------------------------------------------------------------------------- + +// Perform our own check with RtlVerifyVersionInfo() instead of using functions from as they +// require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200 +static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) +{ + typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG); + static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = nullptr; + if (RtlVerifyVersionInfoFn == nullptr) + if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll")) + RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo"); + if (RtlVerifyVersionInfoFn == nullptr) + return FALSE; + + RTL_OSVERSIONINFOEXW versionInfo = { }; + ULONGLONG conditionMask = 0; + versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + versionInfo.dwMajorVersion = major; + versionInfo.dwMinorVersion = minor; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE; +} + +#define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA +#define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8 +#define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE +#define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10 + +#ifndef DPI_ENUMS_DECLARED +typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; +typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE; +#endif +#ifndef _DPI_AWARENESS_CONTEXTS_ +DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3 +#endif +#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4 +#endif +typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+ +typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+ +typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update) + +// Helper function to enable DPI awareness without setting up a manifest +void ImGui_ImplWin32_EnableDpiAwareness() +{ + if (_IsWindows10OrGreater()) + { + static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process + if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) + { + SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + return; + } + } + if (_IsWindows8Point1OrGreater()) + { + static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process + if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness")) + { + SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE); + return; + } + } +#if _WIN32_WINNT >= 0x0600 + ::SetProcessDPIAware(); +#endif +} + +#if defined(_MSC_VER) && !defined(NOGDI) +#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32' +#endif + +float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) +{ + UINT xdpi = 96, ydpi = 96; + if (_IsWindows8Point1OrGreater()) + { + static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process + static PFN_GetDpiForMonitor GetDpiForMonitorFn = nullptr; + if (GetDpiForMonitorFn == nullptr && shcore_dll != nullptr) + GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"); + if (GetDpiForMonitorFn != nullptr) + { + GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! + return xdpi / 96.0f; + } + } +#ifndef NOGDI + const HDC dc = ::GetDC(nullptr); + xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); + ydpi = ::GetDeviceCaps(dc, LOGPIXELSY); + IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! + ::ReleaseDC(nullptr, dc); +#endif + return xdpi / 96.0f; +} + +float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd) +{ + HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST); + return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); +} + +//--------------------------------------------------------------------------------------------------------- +// Transparency related helpers (optional) +//-------------------------------------------------------------------------------------------------------- + +#if defined(_MSC_VER) +#pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi' +#endif + +// [experimental] +// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c +// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW) +void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd) +{ + if (!_IsWindowsVistaOrGreater()) + return; + + BOOL composition; + if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition) + return; + + BOOL opaque; + DWORD color; + if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque)) + { + HRGN region = ::CreateRectRgn(0, 0, -1, -1); + DWM_BLURBEHIND bb = {}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = region; + bb.fEnable = TRUE; + ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); + ::DeleteObject(region); + } + else + { + DWM_BLURBEHIND bb = {}; + bb.dwFlags = DWM_BB_ENABLE; + ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); + } +} + +//--------------------------------------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_impl_win32.h b/Amalgam/include/ImGui/imgui_impl_win32.h new file mode 100644 index 0000000..08f657d --- /dev/null +++ b/Amalgam/include/ImGui/imgui_impl_win32.h @@ -0,0 +1,49 @@ +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) + +// Implemented features: +// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) +// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API +#ifndef IMGUI_DISABLE + +IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); +IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); +IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); + +// Win32 message handler your application need to call. +// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. +// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. +// - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. + +#if 0 +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + +// DPI-related helpers (optional) +// - Use to enable DPI awareness without having to create an application manifest. +// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. +// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. +// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, +// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. +IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd +IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor + +// Transparency related helpers (optional) [experimental] +// - Use to enable alpha compositing transparency with the desktop. +// - Use together with e.g. clearing your framebuffer with zero-alpha. +IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_internal.h b/Amalgam/include/ImGui/imgui_internal.h new file mode 100644 index 0000000..4e35a20 --- /dev/null +++ b/Amalgam/include/ImGui/imgui_internal.h @@ -0,0 +1,3335 @@ +// dear imgui, v1.89.8 +// (internal structures/api) + +// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. +// To implement maths operators for ImVec2 (disabled by default to not conflict with using IM_VEC2_CLASS_EXTRA with your own math types+operators), use: +/* +#define IMGUI_DEFINE_MATH_OPERATORS +#include "imgui_internal.h" +*/ + +/* + +Index of this file: + +// [SECTION] Header mess +// [SECTION] Forward declarations +// [SECTION] Context pointer +// [SECTION] STB libraries includes +// [SECTION] Macros +// [SECTION] Generic helpers +// [SECTION] ImDrawList support +// [SECTION] Widgets support: flags, enums, data structures +// [SECTION] Inputs support +// [SECTION] Clipper support +// [SECTION] Navigation support +// [SECTION] Columns support +// [SECTION] Multi-select support +// [SECTION] Docking support +// [SECTION] Viewport support +// [SECTION] Settings support +// [SECTION] Localization support +// [SECTION] Metrics, Debug tools +// [SECTION] Generic context hooks +// [SECTION] ImGuiContext (main imgui context) +// [SECTION] ImGuiWindowTempData, ImGuiWindow +// [SECTION] Tab bar, Tab item support +// [SECTION] Table support +// [SECTION] ImGui internal API +// [SECTION] ImFontAtlas internal API +// [SECTION] Test Engine specific hooks (imgui_test_engine) + +*/ + +#pragma once +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#ifndef IMGUI_VERSION +#include "imgui.h" +#endif + +#include // FILE*, sscanf +#include // NULL, malloc, free, qsort, atoi, atof +#include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf +#include // INT_MIN, INT_MAX + +// Enable SSE intrinsics if available +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) +#define IMGUI_ENABLE_SSE +#include +#endif + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport) +#pragma warning (disable: 26812) // The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer) +#pragma warning (disable: 26495) // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6). +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloorSigned() +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn' +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +// In 1.89.4, we moved the implementation of "courtesy maths operators" from imgui_internal.h in imgui.h +// As they are frequently requested, we do not want to encourage to many people using imgui_internal.h +#if defined(IMGUI_DEFINE_MATH_OPERATORS) && !defined(IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED) +#error Please '#define IMGUI_DEFINE_MATH_OPERATORS' _BEFORE_ including imgui.h! +#endif + +// Legacy defines +#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_MATH_FUNCTIONS // Renamed in 1.74 +#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#endif + +// Enable stb_truetype by default unless FreeType is enabled. +// You can compile with both by defining both IMGUI_ENABLE_FREETYPE and IMGUI_ENABLE_STB_TRUETYPE together. +#ifndef IMGUI_ENABLE_FREETYPE +#define IMGUI_ENABLE_STB_TRUETYPE +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Forward declarations +//----------------------------------------------------------------------------- + +struct ImBitVector; // Store 1-bit per value +struct ImRect; // An axis-aligned rectangle (2 points) +struct ImDrawDataBuilder; // Helper to build a ImDrawData instance +struct ImDrawListSharedData; // Data shared between all ImDrawList instances +struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it +struct ImGuiContext; // Main Dear ImGui context +struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine +struct ImGuiDataVarInfo; // Variable information (e.g. to avoid style variables from an enum) +struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum +struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() +struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box +struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id +struct ImGuiLastItemData; // Status storage for last submitted items +struct ImGuiLocEntry; // A localization entry. +struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only +struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result +struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions +struct ImGuiNextWindowData; // Storage for SetNextWindow** functions +struct ImGuiNextItemData; // Storage for SetNextItem** functions +struct ImGuiOldColumnData; // Storage data for a single column for legacy Columns() api +struct ImGuiOldColumns; // Storage data for a columns set for legacy Columns() api +struct ImGuiPopupData; // Storage for current popup stack +struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStackSizes; // Storage of stack sizes for debugging/asserting +struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it +struct ImGuiTabBar; // Storage for a tab bar +struct ImGuiTabItem; // Storage for a tab item (within a tab bar) +struct ImGuiTable; // Storage for a table +struct ImGuiTableColumn; // Storage for one column of a table +struct ImGuiTableInstanceData; // Storage for one instance of a same table +struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables. +struct ImGuiTableSettings; // Storage for a table .ini settings +struct ImGuiTableColumnsSettings; // Storage for a column .ini settings +struct ImGuiWindow; // Storage for one window +struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window) +struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) + +// Enumerations +// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +enum ImGuiLocKey : int; // -> enum ImGuiLocKey // Enum: a localization entry for translation. +typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical + +// Flags +typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) +typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags +typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow(); +typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for IsKeyPressed(), IsMouseClicked(), SetKeyOwner(), SetItemKeyOwner() etc. +typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags +typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags +typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() +typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() +typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests +typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions +typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions +typedef int ImGuiScrollFlags; // -> enum ImGuiScrollFlags_ // Flags: for ScrollToItem() and navigation requests +typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx() +typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx() +typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // Flags: for BeginTooltipEx() + +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); + +//----------------------------------------------------------------------------- +// [SECTION] Context pointer +// See implementation of this variable in imgui.cpp for comments and details. +//----------------------------------------------------------------------------- + +#ifndef GImGui +extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer +#endif + +//------------------------------------------------------------------------- +// [SECTION] STB libraries includes +//------------------------------------------------------------------------- + +namespace ImStb +{ + +#undef STB_TEXTEDIT_STRING +#undef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_STRING ImGuiInputTextState +#define STB_TEXTEDIT_CHARTYPE ImWchar +#define STB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#include "imstb_textedit.h" + +} // namespace ImStb + +//----------------------------------------------------------------------------- +// [SECTION] Macros +//----------------------------------------------------------------------------- + +// Debug Printing Into TTY +// (since IMGUI_VERSION_NUM >= 18729: IMGUI_DEBUG_LOG was reworked into IMGUI_DEBUG_PRINTF (and removed framecount from it). If you were using a #define IMGUI_DEBUG_LOG please rename) +#ifndef IMGUI_DEBUG_PRINTF +#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS +#define IMGUI_DEBUG_PRINTF(_FMT,...) printf(_FMT, __VA_ARGS__) +#else +#define IMGUI_DEBUG_PRINTF(_FMT,...) ((void)0) +#endif +#endif + +// Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) +#else +#define IMGUI_DEBUG_LOG(...) ((void)0) +#endif +#define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) + +// Static Asserts +#define IM_STATIC_ASSERT(_COND) static_assert(_COND, "") + +// "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much. +// We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code. +//#define IMGUI_DEBUG_PARANOID +#ifdef IMGUI_DEBUG_PARANOID +#define IM_ASSERT_PARANOID(_EXPR) IM_ASSERT(_EXPR) +#else +#define IM_ASSERT_PARANOID(_EXPR) +#endif + +// Error handling +// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. +#ifndef IM_ASSERT_USER_ERROR +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error +#endif + +// Misc Macros +#define IM_PI 3.14159265358979323846f +#ifdef _WIN32 +#define IM_NEWLINE "\r\n" // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!) +#else +#define IM_NEWLINE "\n" +#endif +#ifndef IM_TABSIZE // Until we move this to runtime and/or add proper tab support, at least allow users to compile-time override +#define IM_TABSIZE (4) +#endif +#define IM_MEMALIGN(_OFF,_ALIGN) (((_OFF) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8 +#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose +#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 +#define IM_FLOOR(_VAL) ((float)(int)(_VAL)) // ImFloor() is not inlined in MSVC debug builds +#define IM_ROUND(_VAL) ((float)(int)((_VAL) + 0.5f)) // +#define IM_STRINGIFY_HELPER(_X) #_X +#define IM_STRINGIFY(_X) IM_STRINGIFY_HELPER(_X) // Preprocessor idiom to stringify e.g. an integer. + +// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall +#ifdef _MSC_VER +#define IMGUI_CDECL __cdecl +#else +#define IMGUI_CDECL +#endif + +// Warnings +#if defined(_MSC_VER) && !defined(__clang__) +#define IM_MSVC_WARNING_SUPPRESS(XXXX) __pragma(warning(suppress: XXXX)) +#else +#define IM_MSVC_WARNING_SUPPRESS(XXXX) +#endif + +// Debug Tools +// Use 'Metrics/Debugger->Tools->Item Picker' to break into the call-stack of a specific item. +// This will call IM_DEBUG_BREAK() which you may redefine yourself. See https://github.com/scottt/debugbreak for more reference. +#ifndef IM_DEBUG_BREAK +#if defined (_MSC_VER) +#define IM_DEBUG_BREAK() __debugbreak() +#elif defined(__clang__) +#define IM_DEBUG_BREAK() __builtin_debugtrap() +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define IM_DEBUG_BREAK() __asm__ volatile("int $0x03") +#elif defined(__GNUC__) && defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0"); +#else +#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! +#endif +#endif // #ifndef IM_DEBUG_BREAK + +//----------------------------------------------------------------------------- +// [SECTION] Generic helpers +// Note that the ImXXX helpers functions are lower-level than ImGui functions. +// ImGui functions or the ImGui context are never called/used from other ImXXX functions. +//----------------------------------------------------------------------------- +// - Helpers: Hashing +// - Helpers: Sorting +// - Helpers: Bit manipulation +// - Helpers: String +// - Helpers: Formatting +// - Helpers: UTF-8 <> wchar conversions +// - Helpers: ImVec2/ImVec4 operators +// - Helpers: Maths +// - Helpers: Geometry +// - Helper: ImVec1 +// - Helper: ImVec2ih +// - Helper: ImRect +// - Helper: ImBitArray +// - Helper: ImBitVector +// - Helper: ImSpan<>, ImSpanAllocator<> +// - Helper: ImPool<> +// - Helper: ImChunkStream<> +// - Helper: ImGuiTextIndex +//----------------------------------------------------------------------------- + +// Helpers: Hashing +IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed = 0); +IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiID seed = 0); + +// Helpers: Sorting +#ifndef ImQsort +static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); } +#endif + +// Helpers: Color Blending +IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); + +// Helpers: Bit manipulation +static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } +static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } + +// Helpers: String +IMGUI_API int ImStricmp(const char* str1, const char* str2); +IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); +IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); +IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); +IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); +IMGUI_API int ImStrlenW(const ImWchar* str); +IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line +IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); +IMGUI_API void ImStrTrimBlanks(char* str); +IMGUI_API const char* ImStrSkipBlank(const char* str); +IM_MSVC_RUNTIME_CHECKS_OFF +static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helpers: Formatting +IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); +IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...) IM_FMTARGS(3); +IMGUI_API void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API const char* ImParseFormatFindStart(const char* format); +IMGUI_API const char* ImParseFormatFindEnd(const char* format); +IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); +IMGUI_API void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size); +IMGUI_API const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size); +IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); + +// Helpers: UTF-8 <> wchar conversions +IMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c); // return out_buf +IMGUI_API int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count +IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count +IMGUI_API int ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count +IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count) +IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8 +IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8 + +// Helpers: File System +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS +#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef void* ImFileHandle; +static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } +static inline bool ImFileClose(ImFileHandle) { return false; } +static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } +static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } +static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } +#endif +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef FILE* ImFileHandle; +IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); +IMGUI_API bool ImFileClose(ImFileHandle file); +IMGUI_API ImU64 ImFileGetSize(ImFileHandle file); +IMGUI_API ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file); +IMGUI_API ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file); +#else +#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions +#endif +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); + +// Helpers: Maths +IM_MSVC_RUNTIME_CHECKS_OFF +// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) +#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS +#define ImFabs(X) fabsf(X) +#define ImSqrt(X) sqrtf(X) +#define ImFmod(X, Y) fmodf((X), (Y)) +#define ImCos(X) cosf(X) +#define ImSin(X) sinf(X) +#define ImAcos(X) acosf(X) +#define ImAtan2(Y, X) atan2f((Y), (X)) +#define ImAtof(STR) atof(STR) +//#define ImFloorStd(X) floorf(X) // We use our own, see ImFloor() and ImFloorSigned() +#define ImCeil(X) ceilf(X) +static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision +static inline double ImPow(double x, double y) { return pow(x, y); } +static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision +static inline double ImLog(double x) { return log(x); } +static inline int ImAbs(int x) { return x < 0 ? -x : x; } +static inline float ImAbs(float x) { return fabsf(x); } +static inline double ImAbs(double x) { return fabs(x); } +static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument +static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } +#ifdef IMGUI_ENABLE_SSE +static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +#else +static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } +#endif +static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } +#endif +// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double +// (Exceptionally using templates here but we could also redefine them for those types) +template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } +template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } +template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } +template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } +template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } +// - Misc maths helpers +static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } +static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } +static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } +static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } +static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } +static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } +static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } +static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } +static inline float ImFloor(float f) { return (float)(int)(f); } +static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() +static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } +static inline ImVec2 ImFloorSigned(const ImVec2& v) { return ImVec2(ImFloorSigned(v.x), ImFloorSigned(v.y)); } +static inline int ImModPositive(int a, int b) { return (a + b) % b; } +static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } +static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } +static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } +static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } +static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; } +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helpers: Geometry +IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); +IMGUI_API ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments +IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol +IMGUI_API ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t); +IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); +IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); +IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); +inline float ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; } + +// Helper: ImVec1 (1D vector) +// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) +IM_MSVC_RUNTIME_CHECKS_OFF +struct ImVec1 +{ + float x; + constexpr ImVec1() : x(0.0f) { } + constexpr ImVec1(float _x) : x(_x) { } +}; + +// Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) +struct ImVec2ih +{ + short x, y; + constexpr ImVec2ih() : x(0), y(0) {} + constexpr ImVec2ih(short _x, short _y) : x(_x), y(_y) {} + constexpr explicit ImVec2ih(const ImVec2& rhs) : x((short)rhs.x), y((short)rhs.y) {} +}; + +// Helper: ImRect (2D axis aligned bounding-box) +// NB: we can't rely on ImVec2 math operators being available here! +struct IMGUI_API ImRect +{ + ImVec2 Min; // Upper-left + ImVec2 Max; // Lower-right + + constexpr ImRect() : Min(0.0f, 0.0f), Max(0.0f, 0.0f) {} + constexpr ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {} + constexpr ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {} + constexpr ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {} + + ImVec2 GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); } + ImVec2 GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); } + float GetWidth() const { return Max.x - Min.x; } + float GetHeight() const { return Max.y - Min.y; } + float GetArea() const { return (Max.x - Min.x) * (Max.y - Min.y); } + ImVec2 GetTL() const { return Min; } // Top-left + ImVec2 GetTR() const { return ImVec2(Max.x, Min.y); } // Top-right + ImVec2 GetBL() const { return ImVec2(Min.x, Max.y); } // Bottom-left + ImVec2 GetBR() const { return Max; } // Bottom-right + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } + void Add(const ImVec2& p) { if (Min.x > p.x) Min.x = p.x; if (Min.y > p.y) Min.y = p.y; if (Max.x < p.x) Max.x = p.x; if (Max.y < p.y) Max.y = p.y; } + void Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; } + void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } + void Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; } + void Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; } + void TranslateX(float dx) { Min.x += dx; Max.x += dx; } + void TranslateY(float dy) { Min.y += dy; Max.y += dy; } + void ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); } // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display. + void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. + void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } + bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } + ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } +}; + +// Helper: ImBitArray +#define IM_BITARRAY_TESTBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] & ((ImU32)1 << ((_N) & 31))) != 0) // Macro version of ImBitArrayTestBit(): ensure args have side-effect or are costly! +#define IM_BITARRAY_CLEARBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] &= ~((ImU32)1 << ((_N) & 31)))) // Macro version of ImBitArrayClearBit(): ensure args have side-effect or are costly! +inline size_t ImBitArrayGetStorageSizeInBytes(int bitcount) { return (size_t)((bitcount + 31) >> 5) << 2; } +inline void ImBitArrayClearAllBits(ImU32* arr, int bitcount){ memset(arr, 0, ImBitArrayGetStorageSizeInBytes(bitcount)); } +inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } +inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } +inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } +inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on range [n..n2) +{ + n2--; + while (n <= n2) + { + int a_mod = (n & 31); + int b_mod = (n2 > (n | 31) ? 31 : (n2 & 31)) + 1; + ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1); + arr[n >> 5] |= mask; + n = (n + 32) & ~31; + } +} + +typedef ImU32* ImBitArrayPtr; // Name for use in structs + +// Helper: ImBitArray class (wrapper over ImBitArray functions) +// Store 1-bit per value. +template +struct ImBitArray +{ + ImU32 Storage[(BITCOUNT + 31) >> 5]; + ImBitArray() { ClearAllBits(); } + void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } + void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } + bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); } + void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } + void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } + void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) + bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); } +}; + +// Helper: ImBitVector +// Store 1-bit per value. +struct IMGUI_API ImBitVector +{ + ImVector Storage; + void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return IM_BITARRAY_TESTBIT(Storage.Data, n); } + void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } + void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + +// Helper: ImSpan<> +// Pointing to a span of data we don't own. +template +struct ImSpan +{ + T* Data; + T* DataEnd; + + // Constructors, destructor + inline ImSpan() { Data = DataEnd = NULL; } + inline ImSpan(T* data, int size) { Data = data; DataEnd = data + size; } + inline ImSpan(T* data, T* data_end) { Data = data; DataEnd = data_end; } + + inline void set(T* data, int size) { Data = data; DataEnd = data + size; } + inline void set(T* data, T* data_end) { Data = data; DataEnd = data_end; } + inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); } + inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } + inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + inline const T& operator[](int i) const { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } + + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return DataEnd; } + inline const T* end() const { return DataEnd; } + + // Utilities + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it < DataEnd); const ptrdiff_t off = it - Data; return (int)off; } +}; + +// Helper: ImSpanAllocator<> +// Facilitate storing multiple chunks into a single large block (the "arena") +// - Usage: call Reserve() N times, allocate GetArenaSizeInBytes() worth, pass it to SetArenaBasePtr(), call GetSpan() N times to retrieve the aligned ranges. +template +struct ImSpanAllocator +{ + char* BasePtr; + int CurrOff; + int CurrIdx; + int Offsets[CHUNKS]; + int Sizes[CHUNKS]; + + ImSpanAllocator() { memset(this, 0, sizeof(*this)); } + inline void Reserve(int n, size_t sz, int a=4) { IM_ASSERT(n == CurrIdx && n < CHUNKS); CurrOff = IM_MEMALIGN(CurrOff, a); Offsets[n] = CurrOff; Sizes[n] = (int)sz; CurrIdx++; CurrOff += (int)sz; } + inline int GetArenaSizeInBytes() { return CurrOff; } + inline void SetArenaBasePtr(void* base_ptr) { BasePtr = (char*)base_ptr; } + inline void* GetSpanPtrBegin(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n]); } + inline void* GetSpanPtrEnd(int n) { IM_ASSERT(n >= 0 && n < CHUNKS && CurrIdx == CHUNKS); return (void*)(BasePtr + Offsets[n] + Sizes[n]); } + template + inline void GetSpan(int n, ImSpan* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } +}; + +// Helper: ImPool<> +// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, +// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. +typedef int ImPoolIdx; +template +struct ImPool +{ + ImVector Buf; // Contiguous data + ImGuiStorage Map; // ID->Index + ImPoolIdx FreeIdx; // Next free idx to use + ImPoolIdx AliveCount; // Number of active/alive items (for display purpose) + + ImPool() { FreeIdx = AliveCount = 0; } + ~ImPool() { Clear(); } + T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; } + T* GetByIndex(ImPoolIdx n) { return &Buf[n]; } + ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); } + T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); } + bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); } + void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = AliveCount = 0; } + T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); AliveCount++; return &Buf[idx]; } + void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } + void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); AliveCount--; } + void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); } + + // To iterate a ImPool: for (int n = 0; n < pool.GetMapSize(); n++) if (T* t = pool.TryGetMapData(n)) { ... } + // Can be avoided if you know .Remove() has never been called on the pool, or AliveCount == GetMapSize() + int GetAliveCount() const { return AliveCount; } // Number of active/alive items in the pool (for display purpose) + int GetBufSize() const { return Buf.Size; } + int GetMapSize() const { return Map.Data.Size; } // It is the map we need iterate to find valid items, since we don't have "alive" storage anywhere + T* TryGetMapData(ImPoolIdx n) { int idx = Map.Data[n].val_i; if (idx == -1) return NULL; return GetByIndex(idx); } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + int GetSize() { return GetMapSize(); } // For ImPlot: should use GetMapSize() from (IMGUI_VERSION_NUM >= 18304) +#endif +}; + +// Helper: ImChunkStream<> +// Build and iterate a contiguous stream of variable-sized structures. +// This is used by Settings to store persistent data while reducing allocation count. +// We store the chunk size first, and align the final size on 4 bytes boundaries. +// The tedious/zealous amount of casting is to avoid -Wcast-align warnings. +template +struct ImChunkStream +{ + ImVector Buf; + + void clear() { Buf.clear(); } + bool empty() const { return Buf.Size == 0; } + int size() const { return Buf.Size; } + T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = IM_MEMALIGN(HDR_SZ + sz, 4u); int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); } + T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); } + T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; } + int chunk_size(const T* p) { return ((const int*)p)[-1]; } + T* end() { return (T*)(void*)(Buf.Data + Buf.Size); } + int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; } + T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); } + void swap(ImChunkStream& rhs) { rhs.Buf.swap(Buf); } + +}; + +// Helper: ImGuiTextIndex<> +// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API. +struct ImGuiTextIndex +{ + ImVector LineOffsets; + int EndOffset = 0; // Because we don't own text buffer we need to maintain EndOffset (may bake in LineOffsets?) + + void clear() { LineOffsets.clear(); EndOffset = 0; } + int size() { return LineOffsets.Size; } + const char* get_line_begin(const char* base, int n) { return base + LineOffsets[n]; } + const char* get_line_end(const char* base, int n) { return base + (n + 1 < LineOffsets.Size ? (LineOffsets[n + 1] - 1) : EndOffset); } + void append(const char* base, int old_size, int new_size); +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImDrawList support +//----------------------------------------------------------------------------- + +// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value. +// Estimation of number of circle segment based on error is derived using method described in https://stackoverflow.com/a/2244088/15194693 +// Number of segments (N) is calculated using equation: +// N = ceil ( pi / acos(1 - error / r) ) where r > 0, error <= r +// Our equation is significantly simpler that one in the post thanks for choosing segment that is +// perpendicular to X axis. Follow steps in the article from this starting condition and you will +// will get this result. +// +// Rendering circles with an odd number of segments, while mathematically correct will produce +// asymmetrical results on the raster grid. Therefore we're rounding N to next even number (7->8, 8->8, 9->10 etc.) +#define IM_ROUNDUP_TO_EVEN(_V) ((((_V) + 1) / 2) * 2) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 4 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512 +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp(IM_ROUNDUP_TO_EVEN((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD)))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) + +// Raw equation from IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC rewritten for 'r' and 'error'. +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N,_MAXERROR) ((_MAXERROR) / (1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI)))) +#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N,_RAD) ((1 - ImCos(IM_PI / ImMax((float)(_N), IM_PI))) / (_RAD)) + +// ImDrawList: Lookup table size for adaptive arc drawing, cover full circle. +#ifndef IM_DRAWLIST_ARCFAST_TABLE_SIZE +#define IM_DRAWLIST_ARCFAST_TABLE_SIZE 48 // Number of samples in lookup table. +#endif +#define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. + +// Data shared between all ImDrawList instances +// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. +struct IMGUI_API ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + ImFont* Font; // Current/default font (optional, for simplified AddText overload) + float FontSize; // Current/default font size (optional, for simplified AddText overload) + float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() + float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) + + // [Internal] Temp write buffer + ImVector TempBuffer; + + // [Internal] Lookup tables + ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. + float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() + ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) + const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas + + ImDrawListSharedData(); + void SetCircleTessellationMaxError(float max_error); +}; + +struct ImDrawDataBuilder +{ + ImVector* Layers[2]; // Pointers to global layers for: regular, tooltip. LayersP[0] is owned by DrawData. + ImVector LayerData1; + + ImDrawDataBuilder() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Widgets support: flags, enums, data structures +//----------------------------------------------------------------------------- + +// Flags used by upcoming items +// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags. +// - output: stored in g.LastItemData.InFlags +// Current window shared by all windows. +// This is going to be exposed in imgui.h when stabilized enough. +enum ImGuiItemFlags_ +{ + // Controlled by user + ImGuiItemFlags_None = 0, + ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav. + ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. + ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211 + ImGuiItemFlags_NoNav = 1 << 3, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls) + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items) + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window + ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) + ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. + ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() + ImGuiItemflags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. + + // Controlled by widget code + ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. +}; + +// Status flags for an already submitted item +// - output: stored in g.LastItemData.StatusFlags +enum ImGuiItemStatusFlags_ +{ + ImGuiItemStatusFlags_None = 0, + ImGuiItemStatusFlags_HoveredRect = 1 << 0, // Mouse position is within item rectangle (does NOT mean that the window is in correct z-order and can be hovered!, this is only one part of the most-common IsItemHovered test) + ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, // g.LastItemData.DisplayRect is valid + ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) + ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected", only state changes, in order to easily handle clipping with less issues. + ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state. + ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. + ImGuiItemStatusFlags_Deactivated = 1 << 6, // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. + ImGuiItemStatusFlags_HoveredWindow = 1 << 7, // Override the HoveredWindow test to allow cross-window hover testing. + ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Set when the Focusable item just got focused by Tabbing (FIXME: to be removed soon) + ImGuiItemStatusFlags_Visible = 1 << 9, // [WIP] Set when item is overlapping the current clipping rectangle (Used internally. Please don't use yet: API/system will change as we refactor Itemadd()). + + // Additional status + semantic for ImGuiTestEngine +#ifdef IMGUI_ENABLE_TEST_ENGINE + ImGuiItemStatusFlags_Openable = 1 << 20, // Item is an openable (e.g. TreeNode) + ImGuiItemStatusFlags_Opened = 1 << 21, // Opened status + ImGuiItemStatusFlags_Checkable = 1 << 22, // Item is a checkable (e.g. CheckBox, MenuItem) + ImGuiItemStatusFlags_Checked = 1 << 23, // Checked status + ImGuiItemStatusFlags_Inputable = 1 << 24, // Item is a text-inputable (e.g. InputText, SliderXXX, DragXXX) +#endif +}; + +// Extend ImGuiHoveredFlags_ +enum ImGuiHoveredFlagsPrivate_ +{ + ImGuiHoveredFlags_DelayMask_ = ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay, + ImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary, + ImGuiHoveredFlags_AllowedMaskForIsItemHovered = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayMask_, +}; + +// Extend ImGuiInputTextFlags_ +enum ImGuiInputTextFlagsPrivate_ +{ + // [Internal] + ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() + ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_MergedItem = 1 << 28, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. +}; + +// Extend ImGuiButtonFlags_ +enum ImGuiButtonFlagsPrivate_ +{ + ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event) + ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using + ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item + ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) + ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) + ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) + ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat + ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping + ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable. + ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] + //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled + ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, // disable mouse interaction if a key modifier is held + ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) + ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated (FIXME: this is essentially used everytime an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.InFlags) + ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item + ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) + ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) + ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, + ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease, +}; + +// Extend ImGuiComboFlags_ +enum ImGuiComboFlagsPrivate_ +{ + ImGuiComboFlags_CustomPreview = 1 << 20, // enable BeginComboPreview() +}; + +// Extend ImGuiSliderFlags_ +enum ImGuiSliderFlagsPrivate_ +{ + ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically? + ImGuiSliderFlags_ReadOnly = 1 << 21, +}; + +// Extend ImGuiSelectableFlags_ +enum ImGuiSelectableFlagsPrivate_ +{ + // NB: need to be in sync with last value of ImGuiSelectableFlags_ + ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20, + ImGuiSelectableFlags_SelectOnNav = 1 << 21, // (WIP) Auto-select when moved into. This is not exposed in public API as to handle multi-select and modifiers we will need user to explicitly control focus scope. May be replaced with a BeginSelection() API. + ImGuiSelectableFlags_SelectOnClick = 1 << 22, // Override button behavior to react on Click (default is Click+Release) + ImGuiSelectableFlags_SelectOnRelease = 1 << 23, // Override button behavior to react on Release (default is Click+Release) + ImGuiSelectableFlags_SpanAvailWidth = 1 << 24, // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus) + ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25, // Set Nav/Focus ID on mouse hover (used by MenuItem) + ImGuiSelectableFlags_NoPadWithHalfSpacing = 1 << 26, // Disable padding each side with ItemSpacing * 0.5f + ImGuiSelectableFlags_NoSetKeyOwner = 1 << 27, // Don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) +}; + +// Extend ImGuiTreeNodeFlags_ +enum ImGuiTreeNodeFlagsPrivate_ +{ + ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20, + ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 21,// (FIXME-WIP) Turn Down arrow into an Up arrow, but reversed trees (#6517) +}; + +enum ImGuiSeparatorFlags_ +{ + ImGuiSeparatorFlags_None = 0, + ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar + ImGuiSeparatorFlags_Vertical = 1 << 1, + ImGuiSeparatorFlags_SpanAllColumns = 1 << 2, // Make separator cover all columns of a legacy Columns() set. +}; + +// Flags for FocusWindow(). This is not called ImGuiFocusFlags to avoid confusion with public-facing ImGuiFocusedFlags. +// FIXME: Once we finishing replacing more uses of GetTopMostPopupModal()+IsWindowWithinBeginStackOf() +// and FindBlockingModal() with this, we may want to change the flag to be opt-out instead of opt-in. +enum ImGuiFocusRequestFlags_ +{ + ImGuiFocusRequestFlags_None = 0, + ImGuiFocusRequestFlags_RestoreFocusedChild = 1 << 0, // Find last focused child (if any) and focus it instead. + ImGuiFocusRequestFlags_UnlessBelowModal = 1 << 1, // Do not set focus if the window is below a modal. +}; + +enum ImGuiTextFlags_ +{ + ImGuiTextFlags_None = 0, + ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0, +}; + +enum ImGuiTooltipFlags_ +{ + ImGuiTooltipFlags_None = 0, + ImGuiTooltipFlags_OverridePrevious = 1 << 1, // Clear/ignore previously submitted tooltip (defaults to append) +}; + +// FIXME: this is in development, not exposed/functional as a generic feature yet. +// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiLayoutType_ +{ + ImGuiLayoutType_Horizontal = 0, + ImGuiLayoutType_Vertical = 1 +}; + +enum ImGuiLogType +{ + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard, +}; + +// X/Y enums are fixed to 0/1 so they may be used to index ImVec2 +enum ImGuiAxis +{ + ImGuiAxis_None = -1, + ImGuiAxis_X = 0, + ImGuiAxis_Y = 1 +}; + +enum ImGuiPlotType +{ + ImGuiPlotType_Lines, + ImGuiPlotType_Histogram, +}; + +enum ImGuiPopupPositionPolicy +{ + ImGuiPopupPositionPolicy_Default, + ImGuiPopupPositionPolicy_ComboBox, + ImGuiPopupPositionPolicy_Tooltip, +}; + +struct ImGuiDataVarInfo +{ + ImGuiDataType Type; + ImU32 Count; // 1+ + ImU32 Offset; // Offset in parent structure + void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); } +}; + +struct ImGuiDataTypeTempStorage +{ + ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT +}; + +// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo(). +struct ImGuiDataTypeInfo +{ + size_t Size; // Size in bytes + const char* Name; // Short descriptive name for the type, for debugging + const char* PrintFmt; // Default printf format for the type + const char* ScanFmt; // Default scanf format for the type +}; + +// Extend ImGuiDataType_ +enum ImGuiDataTypePrivate_ +{ + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, + ImGuiDataType_ID, +}; + +// Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; + +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } +}; + +// Storage data for BeginComboPreview()/EndComboPreview() +struct IMGUI_API ImGuiComboPreviewData +{ + ImRect PreviewRect; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec2 BackupCursorPosPrevLine; + float BackupPrevLineTextBaseOffset; + ImGuiLayoutType BackupLayout; + + ImGuiComboPreviewData() { memset(this, 0, sizeof(*this)); } +}; + +// Stacked storage data for BeginGroup()/EndGroup() +struct IMGUI_API ImGuiGroupData +{ + ImGuiID WindowID; + ImVec2 BackupCursorPos; + ImVec2 BackupCursorMaxPos; + ImVec1 BackupIndent; + ImVec1 BackupGroupOffset; + ImVec2 BackupCurrLineSize; + float BackupCurrLineTextBaseOffset; + ImGuiID BackupActiveIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; + bool BackupHoveredIdIsAlive; + bool EmitItem; +}; + +// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper. +struct IMGUI_API ImGuiMenuColumns +{ + ImU32 TotalWidth; + ImU32 NextTotalWidth; + ImU16 Spacing; + ImU16 OffsetIcon; // Always zero for now + ImU16 OffsetLabel; // Offsets are locked in Update() + ImU16 OffsetShortcut; + ImU16 OffsetMark; + ImU16 Widths[4]; // Width of: Icon, Label, Shortcut, Mark (accumulators for current frame) + + ImGuiMenuColumns() { memset(this, 0, sizeof(*this)); } + void Update(float spacing, bool window_reappearing); + float DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark); + void CalcNextTotalWidth(bool update_offsets); +}; + +// Internal temporary state for deactivating InputText() instances. +struct IMGUI_API ImGuiInputTextDeactivatedState +{ + ImGuiID ID; // widget id owning the text state (which just got deactivated) + ImVector TextA; // text buffer + + ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); } + void ClearFreeMemory() { ID = 0; TextA.clear(); } +}; +// Internal state of the currently focused/edited text input box +// For a given item ID, access with ImGui::GetInputTextState() +struct IMGUI_API ImGuiInputTextState +{ + ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). + ImGuiID ID; // widget id owning the text state + int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. + ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. + ImVector TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. + ImVector InitialTextA; // backup of end-user buffer at the time of focus (in UTF-8, unaltered) + bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) + int BufCapacityA; // end-user buffer capacity + float ScrollX; // horizontal scrolling/offset + ImStb::STB_TexteditState Stb; // state for stb_textedit.h + float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately + bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) + bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection + bool Edited; // edited this frame + ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. + + ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } + void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } + int GetUndoAvailCount() const { return Stb.undostate.undo_point; } + int GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } + void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation + + // Cursor & Selection + void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking + void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } + bool HasSelection() const { return Stb.select_start != Stb.select_end; } + void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } + int GetCursorPos() const { return Stb.cursor; } + int GetSelectionStart() const { return Stb.select_start; } + int GetSelectionEnd() const { return Stb.select_end; } + void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } +}; + +// Storage for current popup stack +struct ImGuiPopupData +{ + ImGuiID PopupId; // Set on OpenPopup() + ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() + ImGuiWindow* BackupNavWindow;// Set on OpenPopup(), a NavWindow that will be restored on popup close + int ParentNavLayer; // Resolved on BeginPopup(). Actually a ImGuiNavLayer type (declared down below), initialized to -1 which is not part of an enum, but serves well-enough as "not any of layers" value + int OpenFrameCount; // Set on OpenPopup() + ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) + ImVec2 OpenPopupPos; // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse) + ImVec2 OpenMousePos; // Set on OpenPopup(), copy of mouse position at the time of opening popup + + ImGuiPopupData() { memset(this, 0, sizeof(*this)); ParentNavLayer = OpenFrameCount = -1; } +}; + +enum ImGuiNextWindowDataFlags_ +{ + ImGuiNextWindowDataFlags_None = 0, + ImGuiNextWindowDataFlags_HasPos = 1 << 0, + ImGuiNextWindowDataFlags_HasSize = 1 << 1, + ImGuiNextWindowDataFlags_HasContentSize = 1 << 2, + ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3, + ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4, + ImGuiNextWindowDataFlags_HasFocus = 1 << 5, + ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, + ImGuiNextWindowDataFlags_HasScroll = 1 << 7, +}; + +// Storage for SetNexWindow** functions +struct ImGuiNextWindowData +{ + ImGuiNextWindowDataFlags Flags; + ImGuiCond PosCond; + ImGuiCond SizeCond; + ImGuiCond CollapsedCond; + ImVec2 PosVal; + ImVec2 PosPivotVal; + ImVec2 SizeVal; + ImVec2 ContentSizeVal; + ImVec2 ScrollVal; + bool CollapsedVal; + ImRect SizeConstraintRect; + ImGuiSizeCallback SizeCallback; + void* SizeCallbackUserData; + float BgAlphaVal; // Override background alpha + ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) + + ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } +}; + +enum ImGuiNextItemDataFlags_ +{ + ImGuiNextItemDataFlags_None = 0, + ImGuiNextItemDataFlags_HasWidth = 1 << 0, + ImGuiNextItemDataFlags_HasOpen = 1 << 1, +}; + +struct ImGuiNextItemData +{ + ImGuiNextItemDataFlags Flags; + ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemflags_AllowOverlap. + float Width; // Set by SetNextItemWidth() + ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) + ImGuiCond OpenCond; + bool OpenVal; // Set by SetNextItemOpen() + + ImGuiNextItemData() { memset(this, 0, sizeof(*this)); } + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! +}; + +// Status storage for the last submitted item +struct ImGuiLastItemData +{ + ImGuiID ID; + ImGuiItemFlags InFlags; // See ImGuiItemFlags_ + ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_ + ImRect Rect; // Full rectangle + ImRect NavRect; // Navigation scoring rectangle (not displayed) + ImRect DisplayRect; // Display rectangle (only if ImGuiItemStatusFlags_HasDisplayRect is set) + + ImGuiLastItemData() { memset(this, 0, sizeof(*this)); } +}; + +struct IMGUI_API ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfItemFlagsStack; + short SizeOfBeginPopupStack; + short SizeOfDisabledStack; + + ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } + void SetToContextState(ImGuiContext* ctx); + void CompareWithContextState(ImGuiContext* ctx); +}; + +// Data saved for each window pushed into the stack +struct ImGuiWindowStackData +{ + ImGuiWindow* Window; + ImGuiLastItemData ParentLastItemDataBackup; + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting +}; + +struct ImGuiShrinkWidthItem +{ + int Index; + float Width; + float InitialWidth; +}; + +struct ImGuiPtrOrIndex +{ + void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool. + int Index; // Usually index in a main pool. + + ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; } + ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Inputs support +//----------------------------------------------------------------------------- + +// Bit array for named keys +typedef ImBitArray ImBitArrayForNamedKeys; + +// [Internal] Key ranges +#define ImGuiKey_LegacyNativeKey_BEGIN 0 +#define ImGuiKey_LegacyNativeKey_END 512 +#define ImGuiKey_Keyboard_BEGIN (ImGuiKey_NamedKey_BEGIN) +#define ImGuiKey_Keyboard_END (ImGuiKey_GamepadStart) +#define ImGuiKey_Gamepad_BEGIN (ImGuiKey_GamepadStart) +#define ImGuiKey_Gamepad_END (ImGuiKey_GamepadRStickDown + 1) +#define ImGuiKey_Mouse_BEGIN (ImGuiKey_MouseLeft) +#define ImGuiKey_Mouse_END (ImGuiKey_MouseWheelY + 1) +#define ImGuiKey_Aliases_BEGIN (ImGuiKey_Mouse_BEGIN) +#define ImGuiKey_Aliases_END (ImGuiKey_Mouse_END) + +// [Internal] Named shortcuts for Navigation +#define ImGuiKey_NavKeyboardTweakSlow ImGuiMod_Ctrl +#define ImGuiKey_NavKeyboardTweakFast ImGuiMod_Shift +#define ImGuiKey_NavGamepadTweakSlow ImGuiKey_GamepadL1 +#define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1 +#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown +#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight +#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft +#define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp + +enum ImGuiInputEventType +{ + ImGuiInputEventType_None = 0, + ImGuiInputEventType_MousePos, + ImGuiInputEventType_MouseWheel, + ImGuiInputEventType_MouseButton, + ImGuiInputEventType_Key, + ImGuiInputEventType_Text, + ImGuiInputEventType_Focus, + ImGuiInputEventType_COUNT +}; + +enum ImGuiInputSource +{ + ImGuiInputSource_None = 0, + ImGuiInputSource_Mouse, // Note: may be Mouse or TouchScreen or Pen. See io.MouseSource to distinguish them. + ImGuiInputSource_Keyboard, + ImGuiInputSource_Gamepad, + ImGuiInputSource_Clipboard, // Currently only used by InputText() + ImGuiInputSource_COUNT +}; + +// FIXME: Structures in the union below need to be declared as anonymous unions appears to be an extension? +// Using ImVec2() would fail on Clang 'union member 'MousePos' has a non-trivial default constructor' +struct ImGuiInputEventMousePos { float PosX, PosY; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventMouseWheel { float WheelX, WheelY; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventMouseButton { int Button; bool Down; ImGuiMouseSource MouseSource; }; +struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; }; +struct ImGuiInputEventText { unsigned int Char; }; +struct ImGuiInputEventAppFocused { bool Focused; }; + +struct ImGuiInputEvent +{ + ImGuiInputEventType Type; + ImGuiInputSource Source; + ImU32 EventId; // Unique, sequential increasing integer to identify an event (if you need to correlate them to other data). + union + { + ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos + ImGuiInputEventMouseWheel MouseWheel; // if Type == ImGuiInputEventType_MouseWheel + ImGuiInputEventMouseButton MouseButton; // if Type == ImGuiInputEventType_MouseButton + ImGuiInputEventKey Key; // if Type == ImGuiInputEventType_Key + ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text + ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus + }; + bool AddedByTestEngine; + + ImGuiInputEvent() { memset(this, 0, sizeof(*this)); } +}; + +// Input function taking an 'ImGuiID owner_id' argument defaults to (ImGuiKeyOwner_Any == 0) aka don't test ownership, which matches legacy behavior. +#define ImGuiKeyOwner_Any ((ImGuiID)0) // Accept key that have an owner, UNLESS a call to SetKeyOwner() explicitly used ImGuiInputFlags_LockThisFrame or ImGuiInputFlags_LockUntilRelease. +#define ImGuiKeyOwner_None ((ImGuiID)-1) // Require key to have no owner. + +typedef ImS16 ImGuiKeyRoutingIndex; + +// Routing table entry (sizeof() == 16 bytes) +struct ImGuiKeyRoutingData +{ + ImGuiKeyRoutingIndex NextEntryIndex; + ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super. + ImU8 RoutingNextScore; // Lower is better (0: perfect score) + ImGuiID RoutingCurr; + ImGuiID RoutingNext; + + ImGuiKeyRoutingData() { NextEntryIndex = -1; Mods = 0; RoutingNextScore = 255; RoutingCurr = RoutingNext = ImGuiKeyOwner_None; } +}; + +// Routing table: maintain a desired owner for each possible key-chord (key + mods), and setup owner in NewFrame() when mods are matching. +// Stored in main context (1 instance) +struct ImGuiKeyRoutingTable +{ + ImGuiKeyRoutingIndex Index[ImGuiKey_NamedKey_COUNT]; // Index of first entry in Entries[] + ImVector Entries; + ImVector EntriesNext; // Double-buffer to avoid reallocation (could use a shared buffer) + + ImGuiKeyRoutingTable() { Clear(); } + void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Index); n++) Index[n] = -1; Entries.clear(); EntriesNext.clear(); } +}; + +// This extends ImGuiKeyData but only for named keys (legacy keys don't support the new features) +// Stored in main context (1 per named key). In the future it might be merged into ImGuiKeyData. +struct ImGuiKeyOwnerData +{ + ImGuiID OwnerCurr; + ImGuiID OwnerNext; + bool LockThisFrame; // Reading this key requires explicit owner id (until end of frame). Set by ImGuiInputFlags_LockThisFrame. + bool LockUntilRelease; // Reading this key requires explicit owner id (until key is released). Set by ImGuiInputFlags_LockUntilRelease. When this is true LockThisFrame is always true as well. + + ImGuiKeyOwnerData() { OwnerCurr = OwnerNext = ImGuiKeyOwner_None; LockThisFrame = LockUntilRelease = false; } +}; + +// Flags for extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner() +// Don't mistake with ImGuiInputTextFlags! (for ImGui::InputText() function) +enum ImGuiInputFlags_ +{ + // Flags for IsKeyPressed(), IsMouseClicked(), Shortcut() + ImGuiInputFlags_None = 0, + ImGuiInputFlags_Repeat = 1 << 0, // Return true on successive repeats. Default for legacy IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1. + ImGuiInputFlags_RepeatRateDefault = 1 << 1, // Repeat rate: Regular (default) + ImGuiInputFlags_RepeatRateNavMove = 1 << 2, // Repeat rate: Fast + ImGuiInputFlags_RepeatRateNavTweak = 1 << 3, // Repeat rate: Faster + ImGuiInputFlags_RepeatRateMask_ = ImGuiInputFlags_RepeatRateDefault | ImGuiInputFlags_RepeatRateNavMove | ImGuiInputFlags_RepeatRateNavTweak, + + // Flags for SetItemKeyOwner() + ImGuiInputFlags_CondHovered = 1 << 4, // Only set if item is hovered (default to both) + ImGuiInputFlags_CondActive = 1 << 5, // Only set if item is active (default to both) + ImGuiInputFlags_CondDefault_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive, + ImGuiInputFlags_CondMask_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive, + + // Flags for SetKeyOwner(), SetItemKeyOwner() + ImGuiInputFlags_LockThisFrame = 1 << 6, // Access to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared at end of frame. This is useful to make input-owner-aware code steal keys from non-input-owner-aware code. + ImGuiInputFlags_LockUntilRelease = 1 << 7, // Access to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared when the key is released or at end of each frame if key is released. This is useful to make input-owner-aware code steal keys from non-input-owner-aware code. + + // Routing policies for Shortcut() + low-level SetShortcutRouting() + // - The general idea is that several callers register interest in a shortcut, and only one owner gets it. + // - When a policy (other than _RouteAlways) is set, Shortcut() will register itself with SetShortcutRouting(), + // allowing the system to decide where to route the input among other route-aware calls. + // - Shortcut() uses ImGuiInputFlags_RouteFocused by default: meaning that a simple Shortcut() poll + // will register a route and only succeed when parent window is in the focus stack and if no-one + // with a higher priority is claiming the shortcut. + // - Using ImGuiInputFlags_RouteAlways is roughly equivalent to doing e.g. IsKeyPressed(key) + testing mods. + // - Priorities: GlobalHigh > Focused (when owner is active item) > Global > Focused (when focused window) > GlobalLow. + // - Can select only 1 policy among all available. + ImGuiInputFlags_RouteFocused = 1 << 8, // (Default) Register focused route: Accept inputs if window is in focus stack. Deep-most focused window takes inputs. ActiveId takes inputs over deep-most focused window. + ImGuiInputFlags_RouteGlobalLow = 1 << 9, // Register route globally (lowest priority: unless a focused window or active item registered the route) -> recommended Global priority. + ImGuiInputFlags_RouteGlobal = 1 << 10, // Register route globally (medium priority: unless an active item registered the route, e.g. CTRL+A registered by InputText). + ImGuiInputFlags_RouteGlobalHigh = 1 << 11, // Register route globally (highest priority: unlikely you need to use that: will interfere with every active items) + ImGuiInputFlags_RouteMask_ = ImGuiInputFlags_RouteFocused | ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteGlobalLow | ImGuiInputFlags_RouteGlobalHigh, // _Always not part of this! + ImGuiInputFlags_RouteAlways = 1 << 12, // Do not register route, poll keys directly. + ImGuiInputFlags_RouteUnlessBgFocused= 1 << 13, // Global routes will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications. + ImGuiInputFlags_RouteExtraMask_ = ImGuiInputFlags_RouteAlways | ImGuiInputFlags_RouteUnlessBgFocused, + + // [Internal] Mask of which function support which flags + ImGuiInputFlags_SupportedByIsKeyPressed = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_, + ImGuiInputFlags_SupportedByShortcut = ImGuiInputFlags_Repeat | ImGuiInputFlags_RepeatRateMask_ | ImGuiInputFlags_RouteMask_ | ImGuiInputFlags_RouteExtraMask_, + ImGuiInputFlags_SupportedBySetKeyOwner = ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease, + ImGuiInputFlags_SupportedBySetItemKeyOwner = ImGuiInputFlags_SupportedBySetKeyOwner | ImGuiInputFlags_CondMask_, +}; + +//----------------------------------------------------------------------------- +// [SECTION] Clipper support +//----------------------------------------------------------------------------- + +// Note that Max is exclusive, so perhaps should be using a Begin/End convention. +struct ImGuiListClipperRange +{ + int Min; + int Max; + bool PosToIndexConvert; // Begin/End are absolute position (will be converted to indices later) + ImS8 PosToIndexOffsetMin; // Add to Min after converting to indices + ImS8 PosToIndexOffsetMax; // Add to Min after converting to indices + + static ImGuiListClipperRange FromIndices(int min, int max) { ImGuiListClipperRange r = { min, max, false, 0, 0 }; return r; } + static ImGuiListClipperRange FromPositions(float y1, float y2, int off_min, int off_max) { ImGuiListClipperRange r = { (int)y1, (int)y2, true, (ImS8)off_min, (ImS8)off_max }; return r; } +}; + +// Temporary clipper data, buffers shared/reused between instances +struct ImGuiListClipperData +{ + ImGuiListClipper* ListClipper; + float LossynessOffset; + int StepNo; + int ItemsFrozen; + ImVector Ranges; + + ImGuiListClipperData() { memset(this, 0, sizeof(*this)); } + void Reset(ImGuiListClipper* clipper) { ListClipper = clipper; StepNo = ItemsFrozen = 0; Ranges.resize(0); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Navigation support +//----------------------------------------------------------------------------- + +enum ImGuiActivateFlags_ +{ + ImGuiActivateFlags_None = 0, + ImGuiActivateFlags_PreferInput = 1 << 0, // Favor activation that requires keyboard text input (e.g. for Slider/Drag). Default for Enter key. + ImGuiActivateFlags_PreferTweak = 1 << 1, // Favor activation for tweaking with arrows or gamepad (e.g. for Slider/Drag). Default for Space key and if keyboard is not used. + ImGuiActivateFlags_TryToPreserveState = 1 << 2, // Request widget to preserve state if it can (e.g. InputText will try to preserve cursor/selection) +}; + +// Early work-in-progress API for ScrollToItem() +enum ImGuiScrollFlags_ +{ + ImGuiScrollFlags_None = 0, + ImGuiScrollFlags_KeepVisibleEdgeX = 1 << 0, // If item is not visible: scroll as little as possible on X axis to bring item back into view [default for X axis] + ImGuiScrollFlags_KeepVisibleEdgeY = 1 << 1, // If item is not visible: scroll as little as possible on Y axis to bring item back into view [default for Y axis for windows that are already visible] + ImGuiScrollFlags_KeepVisibleCenterX = 1 << 2, // If item is not visible: scroll to make the item centered on X axis [rarely used] + ImGuiScrollFlags_KeepVisibleCenterY = 1 << 3, // If item is not visible: scroll to make the item centered on Y axis + ImGuiScrollFlags_AlwaysCenterX = 1 << 4, // Always center the result item on X axis [rarely used] + ImGuiScrollFlags_AlwaysCenterY = 1 << 5, // Always center the result item on Y axis [default for Y axis for appearing window) + ImGuiScrollFlags_NoScrollParent = 1 << 6, // Disable forwarding scrolling to parent window if required to keep item/rect visible (only scroll window the function was applied to). + ImGuiScrollFlags_MaskX_ = ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleCenterX | ImGuiScrollFlags_AlwaysCenterX, + ImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY, +}; + +enum ImGuiNavHighlightFlags_ +{ + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_TypeDefault = 1 << 0, + ImGuiNavHighlightFlags_TypeThin = 1 << 1, + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. + ImGuiNavHighlightFlags_NoRounding = 1 << 3, +}; + +enum ImGuiNavMoveFlags_ +{ + ImGuiNavMoveFlags_None = 0, + ImGuiNavMoveFlags_LoopX = 1 << 0, // On failed request, restart from opposite side + ImGuiNavMoveFlags_LoopY = 1 << 1, + ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left) + ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful but provided for completeness + ImGuiNavMoveFlags_WrapMask_ = ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_WrapY, + ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place) + ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisible that only comprise elements that are already fully visible (used by PageUp/PageDown) + ImGuiNavMoveFlags_ScrollToEdgeY = 1 << 6, // Force scrolling to min/max (used by Home/End) // FIXME-NAV: Aim to remove or reword, probably unnecessary + ImGuiNavMoveFlags_Forwarded = 1 << 7, + ImGuiNavMoveFlags_DebugNoResult = 1 << 8, // Dummy scoring for debug purpose, don't apply result + ImGuiNavMoveFlags_FocusApi = 1 << 9, // Requests from focus API can land/focus/activate items even if they are marked with _NoTabStop (see NavProcessItemForTabbingRequest() for details) + ImGuiNavMoveFlags_IsTabbing = 1 << 10, // == Focus + Activate if item is Inputable + DontChangeNavHighlight + ImGuiNavMoveFlags_IsPageMove = 1 << 11, // Identify a PageDown/PageUp request. + ImGuiNavMoveFlags_Activate = 1 << 12, // Activate/select target item. + ImGuiNavMoveFlags_NoSelect = 1 << 13, // Don't trigger selection by not setting g.NavJustMovedTo + ImGuiNavMoveFlags_NoSetNavHighlight = 1 << 14, // Do not alter the visible state of keyboard vs mouse nav highlight +}; + +enum ImGuiNavLayer +{ + ImGuiNavLayer_Main = 0, // Main scrolling layer + ImGuiNavLayer_Menu = 1, // Menu layer (access with Alt) + ImGuiNavLayer_COUNT +}; + +struct ImGuiNavItemData +{ + ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window) + ImGuiID ID; // Init,Move // Best candidate item ID + ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID + ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space + ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags + float DistBox; // Move // Best candidate box distance to current NavId + float DistCenter; // Move // Best candidate center distance to current NavId + float DistAxial; // Move // Best candidate axial distance to current NavId + + ImGuiNavItemData() { Clear(); } + void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; DistBox = DistCenter = DistAxial = FLT_MAX; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Columns support +//----------------------------------------------------------------------------- + +// Flags for internal's BeginColumns(). Prefix using BeginTable() nowadays! +enum ImGuiOldColumnFlags_ +{ + ImGuiOldColumnFlags_None = 0, + ImGuiOldColumnFlags_NoBorder = 1 << 0, // Disable column dividers + ImGuiOldColumnFlags_NoResize = 1 << 1, // Disable resizing columns when clicking on the dividers + ImGuiOldColumnFlags_NoPreserveWidths = 1 << 2, // Disable column width preservation when adjusting columns + ImGuiOldColumnFlags_NoForceWithinWindow = 1 << 3, // Disable forcing columns to fit within window + ImGuiOldColumnFlags_GrowParentContentsSize = 1 << 4, // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove. + + // Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiColumnsFlags_None = ImGuiOldColumnFlags_None, + ImGuiColumnsFlags_NoBorder = ImGuiOldColumnFlags_NoBorder, + ImGuiColumnsFlags_NoResize = ImGuiOldColumnFlags_NoResize, + ImGuiColumnsFlags_NoPreserveWidths = ImGuiOldColumnFlags_NoPreserveWidths, + ImGuiColumnsFlags_NoForceWithinWindow = ImGuiOldColumnFlags_NoForceWithinWindow, + ImGuiColumnsFlags_GrowParentContentsSize = ImGuiOldColumnFlags_GrowParentContentsSize, +#endif +}; + +struct ImGuiOldColumnData +{ + float OffsetNorm; // Column start offset, normalized 0.0 (far left) -> 1.0 (far right) + float OffsetNormBeforeResize; + ImGuiOldColumnFlags Flags; // Not exposed + ImRect ClipRect; + + ImGuiOldColumnData() { memset(this, 0, sizeof(*this)); } +}; + +struct ImGuiOldColumns +{ + ImGuiID ID; + ImGuiOldColumnFlags Flags; + bool IsFirstFrame; + bool IsBeingResized; + int Current; + int Count; + float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x + float LineMinY, LineMaxY; + float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns() + float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns() + ImRect HostInitialClipRect; // Backup of ClipRect at the time of BeginColumns() + ImRect HostBackupClipRect; // Backup of ClipRect during PushColumnsBackground()/PopColumnsBackground() + ImRect HostBackupParentWorkRect;//Backup of WorkRect at the time of BeginColumns() + ImVector Columns; + ImDrawListSplitter Splitter; + + ImGuiOldColumns() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Multi-select support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_MULTI_SELECT +// +#endif // #ifdef IMGUI_HAS_MULTI_SELECT + +//----------------------------------------------------------------------------- +// [SECTION] Docking support +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_DOCK +// +#endif // #ifdef IMGUI_HAS_DOCK + +//----------------------------------------------------------------------------- +// [SECTION] Viewport support +//----------------------------------------------------------------------------- + +// ImGuiViewport Private/Internals fields (cardinal sin: we are using inheritance!) +// Every instance of ImGuiViewport is in fact a ImGuiViewportP. +struct ImGuiViewportP : public ImGuiViewport +{ + int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used + ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. + ImDrawData DrawDataP; + ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) + ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). + ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. + ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. + + ImGuiViewportP() { DrawListsLastFrame[0] = DrawListsLastFrame[1] = -1; DrawLists[0] = DrawLists[1] = NULL; } + ~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } + + // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) + ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } + ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); } + void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields + + // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry) + ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } + ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Settings support +//----------------------------------------------------------------------------- + +// Windows data saved in imgui.ini file +// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily. +// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure) +struct ImGuiWindowSettings +{ + ImGuiID ID; + ImVec2ih Pos; + ImVec2ih Size; + bool Collapsed; + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + bool WantDelete; // Set to invalidate/delete the settings entry + + ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } + char* GetName() { return (char*)(this + 1); } +}; + +struct ImGuiSettingsHandler +{ + const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']' + ImGuiID TypeHash; // == ImHashStr(TypeName) + void (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Clear all settings data + void (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called before reading (in registration order) + void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]" + void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry + void (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler); // Read: Called after reading (in registration order) + void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf' + void* UserData; + + ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Localization support +//----------------------------------------------------------------------------- + +// This is experimental and not officially supported, it'll probably fall short of features, if/when it does we may backtrack. +enum ImGuiLocKey : int +{ + ImGuiLocKey_VersionStr, + ImGuiLocKey_TableSizeOne, + ImGuiLocKey_TableSizeAllFit, + ImGuiLocKey_TableSizeAllDefault, + ImGuiLocKey_TableResetOrder, + ImGuiLocKey_WindowingMainMenuBar, + ImGuiLocKey_WindowingPopup, + ImGuiLocKey_WindowingUntitled, + ImGuiLocKey_COUNT +}; + +struct ImGuiLocEntry +{ + ImGuiLocKey Key; + const char* Text; +}; + + +//----------------------------------------------------------------------------- +// [SECTION] Metrics, Debug Tools +//----------------------------------------------------------------------------- + +enum ImGuiDebugLogFlags_ +{ + // Event types + ImGuiDebugLogFlags_None = 0, + ImGuiDebugLogFlags_EventActiveId = 1 << 0, + ImGuiDebugLogFlags_EventFocus = 1 << 1, + ImGuiDebugLogFlags_EventPopup = 1 << 2, + ImGuiDebugLogFlags_EventNav = 1 << 3, + ImGuiDebugLogFlags_EventClipper = 1 << 4, + ImGuiDebugLogFlags_EventSelection = 1 << 5, + ImGuiDebugLogFlags_EventIO = 1 << 6, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO, + ImGuiDebugLogFlags_OutputToTTY = 1 << 10, // Also send output to TTY +}; + +struct ImGuiMetricsConfig +{ + bool ShowDebugLog = false; + bool ShowStackTool = false; + bool ShowWindowsRects = false; + bool ShowWindowsBeginOrder = false; + bool ShowTablesRects = false; + bool ShowDrawCmdMesh = true; + bool ShowDrawCmdBoundingBoxes = true; + bool ShowAtlasTintedWithTextColor = false; + int ShowWindowsRectsType = -1; + int ShowTablesRectsType = -1; +}; + +struct ImGuiStackLevelInfo +{ + ImGuiID ID; + ImS8 QueryFrameCount; // >= 1: Query in progress + bool QuerySuccess; // Obtained result from DebugHookIdInfo() + ImGuiDataType DataType : 8; + char Desc[57]; // Arbitrarily sized buffer to hold a result (FIXME: could replace Results[] with a chunk stream?) FIXME: Now that we added CTRL+C this should be fixed. + + ImGuiStackLevelInfo() { memset(this, 0, sizeof(*this)); } +}; + +// State for Stack tool queries +struct ImGuiStackTool +{ + int LastActiveFrame; + int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level + ImGuiID QueryId; // ID to query details for + ImVector Results; + bool CopyToClipboardOnCtrlC; + float CopyToClipboardLastTime; + + ImGuiStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Generic context hooks +//----------------------------------------------------------------------------- + +typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); +enum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }; + +struct ImGuiContextHook +{ + ImGuiID HookId; // A unique ID assigned by AddContextHook() + ImGuiContextHookType Type; + ImGuiID Owner; + ImGuiContextHookCallback Callback; + void* UserData; + + ImGuiContextHook() { memset(this, 0, sizeof(*this)); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiContext (main Dear ImGui context) +//----------------------------------------------------------------------------- + +struct ImGuiContext +{ + bool Initialized; + bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. + ImGuiIO IO; + ImGuiStyle Style; + ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() + float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. + float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + ImDrawListSharedData DrawListSharedData; + double Time; + int FrameCount; + int FrameCountEnded; + int FrameCountRendered; + bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() + bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed + bool WithinEndChild; // Set within EndChild() + bool GcCompactAll; // Request full GC + bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() + void* TestEngine; // Test engine user data + + // Inputs + ImVector InputEventsQueue; // Input events which will be trickled/written into IO structure. + ImVector InputEventsTrail; // Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail. + ImGuiMouseSource InputEventsNextMouseSource; + ImU32 InputEventsNextEventId; + + // Windows state + ImVector Windows; // Windows, sorted in display order, back to front + ImVector WindowsFocusOrder; // Root windows, sorted in focus order, back to front. + ImVector WindowsTempSortBuffer; // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child + ImVector CurrentWindowStack; + ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* + int WindowsActiveCount; // Number of unique windows submitted by frame + ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING) + ImGuiWindow* CurrentWindow; // Window being drawn into + ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. + ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. + ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. + ImVec2 WheelingWindowRefMousePos; + int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL + float WheelingWindowReleaseTimer; + ImVec2 WheelingWindowWheelRemainder; + ImVec2 WheelingAxisAvg; + + // Item/widgets state and tracking information + ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] + ImGuiID HoveredId; // Hovered widget, filled during the frame + ImGuiID HoveredIdPreviousFrame; + bool HoveredIdAllowOverlap; + bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0. + float HoveredIdTimer; // Measure contiguous hovering time + float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active + ImGuiID ActiveId; // Active widget + ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame) + float ActiveIdTimer; + bool ActiveIdIsJustActivated; // Set at the time of activation for one frame + bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always) + bool ActiveIdNoClearOnFocusLoss; // Disable losing active id if the active id window gets unfocused. + bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch. + bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state. + bool ActiveIdHasBeenEditedThisFrame; + ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior) + ImGuiWindow* ActiveIdWindow; + ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad + int ActiveIdMouseButton; + ImGuiID ActiveIdPreviousFrame; + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. + float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. + + // [EXPERIMENTAL] Key/Input Ownership + Shortcut Routing system + // - The idea is that instead of "eating" a given key, we can link to an owner. + // - Input query can then read input by specifying ImGuiKeyOwner_Any (== 0), ImGuiKeyOwner_None (== -1) or a custom ID. + // - Routing is requested ahead of time for a given chord (Key + Mods) and granted in NewFrame(). + ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT]; + ImGuiKeyRoutingTable KeysRoutingTable; + ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) + bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (FIXME: This is a shortcut for not taking ownership of 100+ keys but perhaps best to not have the inconsistency) +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + ImU32 ActiveIdUsingNavInputMask; // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);' +#endif + + // Next window/item data + ImGuiID CurrentFocusScopeId; // == g.FocusScopeStack.back() + ImGuiItemFlags CurrentItemFlags; // == g.ItemFlagsStack.back() + ImGuiID DebugLocateId; // Storage for DebugLocateItemOnHover() feature: this is read by ItemAdd() so we keep it in a hot/cached location + ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions + ImGuiLastItemData LastItemData; // Storage for last submitted item (setup by ItemAdd) + ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions + + // Shared stacks + ImVector ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin() + ImVector StyleVarStack; // Stack for PushStyleVar()/PopStyleVar() - inherited by Begin() + ImVector FontStack; // Stack for PushFont()/PopFont() - inherited by Begin() + ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() - inherited by BeginChild(), pushed into by Begin() + ImVectorItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() - inherited by Begin() + ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() + ImVectorOpenPopupStack; // Which popups are open (persistent) + ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) + int BeginMenuCount; + + // Viewports + ImVector Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. + + // Gamepad/keyboard Navigation + ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' + ImGuiID NavId; // Focused item for navigation + ImGuiID NavFocusScopeId; // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set) + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 + ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) + ImGuiActivateFlags NavActivateFlags; + ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest). + ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). + ImGuiKeyChord NavJustMovedToKeyMods; + ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. + ImGuiActivateFlags NavNextActivateFlags; + ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse + ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later. + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid + bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) + bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) + bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. + + // Navigation: Init & Move Requests + bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() + bool NavInitRequest; // Init request for appearing window to select first item + bool NavInitRequestFromMove; + ImGuiNavItemData NavInitResult; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called) + bool NavMoveSubmitted; // Move request submitted, will process result on next NewFrame() + bool NavMoveScoringItems; // Move request submitted, still scoring incoming items + bool NavMoveForwardToNextFrame; + ImGuiNavMoveFlags NavMoveFlags; + ImGuiScrollFlags NavMoveScrollFlags; + ImGuiKeyChord NavMoveKeyMods; + ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down) + ImGuiDir NavMoveDirForDebug; + ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename? + ImRect NavScoringRect; // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring. + ImRect NavScoringNoClipRect; // Some nav operations (such as PageUp/PageDown) enforce a region which clipper will attempt to always keep submitted + int NavScoringDebugCount; // Metrics for debugging + int NavTabbingDir; // Generally -1 or +1, 0 when tabbing without a nav id + int NavTabbingCounter; // >0 when counting items for tabbing + ImGuiNavItemData NavMoveResultLocal; // Best move request candidate within NavWindow + ImGuiNavItemData NavMoveResultLocalVisible; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag) + ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag) + ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy + + // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) + ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab, for reconfiguration (see #4828) + ImGuiKeyChord ConfigNavWindowingKeyPrev; // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab + ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! + ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it. + ImGuiWindow* NavWindowingListWindow; // Internal window actually listing the CTRL+Tab contents + float NavWindowingTimer; + float NavWindowingHighlightAlpha; + bool NavWindowingToggleLayer; + ImVec2 NavWindowingAccumDeltaPos; + ImVec2 NavWindowingAccumDeltaSize; + + // Render + float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) + + // Drag and Drop + bool DragDropActive; + bool DragDropWithinSource; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source. + bool DragDropWithinTarget; // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target. + ImGuiDragDropFlags DragDropSourceFlags; + int DragDropSourceFrameCount; + int DragDropMouseButton; + ImGuiPayload DragDropPayload; + ImRect DragDropTargetRect; // Store rectangle of current target candidate (we favor small targets when overlapping) + ImGuiID DragDropTargetId; + ImGuiDragDropFlags DragDropAcceptFlags; + float DragDropAcceptIdCurrRectSurface; // Target item surface (we resolve overlapping targets by prioritizing the smaller surface) + ImGuiID DragDropAcceptIdCurr; // Target item id (set at the time of accepting the payload) + ImGuiID DragDropAcceptIdPrev; // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets) + int DragDropAcceptFrameCount; // Last time a target expressed a desire to accept the source + ImGuiID DragDropHoldJustPressedId; // Set when holding a payload just made ButtonBehavior() return a press. + ImVector DragDropPayloadBufHeap; // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size + unsigned char DragDropPayloadBufLocal[16]; // Local buffer for small payloads + + // Clipper + int ClipperTempDataStacked; + ImVector ClipperTempData; + + // Tables + ImGuiTable* CurrentTable; + int TablesTempDataStacked; // Temporary table data size (because we leave previous instances undestructed, we generally don't use TablesTempData.Size) + ImVector TablesTempData; // Temporary table data (buffers reused/shared across instances, support nesting) + ImPool Tables; // Persistent table data + ImVector TablesLastTimeActive; // Last used timestamp of each tables (SOA, for efficient GC) + ImVector DrawChannelsTempMergeBuffer; + + // Tab bars + ImGuiTabBar* CurrentTabBar; + ImPool TabBars; + ImVector CurrentTabBarStack; + ImVector ShrinkWidthBuffer; + + // Hover Delay system + ImGuiID HoverItemDelayId; + ImGuiID HoverItemDelayIdPreviousFrame; + float HoverItemDelayTimer; // Currently used by IsItemHovered() + float HoverItemDelayClearTimer; // Currently used by IsItemHovered(): grace time before g.TooltipHoverTimer gets cleared. + ImGuiID HoverItemUnlockedStationaryId; // Mouse has once been stationary on this item. Only reset after departing the item. + ImGuiID HoverWindowUnlockedStationaryId; // Mouse has once been stationary on this window. Only reset after departing the window. + + // Mouse state + ImGuiMouseCursor MouseCursor; + float MouseStationaryTimer; // Time the mouse has been stationary (with some loose heuristic) + ImVec2 MouseLastValidPos; + + // Widget state + ImGuiInputTextState InputTextState; + ImGuiInputTextDeactivatedState InputTextDeactivatedState; + ImFont InputTextPasswordFont; + ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. + ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets + ImGuiID ColorEditCurrentID; // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others). + ImGuiID ColorEditSavedID; // ID we are saving/restoring HS for + float ColorEditSavedHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips + float ColorEditSavedSat; // Backup of last Saturation associated to LastColor, so we can restore Saturation in lossy RGB<>HSV round trips + ImU32 ColorEditSavedColor; // RGB value with alpha set to 0. + ImVec4 ColorPickerRef; // Initial/reference color at the time of opening the color picker. + ImGuiComboPreviewData ComboPreviewData; + float SliderGrabClickOffset; + float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. + bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? + bool DragCurrentAccumDirty; + float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings + float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio + float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? + float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() + short DisabledStackSize; + short TooltipOverrideCount; + ImVector ClipboardHandlerData; // If no custom clipboard handler is defined + ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once + + // Platform support + ImGuiPlatformImeData PlatformImeData; // Data updated by current frame + ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn + char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point + + // Settings + bool SettingsLoaded; + float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero + ImGuiTextBuffer SettingsIniData; // In memory .ini settings + ImVector SettingsHandlers; // List of .ini settings handlers + ImChunkStream SettingsWindows; // ImGuiWindow .ini settings entries + ImChunkStream SettingsTables; // ImGuiTable .ini settings entries + ImVector Hooks; // Hooks for extensions (e.g. test engine) + ImGuiID HookIdNext; // Next available HookId + + // Localization + const char* LocalizationTable[ImGuiLocKey_COUNT]; + + // Capture/Logging + bool LogEnabled; // Currently capturing + ImGuiLogType LogType; // Capture target + ImFileHandle LogFile; // If != NULL log to stdout/ file + ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + const char* LogNextPrefix; + const char* LogNextSuffix; + float LogLinePosY; + bool LogLineFirstItem; + int LogDepthRef; + int LogDepthToExpand; + int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. + + // Debug Tools + ImGuiDebugLogFlags DebugLogFlags; + ImGuiTextBuffer DebugLogBuf; + ImGuiTextIndex DebugLogIndex; + ImU8 DebugLogClipperAutoDisableFrames; + ImU8 DebugLocateFrames; // For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above. + ImS8 DebugBeginReturnValueCullDepth; // Cycle between 0..9 then wrap around. + bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) + ImU8 DebugItemPickerMouseButton; + ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID + ImGuiMetricsConfig DebugMetricsConfig; + ImGuiStackTool DebugStackTool; + + // Misc + float FramerateSecPerFrame[60]; // Calculate estimate of framerate for user over the last 60 frames.. + int FramerateSecPerFrameIdx; + int FramerateSecPerFrameCount; + float FramerateSecPerFrameAccum; + int WantCaptureMouseNextFrame; // Explicit capture override via SetNextFrameWantCaptureMouse()/SetNextFrameWantCaptureKeyboard(). Default to -1. + int WantCaptureKeyboardNextFrame; // " + int WantTextInputNextFrame; + ImVector TempBuffer; // Temporary text buffer + + ImGuiContext(ImFontAtlas* shared_font_atlas) + { + IO.Ctx = this; + InputTextState.Ctx = this; + + Initialized = false; + FontAtlasOwnedByContext = shared_font_atlas ? false : true; + Font = NULL; + FontSize = FontBaseSize = 0.0f; + IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); + Time = 0.0f; + FrameCount = 0; + FrameCountEnded = FrameCountRendered = -1; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + GcCompactAll = false; + TestEngineHookItems = false; + TestEngine = NULL; + + InputEventsNextMouseSource = ImGuiMouseSource_Mouse; + InputEventsNextEventId = 1; + + WindowsActiveCount = 0; + CurrentWindow = NULL; + HoveredWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; + MovingWindow = NULL; + WheelingWindow = NULL; + WheelingWindowStartFrame = -1; + WheelingWindowReleaseTimer = 0.0f; + + DebugHookIdInfo = 0; + HoveredId = HoveredIdPreviousFrame = 0; + HoveredIdAllowOverlap = false; + HoveredIdDisabled = false; + HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; + ActiveId = 0; + ActiveIdIsAlive = 0; + ActiveIdTimer = 0.0f; + ActiveIdIsJustActivated = false; + ActiveIdAllowOverlap = false; + ActiveIdNoClearOnFocusLoss = false; + ActiveIdHasBeenPressedBefore = false; + ActiveIdHasBeenEditedBefore = false; + ActiveIdHasBeenEditedThisFrame = false; + ActiveIdClickOffset = ImVec2(-1, -1); + ActiveIdWindow = NULL; + ActiveIdSource = ImGuiInputSource_None; + ActiveIdMouseButton = -1; + ActiveIdPreviousFrame = 0; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEditedBefore = false; + ActiveIdPreviousFrameWindow = NULL; + LastActiveId = 0; + LastActiveIdTimer = 0.0f; + + ActiveIdUsingNavDirMask = 0x00; + ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + ActiveIdUsingNavInputMask = 0x00; +#endif + + CurrentFocusScopeId = 0; + CurrentItemFlags = ImGuiItemFlags_None; + BeginMenuCount = 0; + + NavWindow = NULL; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; + NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0; + NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; + NavJustMovedToKeyMods = ImGuiMod_None; + NavInputSource = ImGuiInputSource_Keyboard; + NavLayer = ImGuiNavLayer_Main; + NavIdIsAlive = false; + NavMousePosDirty = false; + NavDisableHighlight = true; + NavDisableMouseHover = false; + NavAnyRequest = false; + NavInitRequest = false; + NavInitRequestFromMove = false; + NavMoveSubmitted = false; + NavMoveScoringItems = false; + NavMoveForwardToNextFrame = false; + NavMoveFlags = ImGuiNavMoveFlags_None; + NavMoveScrollFlags = ImGuiScrollFlags_None; + NavMoveKeyMods = ImGuiMod_None; + NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None; + NavScoringDebugCount = 0; + NavTabbingDir = 0; + NavTabbingCounter = 0; + + ConfigNavWindowingKeyNext = ImGuiMod_Ctrl | ImGuiKey_Tab; + ConfigNavWindowingKeyPrev = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab; + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; + + DimBgRatio = 0.0f; + + DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; + DragDropSourceFlags = ImGuiDragDropFlags_None; + DragDropSourceFrameCount = -1; + DragDropMouseButton = -1; + DragDropTargetId = 0; + DragDropAcceptFlags = ImGuiDragDropFlags_None; + DragDropAcceptIdCurrRectSurface = 0.0f; + DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; + DragDropAcceptFrameCount = -1; + DragDropHoldJustPressedId = 0; + memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); + + ClipperTempDataStacked = 0; + + CurrentTable = NULL; + TablesTempDataStacked = 0; + CurrentTabBar = NULL; + + HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0; + HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f; + + MouseCursor = ImGuiMouseCursor_Arrow; + MouseStationaryTimer = 0.0f; + + TempInputId = 0; + ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; + ColorEditCurrentID = ColorEditSavedID = 0; + ColorEditSavedHue = ColorEditSavedSat = 0.0f; + ColorEditSavedColor = 0; + SliderGrabClickOffset = 0.0f; + SliderCurrentAccum = 0.0f; + SliderCurrentAccumDirty = false; + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; + DragSpeedDefaultRatio = 1.0f / 100.0f; + ScrollbarClickDeltaToGrabCenter = 0.0f; + DisabledAlphaBackup = 0.0f; + DisabledStackSize = 0; + TooltipOverrideCount = 0; + + PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); + PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission + PlatformLocaleDecimalPoint = '.'; + + SettingsLoaded = false; + SettingsDirtyTimer = 0.0f; + HookIdNext = 0; + + memset(LocalizationTable, 0, sizeof(LocalizationTable)); + + LogEnabled = false; + LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; + LogFile = NULL; + LogLinePosY = FLT_MAX; + LogLineFirstItem = false; + LogDepthRef = 0; + LogDepthToExpand = LogDepthToExpandDefault = 2; + + DebugLogFlags = ImGuiDebugLogFlags_OutputToTTY; + DebugLocateId = 0; + DebugLogClipperAutoDisableFrames = 0; + DebugLocateFrames = 0; + DebugBeginReturnValueCullDepth = -1; + DebugItemPickerActive = false; + DebugItemPickerMouseButton = ImGuiMouseButton_Left; + DebugItemPickerBreakId = 0; + + memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); + FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0; + FramerateSecPerFrameAccum = 0.0f; + WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; + } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGuiWindowTempData, ImGuiWindow +//----------------------------------------------------------------------------- + +// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. +// (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..) +// (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin) +struct IMGUI_API ImGuiWindowTempData +{ + // Layout + ImVec2 CursorPos; // Current emitting position, in absolute coordinates. + ImVec2 CursorPosPrevLine; + ImVec2 CursorStartPos; // Initial position after Begin(), generally ~ window position + WindowPadding. + ImVec2 CursorMaxPos; // Used to implicitly calculate ContentSize at the beginning of next frame, for scrolling range and auto-resize. Always growing during the frame. + ImVec2 IdealMaxPos; // Used to implicitly calculate ContentSizeIdeal at the beginning of next frame, for auto-resize only. Always growing during the frame. + ImVec2 CurrLineSize; + ImVec2 PrevLineSize; + float CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added). + float PrevLineTextBaseOffset; + bool IsSameLine; + bool IsSetPos; + ImVec1 Indent; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) + ImVec1 ColumnsOffset; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. + ImVec1 GroupOffset; + ImVec2 CursorStartPosLossyness;// Record the loss of precision of CursorStartPos due to really large scrolling amount. This is used by clipper to compensate and fix the most common use case of large scroll area. + + // Keyboard/Gamepad navigation + ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1) + short NavLayersActiveMask; // Which layers have been written to (result from previous frame) + short NavLayersActiveMaskNext;// Which layers have been written to (accumulator for current frame) + bool NavIsScrollPushableX; // Set when current work location may be scrolled horizontally when moving left / right. This is generally always true UNLESS within a column. + bool NavHideHighlightOneFrame; + bool NavWindowHasScrollY; // Set per window when scrolling can be used (== ScrollMax.y > 0.0f) + + // Miscellaneous + bool MenuBarAppending; // FIXME: Remove this + ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. + ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement + int TreeDepth; // Current tree depth. + ImU32 TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary. + ImVector ChildWindows; + ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) + ImGuiOldColumns* CurrentColumns; // Current columns set + int CurrentTableIdx; // Current table index (into g.Tables) + ImGuiLayoutType LayoutType; + ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() + + // Local parameters stacks + // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. + float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). + float TextWrapPos; // Current text wrap pos. + ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) + ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) +}; + +// Storage for one window +struct IMGUI_API ImGuiWindow +{ + ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). + char* Name; // Window name, owned by the window. + ImGuiID ID; // == ImHashStr(Name) + ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ + ImGuiViewportP* Viewport; // Always set in Begin(). Inactive windows may have a NULL value here if their viewport was discarded. + ImVec2 Pos; // Position (always rounded-up to nearest pixel) + ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) + ImVec2 SizeFull; // Size when non collapsed + ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. + ImVec2 ContentSizeIdeal; + ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). + ImVec2 WindowPadding; // Window padding at the time of Begin(). + float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. + float WindowBorderSize; // Window border size at the time of Begin(). + float DecoOuterSizeX1, DecoOuterSizeY1; // Left/Up offsets. Sum of non-scrolling outer decorations (X1 generally == 0.0f. Y1 generally = TitleBarHeight + MenuBarHeight). Locked during Begin(). + float DecoOuterSizeX2, DecoOuterSizeY2; // Right/Down offsets (X2 generally == ScrollbarSize.x, Y2 == ScrollbarSizes.y). + float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes). + int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! + ImGuiID MoveId; // == window->GetID("#MOVE") + ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) + ImVec2 Scroll; + ImVec2 ScrollMax; + ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change) + ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered + ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold + ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. + bool ScrollbarX, ScrollbarY; // Are scrollbars visible? + bool Active; // Set to true on Begin(), unless Collapsed + bool WasActive; + bool WriteAccessed; // Set to true when any widget access the current window + bool Collapsed; // Set when collapsing window to become only title-bar + bool WantCollapseToggle; + bool SkipItems; // Set when items can safely be all clipped (e.g. window not visible or collapsed) + bool Appearing; // Set during the frame where the window is appearing (or re-appearing) + bool Hidden; // Do not display (== HiddenFrames*** > 0) + bool IsFallbackWindow; // Set on the "Debug##Default" window. + bool IsExplicitChild; // Set when passed _ChildWindow, left to false by BeginDocked() + bool HasCloseButton; // Set when the window has a close button (p_open != NULL) + signed char ResizeBorderHeld; // Current border being held for resize (-1: none, otherwise 0-3) + short BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs) + short BeginCountPreviousFrame; // Number of Begin() during the previous frame + short BeginOrderWithinParent; // Begin() order within immediate parent window, if we are a child window. Otherwise 0. + short BeginOrderWithinContext; // Begin() order within entire imgui context. This is mostly used for debugging submission order related issues. + short FocusOrder; // Order within WindowsFocusOrder[], altered when windows are focused. + ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) + ImS8 AutoFitFramesX, AutoFitFramesY; + ImS8 AutoFitChildAxises; + bool AutoFitOnlyGrows; + ImGuiDir AutoPosLastDirection; + ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames + ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size + ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only + ImS8 DisableInputsFrames; // Disable window interactions for N frames + ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. + ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. + ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use. + ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) + ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right. + + ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) + ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. + + // The best way to understand what those rectangles are is to use the 'Metrics->Tools->Show Windows Rectangles' viewer. + // The main 'OuterRect', omitted as a field, is window->Rect(). + ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. + ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar) + ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect. + ImRect WorkRect; // Initially covers the whole scrolling region. Reduced by containers e.g columns/tables when active. Shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward). + ImRect ParentWorkRect; // Backup of WorkRect before entering a container such as columns/tables. Used by e.g. SpanAllColumns functions to easily access. Stacked containers are responsible for maintaining this. // FIXME-WORKRECT: Could be a stack? + ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back(). + ImRect ContentRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on. + ImVec2ih HitTestHoleSize; // Define an optional rectangular hole where mouse will pass-through the window. + ImVec2ih HitTestHoleOffset; + + int LastFrameActive; // Last frame number the window was Active. + float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) + float ItemWidthDefault; + ImGuiStorage StateStorage; + ImVector ColumnsStorage; + float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() + int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) + + ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) + ImDrawList DrawListInst; + ImGuiWindow* ParentWindow; // If we are a child _or_ popup _or_ docked window, this is pointing to our parent. Otherwise NULL. + ImGuiWindow* ParentWindowInBeginStack; + ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes. + ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child. + ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. + ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. + + ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) + ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) + ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space + ImVec2 NavPreferredScoringPosRel[ImGuiNavLayer_COUNT]; // Preferred X/Y position updated when moving on a given axis, reset to FLT_MAX. + ImGuiID NavRootFocusScopeId; // Focus Scope ID at the time of Begin() + + int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy + int MemoryDrawListVtxCapacity; + bool MemoryCompacted; // Set when window extraneous data have been garbage collected + +public: + ImGuiWindow(ImGuiContext* context, const char* name); + ~ImGuiWindow(); + + ImGuiID GetID(const char* str, const char* str_end = NULL); + ImGuiID GetID(const void* ptr); + ImGuiID GetID(int n); + ImGuiID GetIDFromRectangle(const ImRect& r_abs); + + // We don't use g.FontSize because the window may be != g.CurrentWindow. + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float TitleBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } + ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); } + float MenuBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; } + ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Tab bar, Tab item support +//----------------------------------------------------------------------------- + +// Extend ImGuiTabBarFlags_ +enum ImGuiTabBarFlagsPrivate_ +{ + ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around] + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22, // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs +}; + +// Extend ImGuiTabItemFlags_ +enum ImGuiTabItemFlagsPrivate_ +{ + ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, + ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) + ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button +}; + +// Storage for one active tab item (sizeof() 40 bytes) +struct ImGuiTabItem +{ + ImGuiID ID; + ImGuiTabItemFlags Flags; + int LastFrameVisible; + int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + float Offset; // Position relative to beginning of tab + float Width; // Width currently displayed + float ContentWidth; // Width of label, stored during BeginTabItem() call + float RequestedWidth; // Width optionally requested by caller, -1.0f is unused + ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames + ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable + ImS16 IndexDuringLayout; // Index only used during TabBarLayout(). Tabs gets reordered so 'Tabs[n].IndexDuringLayout == n' but may mismatch during additions. + bool WantClose; // Marked as closed by SetTabItemClosed() + + ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; } +}; + +// Storage for a tab bar (sizeof() 152 bytes) +struct IMGUI_API ImGuiTabBar +{ + ImVector Tabs; + ImGuiTabBarFlags Flags; + ImGuiID ID; // Zero for tab-bars used by docking + ImGuiID SelectedTabId; // Selected tab/window + ImGuiID NextSelectedTabId; // Next selected tab/window. Will also trigger a scrolling animation + ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview) + int CurrFrameVisible; + int PrevFrameVisible; + ImRect BarRect; + float CurrTabsContentsHeight; + float PrevTabsContentsHeight; // Record the height of contents submitted below the tab bar + float WidthAllTabs; // Actual width of all tabs (locked during layout) + float WidthAllTabsIdeal; // Ideal width if all tabs were visible and not clipped + float ScrollingAnim; + float ScrollingTarget; + float ScrollingTargetDistToVisibility; + float ScrollingSpeed; + float ScrollingRectMinX; + float ScrollingRectMaxX; + ImGuiID ReorderRequestTabId; + ImS16 ReorderRequestOffset; + ImS8 BeginCount; + bool WantLayout; + bool VisibleTabWasSubmitted; + bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame + ImS16 TabsActiveCount; // Number of tabs submitted this frame. + ImS16 LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem() + float ItemSpacingY; + ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + ImVec2 BackupCursorPos; + ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer. + + ImGuiTabBar(); +}; + +//----------------------------------------------------------------------------- +// [SECTION] Table support +//----------------------------------------------------------------------------- + +#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. +#define IMGUI_TABLE_MAX_COLUMNS 512 // May be further lifted + +// Our current column maximum is 64 but we may raise that in the future. +typedef ImS16 ImGuiTableColumnIdx; +typedef ImU16 ImGuiTableDrawChannelIdx; + +// [Internal] sizeof() ~ 112 +// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. +// We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping. +// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped". +struct ImGuiTableColumn +{ + ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_ + float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be > WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space. + float MinX; // Absolute positions + float MaxX; + float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout() + float WidthAuto; // Automatic width + float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. + float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). + ImRect ClipRect; // Clipping rectangle for the column + ImGuiID UserID; // Optional, value passed to TableSetupColumn() + float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column + float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2) + float ItemWidth; // Current item width for the column, preserved across rows + float ContentMaxXFrozen; // Contents maximum position for frozen rows (apart from headers), from which we can infer content width. + float ContentMaxXUnfrozen; + float ContentMaxXHeadersUsed; // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls + float ContentMaxXHeadersIdeal; + ImS16 NameOffset; // Offset into parent ColumnsNames[] + ImGuiTableColumnIdx DisplayOrder; // Index within Table's IndexToDisplayOrder[] (column may be reordered by users) + ImGuiTableColumnIdx IndexWithinEnabledSet; // Index within enabled/visible set (<= IndexToDisplayOrder) + ImGuiTableColumnIdx PrevEnabledColumn; // Index of prev enabled/visible column within Columns[], -1 if first enabled/visible column + ImGuiTableColumnIdx NextEnabledColumn; // Index of next enabled/visible column within Columns[], -1 if last enabled/visible column + ImGuiTableColumnIdx SortOrder; // Index of this column within sort specs, -1 if not sorting on this column, 0 for single-sort, may be >0 on multi-sort + ImGuiTableDrawChannelIdx DrawChannelCurrent; // Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx DrawChannelFrozen; // Draw channels for frozen rows (often headers) + ImGuiTableDrawChannelIdx DrawChannelUnfrozen; // Draw channels for unfrozen rows + bool IsEnabled; // IsUserEnabled && (Flags & ImGuiTableColumnFlags_Disabled) == 0 + bool IsUserEnabled; // Is the column not marked Hidden by the user? (unrelated to being off view, e.g. clipped by scrolling). + bool IsUserEnabledNextFrame; + bool IsVisibleX; // Is actually in view (e.g. overlapping the host window clipping rectangle, not scrolled). + bool IsVisibleY; + bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not. + bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). + bool IsPreserveWidthAuto; + ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte + ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit + ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem + ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending + ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3) + ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each) + ImU8 SortDirectionsAvailList; // Ordered list of available sort directions (2-bits each, total 8-bits) + + ImGuiTableColumn() + { + memset(this, 0, sizeof(*this)); + StretchWeight = WidthRequest = -1.0f; + NameOffset = -1; + DisplayOrder = IndexWithinEnabledSet = -1; + PrevEnabledColumn = NextEnabledColumn = -1; + SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1; + } +}; + +// Transient cell data stored per row. +// sizeof() ~ 6 +struct ImGuiTableCellData +{ + ImU32 BgColor; // Actual color + ImGuiTableColumnIdx Column; // Column number +}; + +// Per-instance data that needs preserving across frames (seemingly most others do not need to be preserved aside from debug needs. Does that means they could be moved to ImGuiTableTempData?) +struct ImGuiTableInstanceData +{ + ImGuiID TableInstanceID; + float LastOuterHeight; // Outer height from last frame + float LastFirstRowHeight; // Height of first row from last frame (FIXME: this is used as "header height" and may be reworked) + float LastFrozenHeight; // Height of frozen section from last frame + int HoveredRowLast; // Index of row which was hovered last frame. + int HoveredRowNext; // Index of row hovered this frame, set after encountering it. + + ImGuiTableInstanceData() { TableInstanceID = 0; LastOuterHeight = LastFirstRowHeight = LastFrozenHeight = 0.0f; HoveredRowLast = HoveredRowNext = -1; } +}; + +// FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs, incoming RowData +// sizeof() ~ 580 bytes + heap allocs described in TableBeginInitMemory() +struct IMGUI_API ImGuiTable +{ + ImGuiID ID; + ImGuiTableFlags Flags; + void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[] + ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[] + ImSpan Columns; // Point within RawData[] + ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) + ImSpan RowCellData; // Point within RawData[]. Store cells background requests for current row. + ImBitArrayPtr EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map + ImBitArrayPtr EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data + ImBitArrayPtr VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) + ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order) + int SettingsOffset; // Offset in g.SettingsTables + int LastFrameActive; + int ColumnsCount; // Number of columns declared in BeginTable() + int CurrentRow; + int CurrentColumn; + ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched. + ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with + float RowPosY1; + float RowPosY2; + float RowMinHeight; // Height submitted to TableNextRow() + float RowTextBaseline; + float RowIndentOffsetX; + ImGuiTableRowFlags RowFlags : 16; // Current row flags, see ImGuiTableRowFlags_ + ImGuiTableRowFlags LastRowFlags : 16; + int RowBgColorCounter; // Counter for alternating background colors (can be fast-forwarded by e.g clipper), not same as CurrentRow because header rows typically don't increase this. + ImU32 RowBgColor[2]; // Background color override for current row. + ImU32 BorderColorStrong; + ImU32 BorderColorLight; + float BorderX1; + float BorderX2; + float HostIndentX; + float MinColumnWidth; + float OuterPaddingX; + float CellPaddingX; // Padding from each borders + float CellPaddingY; + float CellSpacingX1; // Spacing between non-bordered cells + float CellSpacingX2; + float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details. + float ColumnsGivenWidth; // Sum of current column width + float ColumnsAutoFitWidth; // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window + float ColumnsStretchSumWeights; // Sum of weight of all enabled stretching columns + float ResizedColumnNextWidth; + float ResizeLockMinContentsX2; // Lock minimum contents width while resizing down in order to not create feedback loops. But we allow growing the table. + float RefScale; // Reference scale to be able to rescale columns on font/dpi changes. + ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable(). + ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is + ImRect WorkRect; + ImRect InnerClipRect; + ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries + ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped + ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect. + ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window. + ImRect HostBackupInnerClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground() + ImGuiWindow* OuterWindow; // Parent window for the table + ImGuiWindow* InnerWindow; // Window holding the table data (== OuterWindow or a child window) + ImGuiTextBuffer ColumnsNames; // Contiguous buffer holding columns names + ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly + ImGuiTableInstanceData InstanceDataFirst; + ImVector InstanceDataExtra; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableColumnSortSpecs SortSpecsSingle; + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() + ImGuiTableColumnIdx SortSpecsCount; + ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) + ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns (<= ColumnsCount) + ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn() + ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column! + ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing). + ImGuiTableColumnIdx AutoFitSingleColumn; // Index of single column requesting auto-fit. + ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0. + ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame. + ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. + ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared) + ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1 + ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column. + ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column. + ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column. + ImGuiTableColumnIdx RightMostStretchedColumn; // Index of right-most stretched column. + ImGuiTableColumnIdx ContextPopupColumn; // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot + ImGuiTableColumnIdx FreezeRowsRequest; // Requested frozen rows count + ImGuiTableColumnIdx FreezeRowsCount; // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset) + ImGuiTableColumnIdx FreezeColumnsRequest; // Requested frozen columns count + ImGuiTableColumnIdx FreezeColumnsCount; // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset) + ImGuiTableColumnIdx RowCellDataCurrent; // Index of current RowCellData[] entry in current row + ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. + bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). + bool IsInitializing; + bool IsSortSpecsDirty; + bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag. + bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted). + bool IsSettingsRequestLoad; + bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data. + bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) + bool IsResetAllRequest; + bool IsResetDisplayOrderRequest; + bool IsUnfrozenRows; // Set when we got past the frozen row. + bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() + bool HasScrollbarYCurr; // Whether ANY instance of this table had a vertical scrollbar during the current frame. + bool HasScrollbarYPrev; // Whether ANY instance of this table had a vertical scrollbar during the previous. + bool MemoryCompacted; + bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis + + ImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; } + ~ImGuiTable() { IM_FREE(RawData); } +}; + +// Transient data that are only needed between BeginTable() and EndTable(), those buffers are shared (1 per level of stacked table). +// - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. +// - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. +// sizeof() ~ 112 bytes. +struct IMGUI_API ImGuiTableTempData +{ + int TableIndex; // Index in g.Tables.Buf[] pool + float LastTimeActive; // Last timestamp this structure was used + + ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() + ImDrawListSplitter DrawSplitter; + + ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable() + ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable() + ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable() + ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable() + ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable() + ImVec1 HostBackupColumnsOffset; // Backup of OuterWindow->DC.ColumnsOffset at the end of BeginTable() + float HostBackupItemWidth; // Backup of OuterWindow->DC.ItemWidth at the end of BeginTable() + int HostBackupItemWidthStackSize;//Backup of OuterWindow->DC.ItemWidthStack.Size at the end of BeginTable() + + ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; } +}; + +// sizeof() ~ 12 +struct ImGuiTableColumnSettings +{ + float WidthOrWeight; + ImGuiID UserID; + ImGuiTableColumnIdx Index; + ImGuiTableColumnIdx DisplayOrder; + ImGuiTableColumnIdx SortOrder; + ImU8 SortDirection : 2; + ImU8 IsEnabled : 1; // "Visible" in ini file + ImU8 IsStretch : 1; + + ImGuiTableColumnSettings() + { + WidthOrWeight = 0.0f; + UserID = 0; + Index = -1; + DisplayOrder = SortOrder = -1; + SortDirection = ImGuiSortDirection_None; + IsEnabled = 1; + IsStretch = 0; + } +}; + +// This is designed to be stored in a single ImChunkStream (1 header followed by N ImGuiTableColumnSettings, etc.) +struct ImGuiTableSettings +{ + ImGuiID ID; // Set to 0 to invalidate/delete the setting + ImGuiTableFlags SaveFlags; // Indicate data we want to save using the Resizable/Reorderable/Sortable/Hideable flags (could be using its own flags..) + float RefScale; // Reference scale to be able to rescale columns on font/dpi changes. + ImGuiTableColumnIdx ColumnsCount; + ImGuiTableColumnIdx ColumnsCountMax; // Maximum number of columns this settings instance can store, we can recycle a settings instance with lower number of columns but not higher + bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + + ImGuiTableSettings() { memset(this, 0, sizeof(*this)); } + ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } +}; + +//----------------------------------------------------------------------------- +// [SECTION] ImGui internal API +// No guarantee of forward compatibility here! +//----------------------------------------------------------------------------- + +namespace ImGui +{ + // Windows + // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window) + // If this ever crash because g.CurrentWindow is NULL it means that either + // - ImGui::NewFrame() has never been called, which is illegal. + // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. + inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } + inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } + IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); + IMGUI_API ImGuiWindow* FindWindowByName(const char* name); + IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); + IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window); + IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy); + IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent); + IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below); + IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); + IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); + IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0); + IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); + IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); + IMGUI_API void SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window); + inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } + inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } + inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } + + // Windows: Display Order and Focus Order + IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); + IMGUI_API void FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags); + IMGUI_API void BringWindowToFocusFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayFront(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBack(ImGuiWindow* window); + IMGUI_API void BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* above_window); + IMGUI_API int FindWindowDisplayIndex(ImGuiWindow* window); + IMGUI_API ImGuiWindow* FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window); + + // Fonts, drawing + IMGUI_API void SetCurrentFont(ImFont* font); + inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } + inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. + IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. + IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. + IMGUI_API void AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector* out_list, ImDrawList* draw_list); + + // Init + IMGUI_API void Initialize(); + IMGUI_API void Shutdown(); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). + + // NewFrame + IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); + IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); + IMGUI_API void UpdateMouseMovingWindowNewFrame(); + IMGUI_API void UpdateMouseMovingWindowEndFrame(); + + // Generic context hooks + IMGUI_API ImGuiID AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook); + IMGUI_API void RemoveContextHook(ImGuiContext* context, ImGuiID hook_to_remove); + IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); + + // Viewports + IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); + + // Settings + IMGUI_API void MarkIniSettingsDirty(); + IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); + IMGUI_API void ClearIniSettings(); + IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler); + IMGUI_API void RemoveSettingsHandler(const char* type_name); + IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + + // Settings - Windows + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByID(ImGuiID id); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); + IMGUI_API void ClearWindowSettings(const char* name); + + // Localization + IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count); + inline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : "*Missing Text*"; } + + // Scrolling + IMGUI_API void SetScrollX(ImGuiWindow* window, float scroll_x); + IMGUI_API void SetScrollY(ImGuiWindow* window, float scroll_y); + IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio); + IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio); + + // Early work-in-progress API (ScrollToItem() will become public) + IMGUI_API void ScrollToItem(ImGuiScrollFlags flags = 0); + IMGUI_API void ScrollToRect(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0); + IMGUI_API ImVec2 ScrollToRectEx(ImGuiWindow* window, const ImRect& rect, ImGuiScrollFlags flags = 0); +//#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& rect) { ScrollToRect(window, rect, ImGuiScrollFlags_KeepVisibleEdgeY); } +//#endif + + // Basic Accessors + inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } + inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } + inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } + inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } + IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); + IMGUI_API void ClearActiveID(); + IMGUI_API ImGuiID GetHoveredID(); + IMGUI_API void SetHoveredID(ImGuiID id); + IMGUI_API void KeepAliveID(ImGuiID id); + IMGUI_API void MarkItemEdited(ImGuiID id); // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function. + IMGUI_API void PushOverrideID(ImGuiID id); // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes) + IMGUI_API ImGuiID GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed); + IMGUI_API ImGuiID GetIDWithSeed(int n, ImGuiID seed); + + // Basic Helpers for widget code + IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); + inline void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min. + IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags); + IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); + IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); + IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); + IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); + IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); + IMGUI_API void PushMultiItemsWidths(int components, float width_full); + IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly) + IMGUI_API ImVec2 GetContentRegionMaxAbs(); + IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); + + // Parameter stacks (shared) + IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); + IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx); + + // Logging/Capture + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); + + // Popups, Modals, Tooltips + IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); + IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None); + IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); + IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); + IMGUI_API void ClosePopupsExceptModals(); + IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); + IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); + IMGUI_API bool BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); + IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); + IMGUI_API ImGuiWindow* GetTopMostPopupModal(); + IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal(); + IMGUI_API ImGuiWindow* FindBlockingModal(ImGuiWindow* window); + IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); + IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy); + + // Menus + IMGUI_API bool BeginViewportSideBar(const char* name, ImGuiViewport* viewport, ImGuiDir dir, float size, ImGuiWindowFlags window_flags); + IMGUI_API bool BeginMenuEx(const char* label, const char* icon, bool enabled = true); + IMGUI_API bool MenuItemEx(const char* label, const char* icon, const char* shortcut = NULL, bool selected = false, bool enabled = true); + + // Combos + IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags); + IMGUI_API bool BeginComboPreview(); + IMGUI_API void EndComboPreview(); + + // Gamepad/Keyboard Navigation + IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); + IMGUI_API void NavInitRequestApplyResult(); + IMGUI_API bool NavMoveRequestButNoResultYet(); + IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); + IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); + IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); + IMGUI_API void NavMoveRequestCancel(); + IMGUI_API void NavMoveRequestApplyResult(); + IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis); + IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); + IMGUI_API void SetNavWindow(ImGuiWindow* window); + IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); + + // Focus/Activation + // This should be part of a larger set of API: FocusItem(offset = -1), FocusItemByID(id), ActivateItem(offset = -1), ActivateItemByID(id) etc. which are + // much harder to design and implement than expected. I have a couple of private branches on this matter but it's not simple. For now implementing the easy ones. + IMGUI_API void FocusItem(); // Focus last item (no selection/activation). + IMGUI_API void ActivateItemByID(ImGuiID id); // Activate an item by ID (button, checkbox, tree node etc.). Activation is queued and processed on the next frame when the item is encountered again. + + // Inputs + // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. + inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; } + inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; } + inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; } + inline bool IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; } + inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } + inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } + inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } + inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); } + inline ImGuiKey ConvertSingleModFlagToKey(ImGuiContext* ctx, ImGuiKey key) + { + ImGuiContext& g = *ctx; + if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl; + if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift; + if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt; + if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper; + if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl); + return key; + } + + IMGUI_API ImGuiKeyData* GetKeyData(ImGuiContext* ctx, ImGuiKey key); + inline ImGuiKeyData* GetKeyData(ImGuiKey key) { ImGuiContext& g = *GImGui; return GetKeyData(&g, key); } + IMGUI_API void GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size); + inline ImGuiKey MouseButtonToKey(ImGuiMouseButton button) { IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); return (ImGuiKey)(ImGuiKey_MouseLeft + button); } + IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f); + IMGUI_API ImVec2 GetKeyMagnitude2d(ImGuiKey key_left, ImGuiKey key_right, ImGuiKey key_up, ImGuiKey key_down); + IMGUI_API float GetNavTweakPressedAmount(ImGuiAxis axis); + IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate); + IMGUI_API void GetTypematicRepeatRate(ImGuiInputFlags flags, float* repeat_delay, float* repeat_rate); + IMGUI_API void SetActiveIdUsingAllKeyboardKeys(); + inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; } + + // [EXPERIMENTAL] Low-Level: Key/Input Ownership + // - The idea is that instead of "eating" a given input, we can link to an owner id. + // - Ownership is most often claimed as a result of reacting to a press/down event (but occasionally may be claimed ahead). + // - Input queries can then read input by specifying ImGuiKeyOwner_Any (== 0), ImGuiKeyOwner_None (== -1) or a custom ID. + // - Legacy input queries (without specifying an owner or _Any or _None) are equivalent to using ImGuiKeyOwner_Any (== 0). + // - Input ownership is automatically released on the frame after a key is released. Therefore: + // - for ownership registration happening as a result of a down/press event, the SetKeyOwner() call may be done once (common case). + // - for ownership registration happening ahead of a down/press event, the SetKeyOwner() call needs to be made every frame (happens if e.g. claiming ownership on hover). + // - SetItemKeyOwner() is a shortcut for common simple case. A custom widget will probably want to call SetKeyOwner() multiple times directly based on its interaction state. + // - This is marked experimental because not all widgets are fully honoring the Set/Test idioms. We will need to move forward step by step. + // Please open a GitHub Issue to submit your usage scenario or if there's a use case you need solved. + IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key); + IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); + IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord key, ImGuiID owner_id, ImGuiInputFlags flags = 0); + IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. + IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id' + inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(ctx, key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; } + + // [EXPERIMENTAL] High-Level: Input Access functions w/ support for Key/Input Ownership + // - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag. + // - Expected to be later promoted to public API, the prototypes are designed to replace existing ones (since owner_id can default to Any == 0) + // - Specifying a value for 'ImGuiID owner' will test that EITHER the key is NOT owned (UNLESS locked), EITHER the key is owned by 'owner'. + // Legacy functions use ImGuiKeyOwner_Any meaning that they typically ignore ownership, unless a call to SetKeyOwner() explicitly used ImGuiInputFlags_LockThisFrame or ImGuiInputFlags_LockUntilRelease. + // - Binding generators may want to ignore those for now, or suffix them with Ex() until we decide if this gets moved into public API. + IMGUI_API bool IsKeyDown(ImGuiKey key, ImGuiID owner_id); + IMGUI_API bool IsKeyPressed(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0); // Important: when transitioning from old to new IsKeyPressed(): old API has "bool repeat = true", so would default to repeat. New API requiress explicit ImGuiInputFlags_Repeat. + IMGUI_API bool IsKeyReleased(ImGuiKey key, ImGuiID owner_id); + IMGUI_API bool IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id); + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, ImGuiID owner_id, ImGuiInputFlags flags = 0); + IMGUI_API bool IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id); + + // [EXPERIMENTAL] Shortcut Routing + // - ImGuiKeyChord = a ImGuiKey optionally OR-red with ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. + // ImGuiKey_C (accepted by functions taking ImGuiKey or ImGuiKeyChord) + // ImGuiKey_C | ImGuiMod_Ctrl (accepted by functions taking ImGuiKeyChord) + // ONLY ImGuiMod_XXX values are legal to 'OR' with an ImGuiKey. You CANNOT 'OR' two ImGuiKey values. + // - When using one of the routing flags (e.g. ImGuiInputFlags_RouteFocused): routes requested ahead of time given a chord (key + modifiers) and a routing policy. + // - Routes are resolved during NewFrame(): if keyboard modifiers are matching current ones: SetKeyOwner() is called + route is granted for the frame. + // - Route is granted to a single owner. When multiple requests are made we have policies to select the winning route. + // - Multiple read sites may use the same owner id and will all get the granted route. + // - For routing: when owner_id is 0 we use the current Focus Scope ID as a default owner in order to identify our location. + IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0); + IMGUI_API bool SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id = 0, ImGuiInputFlags flags = 0); + IMGUI_API bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id); + IMGUI_API ImGuiKeyRoutingData* GetShortcutRoutingData(ImGuiKeyChord key_chord); + + // [EXPERIMENTAL] Focus Scope + // This is generally used to identify a unique input location (for e.g. a selection set) + // There is one per window (automatically set in Begin), but: + // - Selection patterns generally need to react (e.g. clear a selection) when landing on one item of the set. + // So in order to identify a set multiple lists in same window may each need a focus scope. + // If you imagine an hypothetical BeginSelectionGroup()/EndSelectionGroup() api, it would likely call PushFocusScope()/EndFocusScope() + // - Shortcut routing also use focus scope as a default location identifier if an owner is not provided. + // We don't use the ID Stack for this as it is common to want them separate. + IMGUI_API void PushFocusScope(ImGuiID id); + IMGUI_API void PopFocusScope(); + inline ImGuiID GetCurrentFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentFocusScopeId; } // Focus scope we are outputting into, set by PushFocusScope() + + // Drag and Drop + IMGUI_API bool IsDragDropActive(); + IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id); + IMGUI_API void ClearDragDrop(); + IMGUI_API bool IsDragDropPayloadBeingAccepted(); + IMGUI_API void RenderDragDropTargetRect(const ImRect& bb); + + // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) + IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). + IMGUI_API void EndColumns(); // close columns + IMGUI_API void PushColumnClipRect(int column_index); + IMGUI_API void PushColumnsBackground(); + IMGUI_API void PopColumnsBackground(); + IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); + IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); + IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); + IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); + + // Tables: Candidates for public API + IMGUI_API void TableOpenContextMenu(int column_n = -1); + IMGUI_API void TableSetColumnWidth(int column_n, float width); + IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); + IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. + IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. + IMGUI_API float TableGetHeaderRowHeight(); + IMGUI_API void TablePushBackgroundChannel(); + IMGUI_API void TablePopBackgroundChannel(); + + // Tables: Internals + inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } + IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); + IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); + IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); + IMGUI_API void TableBeginApplyRequests(ImGuiTable* table); + IMGUI_API void TableSetupDrawChannels(ImGuiTable* table); + IMGUI_API void TableUpdateLayout(ImGuiTable* table); + IMGUI_API void TableUpdateBorders(ImGuiTable* table); + IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); + IMGUI_API void TableDrawBorders(ImGuiTable* table); + IMGUI_API void TableDrawContextMenu(ImGuiTable* table); + IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); + IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); + inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } + inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } + IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); + IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); + IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); + IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column); + IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column); + IMGUI_API void TableBeginRow(ImGuiTable* table); + IMGUI_API void TableEndRow(ImGuiTable* table); + IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); + IMGUI_API void TableEndCell(ImGuiTable* table); + IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); + IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); + IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); + IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); + IMGUI_API void TableRemove(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); + IMGUI_API void TableGcCompactSettings(); + + // Tables: Settings + IMGUI_API void TableLoadSettings(ImGuiTable* table); + IMGUI_API void TableSaveSettings(ImGuiTable* table); + IMGUI_API void TableResetSettings(ImGuiTable* table); + IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); + IMGUI_API void TableSettingsAddSettingsHandler(); + IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); + IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); + + // Tab Bars + inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; } + IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); + IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order); + IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar); + inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); } + IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); + IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset); + IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos); + IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); + IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); + IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker); + IMGUI_API ImVec2 TabItemCalcSize(ImGuiWindow* window); + IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); + IMGUI_API void TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped); + + // Render helpers + // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. + // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally) + IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); + IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); + IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); + IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); + IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); + IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); + IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); + IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight + IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. + IMGUI_API void RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); + + // Render helpers (those functions don't access any ImGui state!) + IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); + IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); + IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); + IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); + IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); + IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding); + + // Widgets + IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); + IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); + IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); + IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f); + IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width); + IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); + IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); + + // Widgets: Window Decorations + IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); + IMGUI_API void Scrollbar(ImGuiAxis axis); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); + IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); + IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners + IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); + + // Widgets low-level behaviors + IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags); + IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API void TreePushOverrideID(ImGuiID id); + IMGUI_API void TreeNodeSetOpen(ImGuiID id, bool open); + IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging. + + // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. + // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). + // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " + template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); + template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); + template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); + template IMGUI_API bool CheckboxFlagsT(const char* label, T* flags, T flags_value); + + // Data type helpers + IMGUI_API const ImGuiDataTypeInfo* DataTypeGetInfo(ImGuiDataType data_type); + IMGUI_API int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format); + IMGUI_API void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format); + IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); + IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); + + // InputText + IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); + IMGUI_API void InputTextDeactivateHook(ImGuiID id); + IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); + IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); + inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } + inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active + + // Color + IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags); + IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags); + + // Plot + IMGUI_API int PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg); + + // Shade functions (write over already created vertices) + IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); + IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); + + // Garbage collection + IMGUI_API void GcCompactTransientMiscBuffers(); + IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); + IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); + + // Debug Log + IMGUI_API void DebugLog(const char* fmt, ...) IM_FMTARGS(1); + IMGUI_API void DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1); + + // Debug Tools + IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + IMGUI_API void DebugLocateItem(ImGuiID target_id); // Call sparingly: only 1 at the same time! + IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id); // Only call on reaction to a mouse Hover: because only 1 at the same time! + IMGUI_API void DebugLocateItemResolveWithLastItem(); + inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); } + inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } + IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); + IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); + IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); + IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label); + IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); + IMGUI_API void DebugNodeFont(ImFont* font); + IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); + IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); + IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); + IMGUI_API void DebugNodeTable(ImGuiTable* table); + IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings); + IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState* state); + IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label); + IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings); + IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); + IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); + IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); + IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list); + IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); + + // Obsolete functions +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline void SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); } // Changed in 1.89 + inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 + + // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets that used FocusableItemRegister(): + // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' + // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_Focused) != 0' + // (New) IMGUI_VERSION_NUM >= 18413: using 'ItemAdd(..., ImGuiItemFlags_Inputable)' and 'bool tab_focused = (GetItemStatusFlags() & ImGuiItemStatusFlags_FocusedTabbing) != 0 || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))' (WIP) + // Widget code are simplified as there's no need to call FocusableItemUnregister() while managing the transition from regular widget to TempInputText() + inline bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id) { IM_ASSERT(0); IM_UNUSED(window); IM_UNUSED(id); return false; } // -> pass ImGuiItemAddFlags_Inputable flag to ItemAdd() + inline void FocusableItemUnregister(ImGuiWindow* window) { IM_ASSERT(0); IM_UNUSED(window); } // -> unnecessary: TempInputText() uses ImGuiInputTextFlags_MergedItem +#endif +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! +#endif + +} // namespace ImGui + + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas internal API +//----------------------------------------------------------------------------- + +// This structure is likely to evolve as we add support for incremental atlas updates +struct ImFontBuilderIO +{ + bool (*FontBuilder_Build)(ImFontAtlas* atlas); +}; + +// Helper for font builder +#ifdef IMGUI_ENABLE_STB_TRUETYPE +IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); +#endif +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); +IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); + +//----------------------------------------------------------------------------- +// [SECTION] Test Engine specific hooks (imgui_test_engine) +//----------------------------------------------------------------------------- + +#ifdef IMGUI_ENABLE_TEST_ENGINE +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, ImGuiID id, const ImRect& bb, const ImGuiLastItemData* item_data); // item_data may be NULL +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); +extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); +extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiID id); + +// In IMGUI_VERSION_NUM >= 18934: changed IMGUI_TEST_ENGINE_ITEM_ADD(bb,id) to IMGUI_TEST_ENGINE_ITEM_ADD(id,bb,item_data); +#define IMGUI_TEST_ENGINE_ITEM_ADD(_ID,_BB,_ITEM_DATA) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _ID, _BB, _ITEM_DATA) // Register item bounding box +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log +#else +#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) ((void)0) +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g) +#endif + +//----------------------------------------------------------------------------- + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_stdlib.cpp b/Amalgam/include/ImGui/imgui_stdlib.cpp new file mode 100644 index 0000000..cf69aa8 --- /dev/null +++ b/Amalgam/include/ImGui/imgui_stdlib.cpp @@ -0,0 +1,85 @@ +// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) +// This is also an example of how you may wrap your own similar types. + +// Changelog: +// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string + +// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki: +// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness + +#include "imgui.h" +#include "imgui_stdlib.h" + +// Clang warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + +struct InputTextCallback_UserData +{ + std::string* Str; + ImGuiInputTextCallback ChainCallback; + void* ChainCallbackUserData; +}; + +static int InputTextCallback(ImGuiInputTextCallbackData* data) +{ + InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData; + if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) + { + // Resize string callback + // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want. + std::string* str = user_data->Str; + IM_ASSERT(data->Buf == str->c_str()); + str->resize(data->BufTextLen); + data->Buf = (char*)str->c_str(); + } + else if (user_data->ChainCallback) + { + // Forward to user callback, if any + data->UserData = user_data->ChainCallbackUserData; + return user_data->ChainCallback(data); + } + return 0; +} + +bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); +} + +bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + flags |= ImGuiInputTextFlags_CallbackResize; + + InputTextCallback_UserData cb_user_data; + cb_user_data.Str = str; + cb_user_data.ChainCallback = callback; + cb_user_data.ChainCallbackUserData = user_data; + return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif diff --git a/Amalgam/include/ImGui/imgui_stdlib.h b/Amalgam/include/ImGui/imgui_stdlib.h new file mode 100644 index 0000000..835a808 --- /dev/null +++ b/Amalgam/include/ImGui/imgui_stdlib.h @@ -0,0 +1,21 @@ +// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) +// This is also an example of how you may wrap your own similar types. + +// Changelog: +// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string + +// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki: +// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness + +#pragma once + +#include + +namespace ImGui +{ + // ImGui::InputText() with std::string + // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity + IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); + IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); + IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); +} diff --git a/Amalgam/include/ImGui/imgui_tables.cpp b/Amalgam/include/ImGui/imgui_tables.cpp new file mode 100644 index 0000000..5985215 --- /dev/null +++ b/Amalgam/include/ImGui/imgui_tables.cpp @@ -0,0 +1,4141 @@ +// dear imgui, v1.89.8 +// (tables and columns code) + +/* + +Index of this file: + +// [SECTION] Commentary +// [SECTION] Header mess +// [SECTION] Tables: Main code +// [SECTION] Tables: Simple accessors +// [SECTION] Tables: Row changes +// [SECTION] Tables: Columns changes +// [SECTION] Tables: Columns width management +// [SECTION] Tables: Drawing +// [SECTION] Tables: Sorting +// [SECTION] Tables: Headers +// [SECTION] Tables: Context Menu +// [SECTION] Tables: Settings (.ini data) +// [SECTION] Tables: Garbage Collection +// [SECTION] Tables: Debugging +// [SECTION] Columns, BeginColumns, EndColumns, etc. + +*/ + +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.GoToAll") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. + +//----------------------------------------------------------------------------- +// [SECTION] Commentary +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typical tables call flow: (root level is generally public API): +//----------------------------------------------------------------------------- +// - BeginTable() user begin into a table +// | BeginChild() - (if ScrollX/ScrollY is set) +// | TableBeginInitMemory() - first time table is used +// | TableResetSettings() - on settings reset +// | TableLoadSettings() - on settings load +// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests +// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) +// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width +// - TableSetupColumn() user submit columns details (optional) +// - TableSetupScrollFreeze() user submit scroll freeze information (optional) +//----------------------------------------------------------------------------- +// - TableUpdateLayout() [Internal] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow(). +// | TableSetupDrawChannels() - setup ImDrawList channels +// | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission +// | TableDrawContextMenu() - draw right-click context menu +//----------------------------------------------------------------------------- +// - TableHeadersRow() or TableHeader() user submit a headers row (optional) +// | TableSortSpecsClickColumn() - when left-clicked: alter sort order and sort direction +// | TableOpenContextMenu() - when right-clicked: trigger opening of the default context menu +// - TableGetSortSpecs() user queries updated sort specs (optional, generally after submitting headers) +// - TableNextRow() user begin into a new row (also automatically called by TableHeadersRow()) +// | TableEndRow() - finish existing row +// | TableBeginRow() - add a new row +// - TableSetColumnIndex() / TableNextColumn() user begin into a cell +// | TableEndCell() - close existing column/cell +// | TableBeginCell() - enter into current column/cell +// - [...] user emit contents +//----------------------------------------------------------------------------- +// - EndTable() user ends the table +// | TableDrawBorders() - draw outer borders, inner vertical borders +// | TableMergeDrawChannels() - merge draw channels if clipping isn't required +// | EndChild() - (if ScrollX/ScrollY is set) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// TABLE SIZING +//----------------------------------------------------------------------------- +// (Read carefully because this is subtle but it does make sense!) +//----------------------------------------------------------------------------- +// About 'outer_size': +// Its meaning needs to differ slightly depending on if we are using ScrollX/ScrollY flags. +// Default value is ImVec2(0.0f, 0.0f). +// X +// - outer_size.x <= 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN or 0.0f will align exactly on right-most edge. +// - outer_size.x > 0.0f -> Set Fixed width. +// Y with ScrollX/ScrollY disabled: we output table directly in current window +// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll. +// - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set) +// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtenY is set) +// Y with ScrollX/ScrollY enabled: using a child window for scrolling +// - outer_size.y < 0.0f -> Bottom-align. Not meaningful if parent window can vertically scroll. +// - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window. +// - outer_size.y > 0.0f -> Set Exact height. Recommended when using Scrolling on any axis. +//----------------------------------------------------------------------------- +// Outer size is also affected by the NoHostExtendX/NoHostExtendY flags. +// Important to note how the two flags have slightly different behaviors! +// - ImGuiTableFlags_NoHostExtendX -> Make outer width auto-fit to columns (overriding outer_size.x value). Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. +// - ImGuiTableFlags_NoHostExtendY -> Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY is disabled. Data below the limit will be clipped and not visible. +// In theory ImGuiTableFlags_NoHostExtendY could be the default and any non-scrolling tables with outer_size.y != 0.0f would use exact height. +// This would be consistent but perhaps less useful and more confusing (as vertically clipped items are not useful and not easily noticeable). +//----------------------------------------------------------------------------- +// About 'inner_width': +// With ScrollX disabled: +// - inner_width -> *ignored* +// With ScrollX enabled: +// - inner_width < 0.0f -> *illegal* fit in known width (right align from outer_size.x) <-- weird +// - inner_width = 0.0f -> fit in outer_width: Fixed size columns will take space they need (if avail, otherwise shrink down), Stretch columns becomes Fixed columns. +// - inner_width > 0.0f -> override scrolling width, generally to be larger than outer_size.x. Fixed column take space they need (if avail, otherwise shrink down), Stretch columns share remaining space! +//----------------------------------------------------------------------------- +// Details: +// - If you want to use Stretch columns with ScrollX, you generally need to specify 'inner_width' otherwise the concept +// of "available space" doesn't make sense. +// - Even if not really useful, we allow 'inner_width < outer_size.x' for consistency and to facilitate understanding +// of what the value does. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// COLUMNS SIZING POLICIES +// (Reference: ImGuiTableFlags_SizingXXX flags and ImGuiTableColumnFlags_WidthXXX flags) +//----------------------------------------------------------------------------- +// About overriding column sizing policy and width/weight with TableSetupColumn(): +// We use a default parameter of -1 for 'init_width'/'init_weight'. +// - with ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic +// - with ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom +// - with ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f +// - with ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom +// Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f) +// and you can fit a 100.0f wide item in it without clipping and with padding honored. +//----------------------------------------------------------------------------- +// About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag) +// - with Table policy ImGuiTableFlags_SizingFixedFit --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width +// - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is max of all contents width +// - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f +// - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents +// Default Width and default Weight can be overridden when calling TableSetupColumn(). +//----------------------------------------------------------------------------- +// About mixing Fixed/Auto and Stretch columns together: +// - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. +// - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! +// that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. +// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the width of the maximum contents. +// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weights/widths. +//----------------------------------------------------------------------------- +// About using column width: +// If a column is manually resizable or has a width specified with TableSetupColumn(): +// - you may use GetContentRegionAvail().x to query the width available in a given column. +// - right-side alignment features such as SetNextItemWidth(-x) or PushItemWidth(-x) will rely on this width. +// If the column is not resizable and has no width specified with TableSetupColumn(): +// - its width will be automatic and be set to the max of items submitted. +// - therefore you generally cannot have ALL items of the columns use e.g. SetNextItemWidth(-FLT_MIN). +// - but if the column has one or more items of known/fixed size, this will become the reference width used by SetNextItemWidth(-FLT_MIN). +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// TABLES CLIPPING/CULLING +//----------------------------------------------------------------------------- +// About clipping/culling of Rows in Tables: +// - For large numbers of rows, it is recommended you use ImGuiListClipper to submit only visible rows. +// ImGuiListClipper is reliant on the fact that rows are of equal height. +// See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper. +// - Note that auto-resizing columns don't play well with using the clipper. +// By default a table with _ScrollX but without _Resizable will have column auto-resize. +// So, if you want to use the clipper, make sure to either enable _Resizable, either setup columns width explicitly with _WidthFixed. +//----------------------------------------------------------------------------- +// About clipping/culling of Columns in Tables: +// - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing +// width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know +// it is not going to contribute to row height. +// In many situations, you may skip submitting contents for every column but one (e.g. the first one). +// - Case A: column is not hidden by user, and at least partially in sight (most common case). +// - Case B: column is clipped / out of sight (because of scrolling or parent ClipRect): TableNextColumn() return false as a hint but we still allow layout output. +// - Case C: column is hidden explicitly by the user (e.g. via the context menu, or _DefaultHide column flag, etc.). +// +// [A] [B] [C] +// TableNextColumn(): true false false -> [userland] when TableNextColumn() / TableSetColumnIndex() returns false, user can skip submitting items but only if the column doesn't contribute to row height. +// SkipItems: false false true -> [internal] when SkipItems is true, most widgets will early out if submitted, resulting is no layout output. +// ClipRect: normal zero-width zero-width -> [internal] when ClipRect is zero, ItemAdd() will return false and most widgets will early out mid-way. +// ImDrawList output: normal dummy dummy -> [internal] when using the dummy channel, ImDrawList submissions (if any) will be wasted (because cliprect is zero-width anyway). +// +// - We need to distinguish those cases because non-hidden columns that are clipped outside of scrolling bounds should still contribute their height to the row. +// However, in the majority of cases, the contribution to row height is the same for all columns, or the tallest cells are known by the programmer. +//----------------------------------------------------------------------------- +// About clipping/culling of whole Tables: +// - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_internal.h" + +// System includes +#include // intptr_t + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Tables: Main code +//----------------------------------------------------------------------------- +// - TableFixFlags() [Internal] +// - TableFindByID() [Internal] +// - BeginTable() +// - BeginTableEx() [Internal] +// - TableBeginInitMemory() [Internal] +// - TableBeginApplyRequests() [Internal] +// - TableSetupColumnFlags() [Internal] +// - TableUpdateLayout() [Internal] +// - TableUpdateBorders() [Internal] +// - EndTable() +// - TableSetupColumn() +// - TableSetupScrollFreeze() +//----------------------------------------------------------------------------- + +// Configuration +static const int TABLE_DRAW_CHANNEL_BG0 = 0; +static const int TABLE_DRAW_CHANNEL_BG2_FROZEN = 1; +static const int TABLE_DRAW_CHANNEL_NOCLIP = 2; // When using ImGuiTableFlags_NoClip (this becomes the last visible channel) +static const float TABLE_BORDER_SIZE = 1.0f; // FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering. +static const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f; // Extend outside inner borders. +static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped. + +// Helper +inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window) +{ + // Adjust flags: set default sizing policy + if ((flags & ImGuiTableFlags_SizingMask_) == 0) + flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame; + + // Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame + if ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableFlags_NoKeepColumnsVisible; + + // Adjust flags: enforce borders when resizable + if (flags & ImGuiTableFlags_Resizable) + flags |= ImGuiTableFlags_BordersInnerV; + + // Adjust flags: disable NoHostExtendX/NoHostExtendY if we have any scrolling going on + if (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) + flags &= ~(ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoHostExtendY); + + // Adjust flags: NoBordersInBodyUntilResize takes priority over NoBordersInBody + if (flags & ImGuiTableFlags_NoBordersInBodyUntilResize) + flags &= ~ImGuiTableFlags_NoBordersInBody; + + // Adjust flags: disable saved settings if there's nothing to save + if ((flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Sortable)) == 0) + flags |= ImGuiTableFlags_NoSavedSettings; + + // Inherit _NoSavedSettings from top-level window (child windows always have _NoSavedSettings set) + if (outer_window->RootWindow->Flags & ImGuiWindowFlags_NoSavedSettings) + flags |= ImGuiTableFlags_NoSavedSettings; + + return flags; +} + +ImGuiTable* ImGui::TableFindByID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + return g.Tables.GetByKey(id); +} + +// Read about "TABLE SIZING" at the top of this file. +bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width) +{ + ImGuiID id = GetID(str_id); + return BeginTableEx(str_id, id, columns_count, flags, outer_size, inner_width); +} + +bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* outer_window = GetCurrentWindow(); + if (outer_window->SkipItems) // Consistent with other tables + beneficial side effect that assert on miscalling EndTable() will be more visible. + return false; + + // Sanity checks + IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS); + if (flags & ImGuiTableFlags_ScrollX) + IM_ASSERT(inner_width >= 0.0f); + + // If an outer size is specified ahead we will be able to early out when not visible. Exact clipping criteria may evolve. + const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; + const ImVec2 avail_size = GetContentRegionAvail(); + ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); + ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); + if (use_child_window && IsClippedEx(outer_rect, 0)) + { + ItemSize(outer_rect); + return false; + } + + // Acquire storage for the table + ImGuiTable* table = g.Tables.GetOrAddByKey(id); + const ImGuiTableFlags table_last_flags = table->Flags; + + // Acquire temporary buffers + const int table_idx = g.Tables.GetIndex(table); + if (++g.TablesTempDataStacked > g.TablesTempData.Size) + g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData()); + ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1]; + temp_data->TableIndex = table_idx; + table->DrawSplitter = &table->TempData->DrawSplitter; + table->DrawSplitter->Clear(); + + // Fix flags + table->IsDefaultSizingPolicy = (flags & ImGuiTableFlags_SizingMask_) == 0; + flags = TableFixFlags(flags, outer_window); + + // Initialize + const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; + table->ID = id; + table->Flags = flags; + table->LastFrameActive = g.FrameCount; + table->OuterWindow = table->InnerWindow = outer_window; + table->ColumnsCount = columns_count; + table->IsLayoutLocked = false; + table->InnerWidth = inner_width; + temp_data->UserOuterSize = outer_size; + + // Instance data (for instance 0, TableID == TableInstanceID) + ImGuiID instance_id; + table->InstanceCurrent = (ImS16)instance_no; + if (instance_no > 0) + { + IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID"); + if (table->InstanceDataExtra.Size < instance_no) + table->InstanceDataExtra.push_back(ImGuiTableInstanceData()); + instance_id = GetIDWithSeed(instance_no, GetIDWithSeed("##Instances", NULL, id)); // Push "##Instances" followed by (int)instance_no in ID stack. + } + else + { + instance_id = id; + } + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + table_instance->TableInstanceID = instance_id; + + // When not using a child window, WorkRect.Max will grow as we append contents. + if (use_child_window) + { + // Ensure no vertical scrollbar appears if we only want horizontal one, to make flag consistent + // (we have no other way to disable vertical scrollbar of a window while keeping the horizontal one showing) + ImVec2 override_content_size(FLT_MAX, FLT_MAX); + if ((flags & ImGuiTableFlags_ScrollX) && !(flags & ImGuiTableFlags_ScrollY)) + override_content_size.y = FLT_MIN; + + // Ensure specified width (when not specified, Stretched columns will act as if the width == OuterWidth and + // never lead to any scrolling). We don't handle inner_width < 0.0f, we could potentially use it to right-align + // based on the right side of the child window work rect, which would require knowing ahead if we are going to + // have decoration taking horizontal spaces (typically a vertical scrollbar). + if ((flags & ImGuiTableFlags_ScrollX) && inner_width > 0.0f) + override_content_size.x = inner_width; + + if (override_content_size.x != FLT_MAX || override_content_size.y != FLT_MAX) + SetNextWindowContentSize(ImVec2(override_content_size.x != FLT_MAX ? override_content_size.x : 0.0f, override_content_size.y != FLT_MAX ? override_content_size.y : 0.0f)); + + // Reset scroll if we are reactivating it + if ((table_last_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) + SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + + // Create scrolling region (without border and zero window padding) + ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; + BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags); + table->InnerWindow = g.CurrentWindow; + table->WorkRect = table->InnerWindow->WorkRect; + table->OuterRect = table->InnerWindow->Rect(); + table->InnerRect = table->InnerWindow->InnerRect; + IM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f); + + // When using multiple instances, ensure they have the same amount of horizontal decorations (aka vertical scrollbar) so stretched columns can be aligned) + if (instance_no == 0) + { + table->HasScrollbarYPrev = table->HasScrollbarYCurr; + table->HasScrollbarYCurr = false; + } + table->HasScrollbarYCurr |= table->InnerWindow->ScrollbarY; + } + else + { + // For non-scrolling tables, WorkRect == OuterRect == InnerRect. + // But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable(). + table->WorkRect = table->OuterRect = table->InnerRect = outer_rect; + } + + // Push a standardized ID for both child-using and not-child-using tables + PushOverrideID(id); + if (instance_no > 0) + PushOverrideID(instance_id); // FIXME: Somehow this is not resolved by stack-tool, even tho GetIDWithSeed() submitted the symbol. + + // Backup a copy of host window members we will modify + ImGuiWindow* inner_window = table->InnerWindow; + table->HostIndentX = inner_window->DC.Indent.x; + table->HostClipRect = inner_window->ClipRect; + table->HostSkipItems = inner_window->SkipItems; + temp_data->HostBackupWorkRect = inner_window->WorkRect; + temp_data->HostBackupParentWorkRect = inner_window->ParentWorkRect; + temp_data->HostBackupColumnsOffset = outer_window->DC.ColumnsOffset; + temp_data->HostBackupPrevLineSize = inner_window->DC.PrevLineSize; + temp_data->HostBackupCurrLineSize = inner_window->DC.CurrLineSize; + temp_data->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos; + temp_data->HostBackupItemWidth = outer_window->DC.ItemWidth; + temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; + inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + + // Padding and Spacing + // - None ........Content..... Pad .....Content........ + // - PadOuter | Pad ..Content..... Pad .....Content.. Pad | + // - PadInner ........Content.. Pad | Pad ..Content........ + // - PadOuter+PadInner | Pad ..Content.. Pad | Pad ..Content.. Pad | + const bool pad_outer_x = (flags & ImGuiTableFlags_NoPadOuterX) ? false : (flags & ImGuiTableFlags_PadOuterX) ? true : (flags & ImGuiTableFlags_BordersOuterV) != 0; + const bool pad_inner_x = (flags & ImGuiTableFlags_NoPadInnerX) ? false : true; + const float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f; + const float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f; + const float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f; + table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border; + table->CellSpacingX2 = inner_spacing_explicit; + table->CellPaddingX = inner_padding_explicit; + table->CellPaddingY = g.Style.CellPadding.y; + + const float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + const float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f; + table->OuterPaddingX = (outer_padding_for_border + outer_padding_explicit) - table->CellPaddingX; + + table->CurrentColumn = -1; + table->CurrentRow = -1; + table->RowBgColorCounter = 0; + table->LastRowFlags = ImGuiTableRowFlags_None; + table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect; + table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width + table->InnerClipRect.ClipWithFull(table->HostClipRect); + table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y; + + table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow + table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow() + table->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any + table->FreezeColumnsRequest = table->FreezeColumnsCount = 0; + table->IsUnfrozenRows = true; + table->DeclColumnsCount = 0; + + // Using opaque colors facilitate overlapping lines of the grid, otherwise we'd need to improve TableDrawBorders() + table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong); + table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight); + + // Make table current + g.CurrentTable = table; + outer_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); + outer_window->DC.CurrentTableIdx = table_idx; + if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly. + inner_window->DC.CurrentTableIdx = table_idx; + + if ((table_last_flags & ImGuiTableFlags_Reorderable) && (flags & ImGuiTableFlags_Reorderable) == 0) + table->IsResetDisplayOrderRequest = true; + + // Mark as used to avoid GC + if (table_idx >= g.TablesLastTimeActive.Size) + g.TablesLastTimeActive.resize(table_idx + 1, -1.0f); + g.TablesLastTimeActive[table_idx] = (float)g.Time; + temp_data->LastTimeActive = (float)g.Time; + table->MemoryCompacted = false; + + // Setup memory buffer (clear data if columns count changed) + ImGuiTableColumn* old_columns_to_preserve = NULL; + void* old_columns_raw_data = NULL; + const int old_columns_count = table->Columns.size(); + if (old_columns_count != 0 && old_columns_count != columns_count) + { + // Attempt to preserve width on column count change (#4046) + old_columns_to_preserve = table->Columns.Data; + old_columns_raw_data = table->RawData; + table->RawData = NULL; + } + if (table->RawData == NULL) + { + TableBeginInitMemory(table, columns_count); + table->IsInitializing = table->IsSettingsRequestLoad = true; + } + if (table->IsResetAllRequest) + TableResetSettings(table); + if (table->IsInitializing) + { + // Initialize + table->SettingsOffset = -1; + table->IsSortSpecsDirty = true; + table->InstanceInteracted = -1; + table->ContextPopupColumn = -1; + table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; + table->AutoFitSingleColumn = -1; + table->HoveredColumnBody = table->HoveredColumnBorder = -1; + for (int n = 0; n < columns_count; n++) + { + ImGuiTableColumn* column = &table->Columns[n]; + if (old_columns_to_preserve && n < old_columns_count) + { + // FIXME: We don't attempt to preserve column order in this path. + *column = old_columns_to_preserve[n]; + } + else + { + float width_auto = column->WidthAuto; + *column = ImGuiTableColumn(); + column->WidthAuto = width_auto; + column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker + column->IsEnabled = column->IsUserEnabled = column->IsUserEnabledNextFrame = true; + } + column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n; + } + } + if (old_columns_raw_data) + IM_FREE(old_columns_raw_data); + + // Load settings + if (table->IsSettingsRequestLoad) + TableLoadSettings(table); + + // Handle DPI/font resize + // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. + // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. + // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. + // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. + const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? + if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) + { + const float scale_factor = new_ref_scale_unit / table->RefScale; + //IMGUI_DEBUG_PRINT("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor); + for (int n = 0; n < columns_count; n++) + table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; + } + table->RefScale = new_ref_scale_unit; + + // Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call.. + // This is not strictly necessary but will reduce cases were "out of table" output will be misleading to the user. + // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option. + inner_window->SkipItems = true; + + // Clear names + // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn() + if (table->ColumnsNames.Buf.Size > 0) + table->ColumnsNames.Buf.resize(0); + + // Apply queued resizing/reordering/hiding requests + TableBeginApplyRequests(table); + + return true; +} + +// For reference, the average total _allocation count_ for a table is: +// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables[]) +// + 1 (for table->RawData allocated below) +// + 1 (for table->ColumnsNames, if names are used) +// Shared allocations for the maximum number of simultaneously nested tables (generally a very small number) +// + 1 (for table->Splitter._Channels) +// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels) +// Where active_channels_count is variable but often == columns_count or == columns_count + 1, see TableSetupDrawChannels() for details. +// Unused channels don't perform their +2 allocations. +void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count) +{ + // Allocate single buffer for our arrays + const int columns_bit_array_size = (int)ImBitArrayGetStorageSizeInBytes(columns_count); + ImSpanAllocator<6> span_allocator; + span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn)); + span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx)); + span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4); + for (int n = 3; n < 6; n++) + span_allocator.Reserve(n, columns_bit_array_size); + table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); + memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes()); + span_allocator.SetArenaBasePtr(table->RawData); + span_allocator.GetSpan(0, &table->Columns); + span_allocator.GetSpan(1, &table->DisplayOrderToIndex); + span_allocator.GetSpan(2, &table->RowCellData); + table->EnabledMaskByDisplayOrder = (ImU32*)span_allocator.GetSpanPtrBegin(3); + table->EnabledMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(4); + table->VisibleMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(5); +} + +// Apply queued resizing/reordering/hiding requests +void ImGui::TableBeginApplyRequests(ImGuiTable* table) +{ + // Handle resizing request + // (We process this in the TableBegin() of the first instance of each table) + // FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling? + if (table->InstanceCurrent == 0) + { + if (table->ResizedColumn != -1 && table->ResizedColumnNextWidth != FLT_MAX) + TableSetColumnWidth(table->ResizedColumn, table->ResizedColumnNextWidth); + table->LastResizedColumn = table->ResizedColumn; + table->ResizedColumnNextWidth = FLT_MAX; + table->ResizedColumn = -1; + + // Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy. + // FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings. + if (table->AutoFitSingleColumn != -1) + { + TableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto); + table->AutoFitSingleColumn = -1; + } + } + + // Handle reordering request + // Note: we don't clear ReorderColumn after handling the request. + if (table->InstanceCurrent == 0) + { + if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1) + table->ReorderColumn = -1; + table->HeldHeaderColumn = -1; + if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0) + { + // We need to handle reordering across hidden columns. + // In the configuration below, moving C to the right of E will lead to: + // ... C [D] E ---> ... [D] E C (Column name/index) + // ... 2 3 4 ... 2 3 4 (Display order) + const int reorder_dir = table->ReorderColumnDir; + IM_ASSERT(reorder_dir == -1 || reorder_dir == +1); + IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable); + ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn]; + ImGuiTableColumn* dst_column = &table->Columns[(reorder_dir == -1) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn]; + IM_UNUSED(dst_column); + const int src_order = src_column->DisplayOrder; + const int dst_order = dst_column->DisplayOrder; + src_column->DisplayOrder = (ImGuiTableColumnIdx)dst_order; + for (int order_n = src_order + reorder_dir; order_n != dst_order + reorder_dir; order_n += reorder_dir) + table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder -= (ImGuiTableColumnIdx)reorder_dir; + IM_ASSERT(dst_column->DisplayOrder == dst_order - reorder_dir); + + // Display order is stored in both columns->IndexDisplayOrder and table->DisplayOrder[]. Rebuild later from the former. + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; + table->ReorderColumnDir = 0; + table->IsSettingsDirty = true; + } + } + + // Handle display order reset request + if (table->IsResetDisplayOrderRequest) + { + for (int n = 0; n < table->ColumnsCount; n++) + table->DisplayOrderToIndex[n] = table->Columns[n].DisplayOrder = (ImGuiTableColumnIdx)n; + table->IsResetDisplayOrderRequest = false; + table->IsSettingsDirty = true; + } +} + +// Adjust flags: default width mode + stretch columns are not allowed when auto extending +static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) +{ + ImGuiTableColumnFlags flags = flags_in; + + // Sizing Policy + if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) + { + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); + if (table_sizing_policy == ImGuiTableFlags_SizingFixedFit || table_sizing_policy == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableColumnFlags_WidthFixed; + else + flags |= ImGuiTableColumnFlags_WidthStretch; + } + else + { + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used. + } + + // Resize + if ((table->Flags & ImGuiTableFlags_Resizable) == 0) + flags |= ImGuiTableColumnFlags_NoResize; + + // Sorting + if ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending)) + flags |= ImGuiTableColumnFlags_NoSort; + + // Indentation + if ((flags & ImGuiTableColumnFlags_IndentMask_) == 0) + flags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable; + + // Alignment + //if ((flags & ImGuiTableColumnFlags_AlignMask_) == 0) + // flags |= ImGuiTableColumnFlags_AlignCenter; + //IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used. + + // Preserve status flags + column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_); + + // Build an ordered list of available sort directions + column->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0; + if (table->Flags & ImGuiTableFlags_Sortable) + { + int count = 0, mask = 0, list = 0; + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; } + column->SortDirectionsAvailList = (ImU8)list; + column->SortDirectionsAvailMask = (ImU8)mask; + column->SortDirectionsAvailCount = (ImU8)count; + ImGui::TableFixColumnSortDirection(table, column); + } +} + +// Layout columns for the frame. This is in essence the followup to BeginTable() and this is our largest function. +// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() and other TableSetupXXXXX() functions to be called first. +// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns. +// Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns? +void ImGui::TableUpdateLayout(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->IsLayoutLocked == false); + + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); + table->IsDefaultDisplayOrder = true; + table->ColumnsEnabledCount = 0; + ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount); + ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount); + table->LeftMostEnabledColumn = -1; + table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE + + // [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns. + // Process columns in their visible orders as we are building the Prev/Next indices. + int count_fixed = 0; // Number of columns that have fixed sizing policies + int count_stretch = 0; // Number of columns that have stretch sizing policies + int prev_visible_column_idx = -1; + bool has_auto_fit_request = false; + bool has_resizable = false; + float stretch_sum_width_auto = 0.0f; + float fixed_max_width_auto = 0.0f; + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + if (column_n != order_n) + table->IsDefaultDisplayOrder = false; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame. + // It would easily work without but we're not ready to guarantee it since e.g. names need resubmission anyway. + // We take a slight shortcut but in theory we could be calling TableSetupColumn() here with dummy values, it should yield the same effect. + if (table->DeclColumnsCount <= column_n) + { + TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); + column->NameOffset = -1; + column->UserID = 0; + column->InitStretchWeightOrWidth = -1.0f; + } + + // Update Enabled state, mark settings and sort specs dirty + if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) + column->IsUserEnabledNextFrame = true; + if (column->IsUserEnabled != column->IsUserEnabledNextFrame) + { + column->IsUserEnabled = column->IsUserEnabledNextFrame; + table->IsSettingsDirty = true; + } + column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0; + + if (column->SortOrder != -1 && !column->IsEnabled) + table->IsSortSpecsDirty = true; + if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) + table->IsSortSpecsDirty = true; + + // Auto-fit unsized columns + const bool start_auto_fit = (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? (column->WidthRequest < 0.0f) : (column->StretchWeight < 0.0f); + if (start_auto_fit) + column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames + + if (!column->IsEnabled) + { + column->IndexWithinEnabledSet = -1; + continue; + } + + // Mark as enabled and link to previous/next enabled column + column->PrevEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + column->NextEnabledColumn = -1; + if (prev_visible_column_idx != -1) + table->Columns[prev_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; + else + table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; + column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; + ImBitArraySetBit(table->EnabledMaskByIndex, column_n); + ImBitArraySetBit(table->EnabledMaskByDisplayOrder, column->DisplayOrder); + prev_visible_column_idx = column_n; + IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); + + // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) + // Combine width from regular rows + width from headers unless requested not to. + if (!column->IsPreserveWidthAuto) + column->WidthAuto = TableGetColumnWidthAuto(table, column); + + // Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto) + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column_is_resizable) + has_resizable = true; + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f && !column_is_resizable) + column->WidthAuto = column->InitStretchWeightOrWidth; + + if (column->AutoFitQueue != 0x00) + has_auto_fit_request = true; + if (column->Flags & ImGuiTableColumnFlags_WidthStretch) + { + stretch_sum_width_auto += column->WidthAuto; + count_stretch++; + } + else + { + fixed_max_width_auto = ImMax(fixed_max_width_auto, column->WidthAuto); + count_fixed++; + } + } + if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + table->IsSortSpecsDirty = true; + table->RightMostEnabledColumn = (ImGuiTableColumnIdx)prev_visible_column_idx; + IM_ASSERT(table->LeftMostEnabledColumn >= 0 && table->RightMostEnabledColumn >= 0); + + // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible + // to avoid the column fitting having to wait until the first visible frame of the child container (may or not be a good thing). + // FIXME-TABLE: for always auto-resizing columns may not want to do that all the time. + if (has_auto_fit_request && table->OuterWindow != table->InnerWindow) + table->InnerWindow->SkipItems = false; + if (has_auto_fit_request) + table->IsSettingsDirty = true; + + // [Part 3] Fix column flags and record a few extra information. + float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding. + float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns. + table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0; + if (column->Flags & ImGuiTableColumnFlags_WidthFixed) + { + // Apply same widths policy + float width_auto = column->WidthAuto; + if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable)) + width_auto = fixed_max_width_auto; + + // Apply automatic width + // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) + if (column->AutoFitQueue != 0x00) + column->WidthRequest = width_auto; + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && column->IsRequestOutput) + column->WidthRequest = width_auto; + + // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets + // (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very + // large height (= first frame scrollbar display very off + clipper would skip lots of items). + // This is merely making the side-effect less extreme, but doesn't properly fixes it. + // FIXME: Move this to ->WidthGiven to avoid temporary lossyless? + // FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller. + if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto) + column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale? + sum_width_requests += column->WidthRequest; + } + else + { + // Initialize stretch weight + if (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f || !column_is_resizable) + { + if (column->InitStretchWeightOrWidth > 0.0f) + column->StretchWeight = column->InitStretchWeightOrWidth; + else if (table_sizing_policy == ImGuiTableFlags_SizingStretchProp) + column->StretchWeight = (column->WidthAuto / stretch_sum_width_auto) * count_stretch; + else + column->StretchWeight = 1.0f; + } + + stretch_sum_weights += column->StretchWeight; + if (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder) + table->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n; + if (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder) + table->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n; + } + column->IsPreserveWidthAuto = false; + sum_width_requests += table->CellPaddingX * 2.0f; + } + table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed; + table->ColumnsStretchSumWeights = stretch_sum_weights; + + // [Part 4] Apply final widths based on requested widths + const ImRect work_rect = table->WorkRect; + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920) + const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed); + const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests; + float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; + table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest) + if (column->Flags & ImGuiTableColumnFlags_WidthStretch) + { + float weight_ratio = column->StretchWeight / stretch_sum_weights; + column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f); + width_remaining_for_stretched_columns -= column->WidthRequest; + } + + // [Resize Rule 1] The right-most Visible column is not resizable if there is at least one Stretch column + // See additional comments in TableSetColumnWidth(). + if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumn != -1) + column->Flags |= ImGuiTableColumnFlags_NoDirectResize_; + + // Assign final width, record width in case we will need to shrink + column->WidthGiven = ImFloor(ImMax(column->WidthRequest, table->MinColumnWidth)); + table->ColumnsGivenWidth += column->WidthGiven; + } + + // [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). + // Using right-to-left distribution (more likely to match resizing cursor). + if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) + for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + continue; + ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; + if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->WidthRequest += 1.0f; + column->WidthGiven += 1.0f; + width_remaining_for_stretched_columns -= 1.0f; + } + + // Determine if table is hovered which will be used to flag columns as hovered. + // - In principle we'd like to use the equivalent of IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + // but because our item is partially submitted at this point we use ItemHoverable() and a workaround (temporarily + // clear ActiveId, which is equivalent to the change provided by _AllowWhenBLockedByActiveItem). + // - This allows columns to be marked as hovered when e.g. clicking a button inside the column, or using drag and drop. + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + table_instance->HoveredRowLast = table_instance->HoveredRowNext; + table_instance->HoveredRowNext = -1; + table->HoveredColumnBody = -1; + table->HoveredColumnBorder = -1; + const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight)); + const ImGuiID backup_active_id = g.ActiveId; + g.ActiveId = 0; + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags_None); + g.ActiveId = backup_active_id; + + // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column + // Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping. + int visible_n = 0; + bool offset_x_frozen = (table->FreezeColumnsCount > 0); + float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; + ImRect host_clip_rect = table->InnerClipRect; + //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; + ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount); + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + + column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen + + if (offset_x_frozen && table->FreezeColumnsCount == visible_n) + { + offset_x += work_rect.Min.x - table->OuterRect.Min.x; + offset_x_frozen = false; + } + + // Clear status flags + column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; + + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + { + // Hidden column: clear a few fields and we are done with it for the remainder of the function. + // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. + column->MinX = column->MaxX = column->WorkMinX = column->ClipRect.Min.x = column->ClipRect.Max.x = offset_x; + column->WidthGiven = 0.0f; + column->ClipRect.Min.y = work_rect.Min.y; + column->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + column->IsVisibleX = column->IsVisibleY = column->IsRequestOutput = false; + column->IsSkipItems = true; + column->ItemWidth = 1.0f; + continue; + } + + // Detect hovered column + if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x) + table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; + + // Lock start position + column->MinX = offset_x; + + // Lock width based on start position and minimum/maximum width for this position + float max_width = TableGetMaxColumnWidth(table, column_n); + column->WidthGiven = ImMin(column->WidthGiven, max_width); + column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth)); + column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + + // Lock other positions + // - ClipRect.Min.x: Because merging draw commands doesn't compare min boundaries, we make ClipRect.Min.x match left bounds to be consistent regardless of merging. + // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column. + // - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow. + // - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter. + column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1; + column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max + column->ItemWidth = ImFloor(column->WidthGiven * 0.65f); + column->ClipRect.Min.x = column->MinX; + column->ClipRect.Min.y = work_rect.Min.y; + column->ClipRect.Max.x = column->MaxX; //column->WorkMaxX; + column->ClipRect.Max.y = FLT_MAX; + column->ClipRect.ClipWithFull(host_clip_rect); + + // Mark column as Clipped (not in sight) + // Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables. + // FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY. + // Taking advantage of LastOuterHeight would yield good results there... + // FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x, + // and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else). + // Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small. + column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x); + column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); + const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; + if (is_visible) + ImBitArraySetBit(table->VisibleMaskByIndex, column_n); + + // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. + column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; + + // Mark column as SkipItems (ignoring all items/layout) + column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; + if (column->IsSkipItems) + IM_ASSERT(!is_visible); + + // Update status flags + column->Flags |= ImGuiTableColumnFlags_IsEnabled; + if (is_visible) + column->Flags |= ImGuiTableColumnFlags_IsVisible; + if (column->SortOrder != -1) + column->Flags |= ImGuiTableColumnFlags_IsSorted; + if (table->HoveredColumnBody == column_n) + column->Flags |= ImGuiTableColumnFlags_IsHovered; + + // Alignment + // FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in + // many cases (to be able to honor this we might be able to store a log of cells width, per row, for + // visible rows, but nav/programmatic scroll would have visible artifacts.) + //if (column->Flags & ImGuiTableColumnFlags_AlignRight) + // column->WorkMinX = ImMax(column->WorkMinX, column->MaxX - column->ContentWidthRowsUnfrozen); + //else if (column->Flags & ImGuiTableColumnFlags_AlignCenter) + // column->WorkMinX = ImLerp(column->WorkMinX, ImMax(column->StartX, column->MaxX - column->ContentWidthRowsUnfrozen), 0.5f); + + // Reset content width variables + column->ContentMaxXFrozen = column->ContentMaxXUnfrozen = column->WorkMinX; + column->ContentMaxXHeadersUsed = column->ContentMaxXHeadersIdeal = column->WorkMinX; + + // Don't decrement auto-fit counters until container window got a chance to submit its items + if (table->HostSkipItems == false) + { + column->AutoFitQueue >>= 1; + column->CannotSkipItemsQueue >>= 1; + } + + if (visible_n < table->FreezeColumnsCount) + host_clip_rect.Min.x = ImClamp(column->MaxX + TABLE_BORDER_SIZE, host_clip_rect.Min.x, host_clip_rect.Max.x); + + offset_x += column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; + visible_n++; + } + + // [Part 7] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it) + // Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either + // because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu. + const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x); + if (is_hovering_table && table->HoveredColumnBody == -1) + { + if (g.IO.MousePos.x >= unused_x1) + table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount; + } + if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable)) + table->Flags &= ~ImGuiTableFlags_Resizable; + + // [Part 8] Lock actual OuterRect/WorkRect right-most position. + // This is done late to handle the case of fixed-columns tables not claiming more widths that they need. + // Because of this we are careful with uses of WorkRect and InnerClipRect before this point. + if (table->RightMostStretchedColumn != -1) + table->Flags &= ~ImGuiTableFlags_NoHostExtendX; + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + table->OuterRect.Max.x = table->WorkRect.Max.x = unused_x1; + table->InnerClipRect.Max.x = ImMin(table->InnerClipRect.Max.x, unused_x1); + } + table->InnerWindow->ParentWorkRect = table->WorkRect; + table->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f); + table->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f); + + // Setup window's WorkRect.Max.y for GetContentRegionAvail(). Other values will be updated in each TableBeginCell() call. + float window_content_max_y; + if (table->Flags & ImGuiTableFlags_NoHostExtendY) + window_content_max_y = table->OuterRect.Max.y; + else + window_content_max_y = ImMax(table->InnerWindow->ContentRegionRect.Max.y, (table->Flags & ImGuiTableFlags_ScrollY) ? 0.0f : table->OuterRect.Max.y); + table->InnerWindow->WorkRect.Max.y = ImClamp(window_content_max_y - g.Style.CellPadding.y, table->InnerWindow->WorkRect.Min.y, table->InnerWindow->WorkRect.Max.y); + + // [Part 9] Allocate draw channels and setup background cliprect + TableSetupDrawChannels(table); + + // [Part 10] Hit testing on borders + if (table->Flags & ImGuiTableFlags_Resizable) + TableUpdateBorders(table); + table_instance->LastFirstRowHeight = 0.0f; + table->IsLayoutLocked = true; + table->IsUsingHeaders = false; + + // [Part 11] Context menu + if (TableBeginContextMenuPopup(table)) + { + TableDrawContextMenu(table); + EndPopup(); + } + + // [Part 12] Sanitize and build sort specs before we have a chance to use them for display. + // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) + if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) + TableSortSpecsBuild(table); + + // [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) + if (table->FreezeColumnsRequest > 0) + table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; + if (table->FreezeRowsRequest > 0) + table->InnerWindow->DecoInnerSizeY1 = table_instance->LastFrozenHeight; + table_instance->LastFrozenHeight = 0.0f; + + // Initial state + ImGuiWindow* inner_window = table->InnerWindow; + if (table->Flags & ImGuiTableFlags_NoClip) + table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + else + inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); +} + +// Process hit-testing on resizing borders. Actual size change will be applied in EndTable() +// - Set table->HoveredColumnBorder with a short delay/timer to reduce visual feedback noise. +void ImGui::TableUpdateBorders(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(table->Flags & ImGuiTableFlags_Resizable); + + // At this point OuterRect height may be zero or under actual final height, so we rely on temporal coherency and + // use the final height from last frame. Because this is only affecting _interaction_ with columns, it is not + // really problematic (whereas the actual visual will be displayed in EndTable() and using the current frame height). + // Actual columns highlight/render will be performed in EndTable() and not be affected. + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + const float hit_half_width = TABLE_RESIZE_SEPARATOR_HALF_THICKNESS; + const float hit_y1 = table->OuterRect.Min.y; + const float hit_y2_body = ImMax(table->OuterRect.Max.y, hit_y1 + table_instance->LastOuterHeight); + const float hit_y2_head = hit_y1 + table_instance->LastFirstRowHeight; + + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + continue; + + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) + continue; + + // ImGuiTableFlags_NoBordersInBodyUntilResize will be honored in TableDrawBorders() + const float border_y2_hit = (table->Flags & ImGuiTableFlags_NoBordersInBody) ? hit_y2_head : hit_y2_body; + if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false) + continue; + + if (!column->IsVisibleX && table->LastResizedColumn != column_n) + continue; + + ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent); + ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, border_y2_hit); + ItemAdd(hit_rect, column_id, NULL, ImGuiItemFlags_NoNav); + //GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100)); + + bool hovered = false, held = false; + bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus); + if (pressed && IsMouseDoubleClicked(0)) + { + TableSetColumnWidthAutoSingle(table, column_n); + ClearActiveID(); + held = hovered = false; + } + if (held) + { + if (table->LastResizedColumn == -1) + table->ResizeLockMinContentsX2 = table->RightMostEnabledColumn != -1 ? table->Columns[table->RightMostEnabledColumn].MaxX : -FLT_MAX; + table->ResizedColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + } + if ((hovered && g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) || held) + { + table->HoveredColumnBorder = (ImGuiTableColumnIdx)column_n; + SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + } +} + +void ImGui::EndTable() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!"); + + // This assert would be very useful to catch a common error... unfortunately it would probably trigger in some + // cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border) + //IM_ASSERT(table->IsLayoutLocked && "Table unused: never called TableNextRow(), is that the intent?"); + + // If the user never got to call TableNextRow() or TableNextColumn(), we call layout ourselves to ensure all our + // code paths are consistent (instead of just hoping that TableBegin/TableEnd will work), get borders drawn, etc. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + const ImGuiTableFlags flags = table->Flags; + ImGuiWindow* inner_window = table->InnerWindow; + ImGuiWindow* outer_window = table->OuterWindow; + ImGuiTableTempData* temp_data = table->TempData; + IM_ASSERT(inner_window == g.CurrentWindow); + IM_ASSERT(outer_window == inner_window || outer_window == inner_window->ParentWindow); + + if (table->IsInsideRow) + TableEndRow(table); + + // Context menu in columns body + if (flags & ImGuiTableFlags_ContextMenuInBody) + if (table->HoveredColumnBody != -1 && !IsAnyItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) + TableOpenContextMenu((int)table->HoveredColumnBody); + + // Finalize table height + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize; + inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize; + inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos; + const float inner_content_max_y = table->RowPosY2; + IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y); + if (inner_window != outer_window) + inner_window->DC.CursorMaxPos.y = inner_content_max_y; + else if (!(flags & ImGuiTableFlags_NoHostExtendY)) + table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_content_max_y); // Patch OuterRect/InnerRect height + table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y); + table_instance->LastOuterHeight = table->OuterRect.GetHeight(); + + // Setup inner scrolling range + // FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y, + // but since the later is likely to be impossible to do we'd rather update both axises together. + if (table->Flags & ImGuiTableFlags_ScrollX) + { + const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; + float max_pos_x = table->InnerWindow->DC.CursorMaxPos.x; + if (table->RightMostEnabledColumn != -1) + max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border); + if (table->ResizedColumn != -1) + max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2); + table->InnerWindow->DC.CursorMaxPos.x = max_pos_x; + } + + // Pop clipping rect + if (!(flags & ImGuiTableFlags_NoClip)) + inner_window->DrawList->PopClipRect(); + inner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back(); + + // Draw borders + if ((flags & ImGuiTableFlags_Borders) != 0) + TableDrawBorders(table); + +#if 0 + // Strip out dummy channel draw calls + // We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out) + // Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway. + // Cons: making it harder for users watching metrics/debugger to spot the wasted vertices. + if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1) + { + ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel]; + dummy_channel->_CmdBuffer.resize(0); + dummy_channel->_IdxBuffer.resize(0); + } +#endif + + // Flatten channels and merge draw calls + ImDrawListSplitter* splitter = table->DrawSplitter; + splitter->SetCurrentChannel(inner_window->DrawList, 0); + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + TableMergeDrawChannels(table); + splitter->Merge(inner_window->DrawList); + + // Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable() + float auto_fit_width_for_fixed = 0.0f; + float auto_fit_width_for_stretched = 0.0f; + float auto_fit_width_for_stretched_min = 0.0f; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column); + if (column->Flags & ImGuiTableColumnFlags_WidthFixed) + auto_fit_width_for_fixed += column_width_request; + else + auto_fit_width_for_stretched += column_width_request; + if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) && (column->Flags & ImGuiTableColumnFlags_NoResize) != 0) + auto_fit_width_for_stretched_min = ImMax(auto_fit_width_for_stretched_min, column_width_request / (column->StretchWeight / table->ColumnsStretchSumWeights)); + } + const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); + table->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount + auto_fit_width_for_fixed + ImMax(auto_fit_width_for_stretched, auto_fit_width_for_stretched_min); + + // Update scroll + if ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window) + { + inner_window->Scroll.x = 0.0f; + } + else if (table->LastResizedColumn != -1 && table->ResizedColumn == -1 && inner_window->ScrollbarX && table->InstanceInteracted == table->InstanceCurrent) + { + // When releasing a column being resized, scroll to keep the resulting column in sight + const float neighbor_width_to_keep_visible = table->MinColumnWidth + table->CellPaddingX * 2.0f; + ImGuiTableColumn* column = &table->Columns[table->LastResizedColumn]; + if (column->MaxX < table->InnerClipRect.Min.x) + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - neighbor_width_to_keep_visible, 1.0f); + else if (column->MaxX > table->InnerClipRect.Max.x) + SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x + neighbor_width_to_keep_visible, 1.0f); + } + + // Apply resizing/dragging at the end of the frame + if (table->ResizedColumn != -1 && table->InstanceCurrent == table->InstanceInteracted) + { + ImGuiTableColumn* column = &table->Columns[table->ResizedColumn]; + const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS); + const float new_width = ImFloor(new_x2 - column->MinX - table->CellSpacingX1 - table->CellPaddingX * 2.0f); + table->ResizedColumnNextWidth = new_width; + } + + // Pop from id stack + IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table_instance->TableInstanceID, "Mismatching PushID/PopID!"); + IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= temp_data->HostBackupItemWidthStackSize, "Too many PopItemWidth!"); + if (table->InstanceCurrent > 0) + PopID(); + PopID(); + + // Restore window data that we modified + const ImVec2 backup_outer_max_pos = outer_window->DC.CursorMaxPos; + inner_window->WorkRect = temp_data->HostBackupWorkRect; + inner_window->ParentWorkRect = temp_data->HostBackupParentWorkRect; + inner_window->SkipItems = table->HostSkipItems; + outer_window->DC.CursorPos = table->OuterRect.Min; + outer_window->DC.ItemWidth = temp_data->HostBackupItemWidth; + outer_window->DC.ItemWidthStack.Size = temp_data->HostBackupItemWidthStackSize; + outer_window->DC.ColumnsOffset = temp_data->HostBackupColumnsOffset; + + // Layout in outer window + // (FIXME: To allow auto-fit and allow desirable effect of SameLine() we dissociate 'used' vs 'ideal' size by overriding + // CursorPosPrevLine and CursorMaxPos manually. That should be a more general layout feature, see same problem e.g. #3414) + if (inner_window != outer_window) + { + EndChild(); + } + else + { + ItemSize(table->OuterRect.GetSize()); + ItemAdd(table->OuterRect, 0); + } + + // Override declared contents width/height to enable auto-resize while not needlessly adding a scrollbar + if (table->Flags & ImGuiTableFlags_NoHostExtendX) + { + // FIXME-TABLE: Could we remove this section? + // ColumnsAutoFitWidth may be one frame ahead here since for Fixed+NoResize is calculated from latest contents + IM_ASSERT((table->Flags & ImGuiTableFlags_ScrollX) == 0); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth); + } + else if (temp_data->UserOuterSize.x <= 0.0f) + { + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.x : 0.0f; + outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth + decoration_size - temp_data->UserOuterSize.x); + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, table->OuterRect.Min.x + table->ColumnsAutoFitWidth)); + } + else + { + outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, table->OuterRect.Max.x); + } + if (temp_data->UserOuterSize.y <= 0.0f) + { + const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.y : 0.0f; + outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y); + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y)); + } + else + { + // OuterRect.Max.y may already have been pushed downward from the initial value (unless ImGuiTableFlags_NoHostExtendY is set) + outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, table->OuterRect.Max.y); + } + + // Save settings + if (table->IsSettingsDirty) + TableSaveSettings(table); + table->IsInitializing = false; + + // Clear or restore current table, if any + IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table); + IM_ASSERT(g.TablesTempDataStacked > 0); + temp_data = (--g.TablesTempDataStacked > 0) ? &g.TablesTempData[g.TablesTempDataStacked - 1] : NULL; + g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL; + if (g.CurrentTable) + { + g.CurrentTable->TempData = temp_data; + g.CurrentTable->DrawSplitter = &temp_data->DrawSplitter; + } + outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; + NavUpdateCurrentWindowIsScrollPushableX(); +} + +// See "COLUMN SIZING POLICIES" comments at the top of this file +// If (init_width_or_weight <= 0.0f) it is ignored +void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!"); + IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); + if (table->DeclColumnsCount >= table->ColumnsCount) + { + IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "Called TableSetupColumn() too many times!"); + return; + } + + ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; + table->DeclColumnsCount++; + + // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. + // Give a grace to users of ImGuiTableFlags_ScrollX. + if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) + IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); + + // When passing a width automatically enforce WidthFixed policy + // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) + if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f) + if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) + flags |= ImGuiTableColumnFlags_WidthFixed; + + TableSetupColumnFlags(table, column, flags); + column->UserID = user_id; + flags = column->Flags; + + // Initialize defaults + column->InitStretchWeightOrWidth = init_width_or_weight; + if (table->IsInitializing) + { + // Init width or weight + if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) + { + if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) + column->WidthRequest = init_width_or_weight; + if (flags & ImGuiTableColumnFlags_WidthStretch) + column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f; + + // Disable auto-fit if an explicit width/weight has been specified + if (init_width_or_weight > 0.0f) + column->AutoFitQueue = 0x00; + } + + // Init default visibility/sort state + if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) + column->IsUserEnabled = column->IsUserEnabledNextFrame = false; + if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) + { + column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + } + } + + // Store name (append with zero-terminator in contiguous buffer) + column->NameOffset = -1; + if (label != NULL && label[0] != 0) + { + column->NameOffset = (ImS16)table->ColumnsNames.size(); + table->ColumnsNames.append(label, label + strlen(label) + 1); + } +} + +// [Public] +void ImGui::TableSetupScrollFreeze(int columns, int rows) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); + IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); + IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit + + table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0; + table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0; + table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0; + table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0; + table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b + + // Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered. + // FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section) + for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++) + { + int order_n = table->DisplayOrderToIndex[column_n]; + if (order_n != column_n && order_n >= table->FreezeColumnsRequest) + { + ImSwap(table->Columns[table->DisplayOrderToIndex[order_n]].DisplayOrder, table->Columns[table->DisplayOrderToIndex[column_n]].DisplayOrder); + ImSwap(table->DisplayOrderToIndex[order_n], table->DisplayOrderToIndex[column_n]); + } + } +} + +//----------------------------------------------------------------------------- +// [SECTION] Tables: Simple accessors +//----------------------------------------------------------------------------- +// - TableGetColumnCount() +// - TableGetColumnName() +// - TableGetColumnName() [Internal] +// - TableSetColumnEnabled() +// - TableGetColumnFlags() +// - TableGetCellBgRect() [Internal] +// - TableGetColumnResizeID() [Internal] +// - TableGetHoveredColumn() [Internal] +// - TableGetHoveredRow() [Internal] +// - TableSetBgColor() +//----------------------------------------------------------------------------- + +int ImGui::TableGetColumnCount() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + return table ? table->ColumnsCount : 0; +} + +const char* ImGui::TableGetColumnName(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return NULL; + if (column_n < 0) + column_n = table->CurrentColumn; + return TableGetColumnName(table, column_n); +} + +const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) +{ + if (table->IsLayoutLocked == false && column_n >= table->DeclColumnsCount) + return ""; // NameOffset is invalid at this point + const ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->NameOffset == -1) + return ""; + return &table->ColumnsNames.Buf[column->NameOffset]; +} + +// Change user accessible enabled/disabled state of a column (often perceived as "showing/hiding" from users point of view) +// Note that end-user can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody) +// - Require table to have the ImGuiTableFlags_Hideable flag because we are manipulating user accessible state. +// - Request will be applied during next layout, which happens on the first call to TableNextRow() after BeginTable(). +// - For the getter you can test (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) != 0. +// - Alternative: the ImGuiTableColumnFlags_Disabled is an overriding/master disable flag which will also hide the column from context menu. +void ImGui::TableSetColumnEnabled(int column_n, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + if (!table) + return; + IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above + if (column_n < 0) + column_n = table->CurrentColumn; + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->IsUserEnabledNextFrame = enabled; +} + +// We allow querying for an extra column in order to poll the IsHovered state of the right-most section +ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return ImGuiTableColumnFlags_None; + if (column_n < 0) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) + return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None; + return table->Columns[column_n].Flags; +} + +// Return the cell rectangle based on currently known height. +// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. +// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height. +// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right +// columns report a small offset so their CellBgRect can extend up to the outer border. +// FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling. +ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float x1 = column->MinX; + float x2 = column->MaxX; + //if (column->PrevEnabledColumn == -1) + // x1 -= table->OuterPaddingX; + //if (column->NextEnabledColumn == -1) + // x2 += table->OuterPaddingX; + x1 = ImMax(x1, table->WorkRect.Min.x); + x2 = ImMin(x2, table->WorkRect.Max.x); + return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); +} + +// Return the resizing ID for the right-side of the given column. +ImGuiID ImGui::TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no) +{ + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiID instance_id = TableGetInstanceID(table, instance_no); + return instance_id + 1 + column_n; // FIXME: #6140: still not ideal +} + +// Return -1 when table is not hovered. return columns_count if hovering the unused space at the right of the right-most visible column. +int ImGui::TableGetHoveredColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return -1; + return (int)table->HoveredColumnBody; +} + +// Return -1 when table is not hovered. Return maxrow+1 if in table but below last submitted row. +// *IMPORTANT* Unlike TableGetHoveredColumn(), this has a one frame latency in updating the value. +// This difference with is the reason why this is not public yet. +int ImGui::TableGetHoveredRow() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return -1; + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + return (int)table_instance->HoveredRowLast; +} + +void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(target != ImGuiTableBgTarget_None); + + if (color == IM_COL32_DISABLE) + color = 0; + + // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time. + switch (target) + { + case ImGuiTableBgTarget_CellBg: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + if (column_n == -1) + column_n = table->CurrentColumn; + if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) + return; + if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) + table->RowCellDataCurrent++; + ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent]; + cell_data->BgColor = color; + cell_data->Column = (ImGuiTableColumnIdx)column_n; + break; + } + case ImGuiTableBgTarget_RowBg0: + case ImGuiTableBgTarget_RowBg1: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + IM_ASSERT(column_n == -1); + int bg_idx = (target == ImGuiTableBgTarget_RowBg1) ? 1 : 0; + table->RowBgColor[bg_idx] = color; + break; + } + default: + IM_ASSERT(0); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Row changes +//------------------------------------------------------------------------- +// - TableGetRowIndex() +// - TableNextRow() +// - TableBeginRow() [Internal] +// - TableEndRow() [Internal] +//------------------------------------------------------------------------- + +// [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows +int ImGui::TableGetRowIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentRow; +} + +// [Public] Starts into the first cell of a new row +void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + if (table->IsInsideRow) + TableEndRow(table); + + table->LastRowFlags = table->RowFlags; + table->RowFlags = row_flags; + table->RowMinHeight = row_min_height; + TableBeginRow(table); + + // We honor min_row_height requested by user, but cannot guarantee per-row maximum height, + // because that would essentially require a unique clipping rectangle per-cell. + table->RowPosY2 += table->CellPaddingY * 2.0f; + table->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height); + + // Disable output until user calls TableNextColumn() + table->InnerWindow->SkipItems = true; +} + +// [Internal] Called by TableNextRow() +void ImGui::TableBeginRow(ImGuiTable* table) +{ + ImGuiWindow* window = table->InnerWindow; + IM_ASSERT(!table->IsInsideRow); + + // New row + table->CurrentRow++; + table->CurrentColumn = -1; + table->RowBgColor[0] = table->RowBgColor[1] = IM_COL32_DISABLE; + table->RowCellDataCurrent = -1; + table->IsInsideRow = true; + + // Begin frozen rows + float next_y1 = table->RowPosY2; + if (table->CurrentRow == 0 && table->FreezeRowsCount > 0) + next_y1 = window->DC.CursorPos.y = table->OuterRect.Min.y; + + table->RowPosY1 = table->RowPosY2 = next_y1; + table->RowTextBaseline = 0.0f; + table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent + window->DC.PrevLineTextBaseOffset = 0.0f; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.IsSameLine = window->DC.IsSetPos = false; + window->DC.CursorMaxPos.y = next_y1; + + // Making the header BG color non-transparent will allow us to overlay it multiple times when handling smooth dragging. + if (table->RowFlags & ImGuiTableRowFlags_Headers) + { + TableSetBgColor(ImGuiTableBgTarget_RowBg0, GetColorU32(ImGuiCol_TableHeaderBg)); + if (table->CurrentRow == 0) + table->IsUsingHeaders = true; + } +} + +// [Internal] Called by TableNextRow() +void ImGui::TableEndRow(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window == table->InnerWindow); + IM_ASSERT(table->IsInsideRow); + + if (table->CurrentColumn != -1) + TableEndCell(table); + + // Logging + if (g.LogEnabled) + LogRenderedText(NULL, "|"); + + // Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. However it is + // likely that the next call to TableBeginCell() will reposition the cursor to take account of vertical padding. + window->DC.CursorPos.y = table->RowPosY2; + + // Row background fill + const float bg_y1 = table->RowPosY1; + const float bg_y2 = table->RowPosY2; + const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount); + const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest); + if (table->CurrentRow == 0) + TableGetInstanceData(table, table->InstanceCurrent)->LastFirstRowHeight = bg_y2 - bg_y1; + + const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y); + if (is_visible) + { + // Update data for TableGetHoveredRow() + if (table->HoveredColumnBody != -1 && g.IO.MousePos.y >= bg_y1 && g.IO.MousePos.y < bg_y2) + TableGetInstanceData(table, table->InstanceCurrent)->HoveredRowNext = table->CurrentRow; + + // Decide of background color for the row + ImU32 bg_col0 = 0; + ImU32 bg_col1 = 0; + if (table->RowBgColor[0] != IM_COL32_DISABLE) + bg_col0 = table->RowBgColor[0]; + else if (table->Flags & ImGuiTableFlags_RowBg) + bg_col0 = GetColorU32((table->RowBgColorCounter & 1) ? ImGuiCol_TableRowBgAlt : ImGuiCol_TableRowBg); + if (table->RowBgColor[1] != IM_COL32_DISABLE) + bg_col1 = table->RowBgColor[1]; + + // Decide of top border color + ImU32 border_col = 0; + const float border_size = TABLE_BORDER_SIZE; + if (table->CurrentRow > 0 || table->InnerWindow == table->OuterWindow) + if (table->Flags & ImGuiTableFlags_BordersInnerH) + border_col = (table->LastRowFlags & ImGuiTableRowFlags_Headers) ? table->BorderColorStrong : table->BorderColorLight; + + const bool draw_cell_bg_color = table->RowCellDataCurrent >= 0; + const bool draw_strong_bottom_border = unfreeze_rows_actual; + if ((bg_col0 | bg_col1 | border_col) != 0 || draw_strong_bottom_border || draw_cell_bg_color) + { + // In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is + // always followed by a change of clipping rectangle we perform the smallest overwrite possible here. + if ((table->Flags & ImGuiTableFlags_NoClip) == 0) + window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4(); + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0); + } + + // Draw row background + // We soft/cpu clip this so all backgrounds and borders can share the same clipping rectangle + if (bg_col0 || bg_col1) + { + ImRect row_rect(table->WorkRect.Min.x, bg_y1, table->WorkRect.Max.x, bg_y2); + row_rect.ClipWith(table->BgClipRect); + if (bg_col0 != 0 && row_rect.Min.y < row_rect.Max.y) + window->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col0); + if (bg_col1 != 0 && row_rect.Min.y < row_rect.Max.y) + window->DrawList->AddRectFilled(row_rect.Min, row_rect.Max, bg_col1); + } + + // Draw cell background color + if (draw_cell_bg_color) + { + ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent]; + for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++) + { + // As we render the BG here we need to clip things (for layout we would not) + // FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling. + const ImGuiTableColumn* column = &table->Columns[cell_data->Column]; + ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column); + cell_bg_rect.ClipWith(table->BgClipRect); + cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling + cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX); + window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor); + } + } + + // Draw top border + if (border_col && bg_y1 >= table->BgClipRect.Min.y && bg_y1 < table->BgClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y1), ImVec2(table->BorderX2, bg_y1), border_col, border_size); + + // Draw bottom border at the row unfreezing mark (always strong) + if (draw_strong_bottom_border && bg_y2 >= table->BgClipRect.Min.y && bg_y2 < table->BgClipRect.Max.y) + window->DrawList->AddLine(ImVec2(table->BorderX1, bg_y2), ImVec2(table->BorderX2, bg_y2), table->BorderColorStrong, border_size); + } + + // End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle) + // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and + // get the new cursor position. + if (unfreeze_rows_request) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; + if (unfreeze_rows_actual) + { + IM_ASSERT(table->IsUnfrozenRows == false); + const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); + table->IsUnfrozenRows = true; + TableGetInstanceData(table, table->InstanceCurrent)->LastFrozenHeight = y0 - table->OuterRect.Min.y; + + // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect + table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); + table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; + table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; + IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); + + float row_height = table->RowPosY2 - table->RowPosY1; + table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; + table->RowPosY1 = table->RowPosY2 - row_height; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->DrawChannelCurrent = column->DrawChannelUnfrozen; + column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; + } + + // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y + SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + } + + if (!(table->RowFlags & ImGuiTableRowFlags_Headers)) + table->RowBgColorCounter++; + table->IsInsideRow = false; +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns changes +//------------------------------------------------------------------------- +// - TableGetColumnIndex() +// - TableSetColumnIndex() +// - TableNextColumn() +// - TableBeginCell() [Internal] +// - TableEndCell() [Internal] +//------------------------------------------------------------------------- + +int ImGui::TableGetColumnIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentColumn; +} + +// [Public] Append into a specific column +bool ImGui::TableSetColumnIndex(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->CurrentColumn != column_n) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + IM_ASSERT(column_n >= 0 && table->ColumnsCount); + TableBeginCell(table, column_n); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + return table->Columns[column_n].IsRequestOutput; +} + +// [Public] Append into the next column, wrap and create a new row when already on last column +bool ImGui::TableNextColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + TableBeginCell(table, table->CurrentColumn + 1); + } + else + { + TableNextRow(); + TableBeginCell(table, 0); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + return table->Columns[table->CurrentColumn].IsRequestOutput; +} + + +// [Internal] Called by TableSetColumnIndex()/TableNextColumn() +// This is called very frequently, so we need to be mindful of unnecessary overhead. +// FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns. +void ImGui::TableBeginCell(ImGuiTable* table, int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTableColumn* column = &table->Columns[column_n]; + ImGuiWindow* window = table->InnerWindow; + table->CurrentColumn = column_n; + + // Start position is roughly ~~ CellRect.Min + CellPadding + Indent + float start_x = column->WorkMinX; + if (column->Flags & ImGuiTableColumnFlags_IndentEnable) + start_x += table->RowIndentOffsetX; // ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row. + + window->DC.CursorPos.x = start_x; + window->DC.CursorPos.y = table->RowPosY1 + table->CellPaddingY; + window->DC.CursorMaxPos.x = window->DC.CursorPos.x; + window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT + window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; + window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; + + // Note how WorkRect.Max.y is only set once during layout + window->WorkRect.Min.y = window->DC.CursorPos.y; + window->WorkRect.Min.x = column->WorkMinX; + window->WorkRect.Max.x = column->WorkMaxX; + window->DC.ItemWidth = column->ItemWidth; + + window->SkipItems = column->IsSkipItems; + if (column->IsSkipItems) + { + g.LastItemData.ID = 0; + g.LastItemData.StatusFlags = 0; + } + + if (table->Flags & ImGuiTableFlags_NoClip) + { + // FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. + table->DrawSplitter->SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP); + } + else + { + // FIXME-TABLE: Could avoid this if draw channel is dummy channel? + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); + } + + // Logging + if (g.LogEnabled && !column->IsSkipItems) + { + LogRenderedText(&window->DC.CursorPos, "|"); + g.LogLinePosY = FLT_MAX; + } +} + +// [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() +void ImGui::TableEndCell(ImGuiTable* table) +{ + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + ImGuiWindow* window = table->InnerWindow; + + if (window->DC.IsSetPos) + ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + + // Report maximum position so we can infer content size per column. + float* p_max_pos_x; + if (table->RowFlags & ImGuiTableRowFlags_Headers) + p_max_pos_x = &column->ContentMaxXHeadersUsed; // Useful in case user submit contents in header row that is not a TableHeader() call + else + p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen; + *p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x); + if (column->IsEnabled) + table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); + column->ItemWidth = window->DC.ItemWidth; + + // Propagate text baseline for the entire row + // FIXME-TABLE: Here we propagate text baseline from the last line of the cell.. instead of the first one. + table->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns width management +//------------------------------------------------------------------------- +// - TableGetMaxColumnWidth() [Internal] +// - TableGetColumnWidthAuto() [Internal] +// - TableSetColumnWidth() +// - TableSetColumnWidthAutoSingle() [Internal] +// - TableSetColumnWidthAutoAll() [Internal] +// - TableUpdateColumnsWeightFromWidth() [Internal] +//------------------------------------------------------------------------- + +// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis. +float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float max_width = FLT_MAX; + const float min_column_distance = table->MinColumnWidth + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2; + if (table->Flags & ImGuiTableFlags_ScrollX) + { + // Frozen columns can't reach beyond visible width else scrolling will naturally break. + // (we use DisplayOrder as within a set of multiple frozen column reordering is possible) + if (column->DisplayOrder < table->FreezeColumnsRequest) + { + max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX; + max_width = max_width - table->OuterPaddingX - table->CellPaddingX - table->CellSpacingX2; + } + } + else if ((table->Flags & ImGuiTableFlags_NoKeepColumnsVisible) == 0) + { + // If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make + // sure they are all visible. Because of this we also know that all of the columns will always fit in + // table->WorkRect and therefore in table->InnerRect (because ScrollX is off) + // FIXME-TABLE: This is solved incorrectly but also quite a difficult problem to fix as we also want ClipRect width to match. + // See "table_width_distrib" and "table_width_keep_visible" tests + max_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - column->MinX; + //max_width -= table->CellSpacingX1; + max_width -= table->CellSpacingX2; + max_width -= table->CellPaddingX * 2.0f; + max_width -= table->OuterPaddingX; + } + return max_width; +} + +// Note this is meant to be stored in column->WidthAuto, please generally use the WidthAuto field +float ImGui::TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column) +{ + const float content_width_body = ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX; + const float content_width_headers = column->ContentMaxXHeadersIdeal - column->WorkMinX; + float width_auto = content_width_body; + if (!(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth)) + width_auto = ImMax(width_auto, content_width_headers); + + // Non-resizable fixed columns preserve their requested width + if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f) + if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize)) + width_auto = column->InitStretchWeightOrWidth; + + return ImMax(width_auto, table->MinColumnWidth); +} + +// 'width' = inner column width, without padding +void ImGui::TableSetColumnWidth(int column_n, float width) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && table->IsLayoutLocked == false); + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column_0 = &table->Columns[column_n]; + float column_0_width = width; + + // Apply constraints early + // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) + IM_ASSERT(table->MinColumnWidth > 0.0f); + const float min_width = table->MinColumnWidth; + const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n)); + column_0_width = ImClamp(column_0_width, min_width, max_width); + if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) + return; + + //IMGUI_DEBUG_PRINT("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width); + ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL; + + // In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns. + // - All fixed: easy. + // - All stretch: easy. + // - One or more fixed + one stretch: easy. + // - One or more fixed + more than one stretch: tricky. + // Qt when manual resize is enabled only supports a single _trailing_ stretch column, we support more cases here. + + // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1. + // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user. + // Scenarios: + // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset. + // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered. + // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size. + // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 W3 resize from W1| or W2| --> ok + // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 F3 resize from W1| or W2| --> ok + // - W1 F2 W3 resize from W1| or F2| --> ok + // - F1 W2 F3 resize from W2| --> ok + // - F1 W3 F2 resize from W3| --> ok + // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. + // - W1 F2 F3 resize from F2| --> ok + // All resizes from a Wx columns are locking other columns. + + // Possible improvements: + // - W1 W2 W3 resize W1| --> to not be stuck, both W2 and W3 would stretch down. Seems possible to fix. Would be most beneficial to simplify resize of all-weighted columns. + // - W3 F1 F2 resize W3| --> to not be stuck past F1|, both F1 and F2 would need to stretch down, which would be lossy or ambiguous. Seems hard to fix. + + // [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout(). + + // If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize. + // This is the preferred resize path + if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed) + if (!column_1 || table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder >= column_0->DisplayOrder) + { + column_0->WidthRequest = column_0_width; + table->IsSettingsDirty = true; + return; + } + + // We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column) + if (column_1 == NULL) + column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL; + if (column_1 == NULL) + return; + + // Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column. + // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) + float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); + column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; + IM_ASSERT(column_0_width > 0.0f && column_1_width > 0.0f); + column_0->WidthRequest = column_0_width; + column_1->WidthRequest = column_1_width; + if ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch) + TableUpdateColumnsWeightFromWidth(table); + table->IsSettingsDirty = true; +} + +// Disable clipping then auto-fit, will take 2 frames +// (we don't take a shortcut for unclipped columns to reduce inconsistencies when e.g. resizing multiple columns) +void ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n) +{ + // Single auto width uses auto-fit + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled) + return; + column->CannotSkipItemsQueue = (1 << 0); + table->AutoFitSingleColumn = (ImGuiTableColumnIdx)column_n; +} + +void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table) +{ + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Cannot reset weight of hidden stretch column + continue; + column->CannotSkipItemsQueue = (1 << 0); + column->AutoFitQueue = (1 << 1); + } +} + +void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table) +{ + IM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1); + + // Measure existing quantities + float visible_weight = 0.0f; + float visible_width = 0.0f; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + IM_ASSERT(column->StretchWeight > 0.0f); + visible_weight += column->StretchWeight; + visible_width += column->WidthRequest; + } + IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); + + // Apply new weights + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->StretchWeight = (column->WidthRequest / visible_width) * visible_weight; + IM_ASSERT(column->StretchWeight > 0.0f); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Drawing +//------------------------------------------------------------------------- +// - TablePushBackgroundChannel() [Internal] +// - TablePopBackgroundChannel() [Internal] +// - TableSetupDrawChannels() [Internal] +// - TableMergeDrawChannels() [Internal] +// - TableDrawBorders() [Internal] +//------------------------------------------------------------------------- + +// Bg2 is used by Selectable (and possibly other widgets) to render to the background. +// Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect. +void ImGui::TablePushBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + table->HostBackupInnerClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent); +} + +void ImGui::TablePopBackgroundChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiTable* table = g.CurrentTable; + ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); +} + +// Allocate draw channels. Called by TableUpdateLayout() +// - We allocate them following storage order instead of display order so reordering columns won't needlessly +// increase overall dormant memory cost. +// - We isolate headers draw commands in their own channels instead of just altering clip rects. +// This is in order to facilitate merging of draw commands. +// - After crossing FreezeRowsCount, all columns see their current draw channel changed to a second set of channels. +// - We only use the dummy draw channel so we can push a null clipping rectangle into it without affecting other +// channels, while simplifying per-row/per-cell overhead. It will be empty and discarded when merged. +// - We allocate 1 or 2 background draw channels. This is because we know TablePushBackgroundChannel() is only used for +// horizontal spanning. If we allowed vertical spanning we'd need one background draw channel per merge group (1-4). +// Draw channel allocation (before merging): +// - NoClip --> 2+D+1 channels: bg0/1 + bg2 + foreground (same clip rect == always 1 draw call) +// - Clip --> 2+D+N channels +// - FreezeRows --> 2+D+N*2 (unless scrolling value is zero) +// - FreezeRows || FreezeColunns --> 3+D+N*2 (unless scrolling value is zero) +// Where D is 1 if any column is clipped or hidden (dummy channel) otherwise 0. +void ImGui::TableSetupDrawChannels(ImGuiTable* table) +{ + const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1; + const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount; + const int channels_for_bg = 1 + 1 * freeze_row_multiplier; + const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || (memcmp(table->VisibleMaskByIndex, table->EnabledMaskByIndex, ImBitArrayGetStorageSizeInBytes(table->ColumnsCount)) != 0)) ? +1 : 0; + const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; + table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total); + table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1); + table->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN; + table->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN); + + int draw_channel_current = 2; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->IsVisibleX && column->IsVisibleY) + { + column->DrawChannelFrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current); + column->DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)(draw_channel_current + (table->FreezeRowsCount > 0 ? channels_for_row + 1 : 0)); + if (!(table->Flags & ImGuiTableFlags_NoClip)) + draw_channel_current++; + } + else + { + column->DrawChannelFrozen = column->DrawChannelUnfrozen = table->DummyDrawChannel; + } + column->DrawChannelCurrent = column->DrawChannelFrozen; + } + + // Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default. + // All our cell highlight are manually clipped with BgClipRect. When unfreezing it will be made smaller to fit scrolling rect. + // (This technically isn't part of setting up draw channels, but is reasonably related to be done here) + table->BgClipRect = table->InnerClipRect; + table->Bg0ClipRectForDrawCmd = table->OuterWindow->ClipRect; + table->Bg2ClipRectForDrawCmd = table->HostClipRect; + IM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y); +} + +// This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable(). +// For simplicity we call it TableMergeDrawChannels() but in fact it only reorder channels + overwrite ClipRect, +// actual merging is done by table->DrawSplitter.Merge() which is called right after TableMergeDrawChannels(). +// +// Columns where the contents didn't stray off their local clip rectangle can be merged. To achieve +// this we merge their clip rect and make them contiguous in the channel list, so they can be merged +// by the call to DrawSplitter.Merge() following to the call to this function. +// We reorder draw commands by arranging them into a maximum of 4 distinct groups: +// +// 1 group: 2 groups: 2 groups: 4 groups: +// [ 0. ] no freeze [ 0. ] row freeze [ 01 ] col freeze [ 01 ] row+col freeze +// [ .. ] or no scroll [ 2. ] and v-scroll [ .. ] and h-scroll [ 23 ] and v+h-scroll +// +// Each column itself can use 1 channel (row freeze disabled) or 2 channels (row freeze enabled). +// When the contents of a column didn't stray off its limit, we move its channels into the corresponding group +// based on its position (within frozen rows/columns groups or not). +// At the end of the operation our 1-4 groups will each have a ImDrawCmd using the same ClipRect. +// This function assume that each column are pointing to a distinct draw channel, +// otherwise merge_group->ChannelsCount will not match set bit count of merge_group->ChannelsMask. +// +// Column channels will not be merged into one of the 1-4 groups in the following cases: +// - The contents stray off its clipping rectangle (we only compare the MaxX value, not the MinX value). +// Direct ImDrawList calls won't be taken into account by default, if you use them make sure the ImGui:: bounds +// matches, by e.g. calling SetCursorScreenPos(). +// - The channel uses more than one draw command itself. We drop all our attempt at merging stuff here.. +// we could do better but it's going to be rare and probably not worth the hassle. +// Columns for which the draw channel(s) haven't been merged with other will use their own ImDrawCmd. +// +// This function is particularly tricky to understand.. take a breath. +void ImGui::TableMergeDrawChannels(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImDrawListSplitter* splitter = table->DrawSplitter; + const bool has_freeze_v = (table->FreezeRowsCount > 0); + const bool has_freeze_h = (table->FreezeColumnsCount > 0); + IM_ASSERT(splitter->_Current == 0); + + // Track which groups we are going to attempt to merge, and which channels goes into each group. + struct MergeGroup + { + ImRect ClipRect; + int ChannelsCount = 0; + ImBitArrayPtr ChannelsMask = NULL; + }; + int merge_group_mask = 0x00; + MergeGroup merge_groups[4]; + + // Use a reusable temp buffer for the merge masks as they are dynamically sized. + const int max_draw_channels = (4 + table->ColumnsCount * 2); + const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels); + g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5); + memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5); + for (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++) + merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n)); + ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4)); + + // 1. Scan channels and take note of those which can be merged + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n)) + continue; + ImGuiTableColumn* column = &table->Columns[column_n]; + + const int merge_group_sub_count = has_freeze_v ? 2 : 1; + for (int merge_group_sub_n = 0; merge_group_sub_n < merge_group_sub_count; merge_group_sub_n++) + { + const int channel_no = (merge_group_sub_n == 0) ? column->DrawChannelFrozen : column->DrawChannelUnfrozen; + + // Don't attempt to merge if there are multiple draw calls within the column + ImDrawChannel* src_channel = &splitter->_Channels[channel_no]; + if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd() + src_channel->_CmdBuffer.pop_back(); + if (src_channel->_CmdBuffer.Size != 1) + continue; + + // Find out the width of this merge group and check if it will fit in our column + // (note that we assume that rendering didn't stray on the left direction. we should need a CursorMinPos to detect it) + if (!(column->Flags & ImGuiTableColumnFlags_NoClip)) + { + float content_max_x; + if (!has_freeze_v) + content_max_x = ImMax(column->ContentMaxXUnfrozen, column->ContentMaxXHeadersUsed); // No row freeze + else if (merge_group_sub_n == 0) + content_max_x = ImMax(column->ContentMaxXFrozen, column->ContentMaxXHeadersUsed); // Row freeze: use width before freeze + else + content_max_x = column->ContentMaxXUnfrozen; // Row freeze: use width after freeze + if (content_max_x > column->ClipRect.Max.x) + continue; + } + + const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2); + IM_ASSERT(channel_no < max_draw_channels); + MergeGroup* merge_group = &merge_groups[merge_group_n]; + if (merge_group->ChannelsCount == 0) + merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); + ImBitArraySetBit(merge_group->ChannelsMask, channel_no); + merge_group->ChannelsCount++; + merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect); + merge_group_mask |= (1 << merge_group_n); + } + + // Invalidate current draw channel + // (we don't clear DrawChannelFrozen/DrawChannelUnfrozen solely to facilitate debugging/later inspection of data) + column->DrawChannelCurrent = (ImGuiTableDrawChannelIdx)-1; + } + + // [DEBUG] Display merge groups +#if 0 + if (g.IO.KeyShift) + for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { + MergeGroup* merge_group = &merge_groups[merge_group_n]; + if (merge_group->ChannelsCount == 0) + continue; + char buf[32]; + ImFormatString(buf, 32, "MG%d:%d", merge_group_n, merge_group->ChannelsCount); + ImVec2 text_pos = merge_group->ClipRect.Min + ImVec2(4, 4); + ImVec2 text_size = CalcTextSize(buf, NULL); + GetForegroundDrawList()->AddRectFilled(text_pos, text_pos + text_size, IM_COL32(0, 0, 0, 255)); + GetForegroundDrawList()->AddText(text_pos, IM_COL32(255, 255, 0, 255), buf, NULL); + GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 255, 0, 255)); + } +#endif + + // 2. Rewrite channel list in our preferred order + if (merge_group_mask != 0) + { + // We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels(). + const int LEADING_DRAW_CHANNELS = 2; + g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized + ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; + ImBitArraySetBitRange(remaining_mask, LEADING_DRAW_CHANNELS, splitter->_Count); + ImBitArrayClearBit(remaining_mask, table->Bg2DrawChannelUnfrozen); + IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); + int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS); + //ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect; + ImRect host_rect = table->HostClipRect; + for (int merge_group_n = 0; merge_group_n < IM_ARRAYSIZE(merge_groups); merge_group_n++) + { + if (int merge_channels_count = merge_groups[merge_group_n].ChannelsCount) + { + MergeGroup* merge_group = &merge_groups[merge_group_n]; + ImRect merge_clip_rect = merge_group->ClipRect; + + // Extend outer-most clip limits to match those of host, so draw calls can be merged even if + // outer-most columns have some outer padding offsetting them from their parent ClipRect. + // The principal cases this is dealing with are: + // - On a same-window table (not scrolling = single group), all fitting columns ClipRect -> will extend and match host ClipRect -> will merge + // - Columns can use padding and have left-most ClipRect.Min.x and right-most ClipRect.Max.x != from host ClipRect -> will extend and match host ClipRect -> will merge + // FIXME-TABLE FIXME-WORKRECT: We are wasting a merge opportunity on tables without scrolling if column doesn't fit + // within host clip rect, solely because of the half-padding difference between window->WorkRect and window->InnerClipRect. + if ((merge_group_n & 1) == 0 || !has_freeze_h) + merge_clip_rect.Min.x = ImMin(merge_clip_rect.Min.x, host_rect.Min.x); + if ((merge_group_n & 2) == 0 || !has_freeze_v) + merge_clip_rect.Min.y = ImMin(merge_clip_rect.Min.y, host_rect.Min.y); + if ((merge_group_n & 1) != 0) + merge_clip_rect.Max.x = ImMax(merge_clip_rect.Max.x, host_rect.Max.x); + if ((merge_group_n & 2) != 0 && (table->Flags & ImGuiTableFlags_NoHostExtendY) == 0) + merge_clip_rect.Max.y = ImMax(merge_clip_rect.Max.y, host_rect.Max.y); + //GetForegroundDrawList()->AddRect(merge_group->ClipRect.Min, merge_group->ClipRect.Max, IM_COL32(255, 0, 0, 200), 0.0f, 0, 1.0f); // [DEBUG] + //GetForegroundDrawList()->AddLine(merge_group->ClipRect.Min, merge_clip_rect.Min, IM_COL32(255, 100, 0, 200)); + //GetForegroundDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); + remaining_count -= merge_group->ChannelsCount; + for (int n = 0; n < (size_for_masks_bitarrays_one >> 2); n++) + remaining_mask[n] &= ~merge_group->ChannelsMask[n]; + for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) + { + // Copy + overwrite new clip rect + if (!IM_BITARRAY_TESTBIT(merge_group->ChannelsMask, n)) + continue; + IM_BITARRAY_CLEARBIT(merge_group->ChannelsMask, n); + merge_channels_count--; + + ImDrawChannel* channel = &splitter->_Channels[n]; + IM_ASSERT(channel->_CmdBuffer.Size == 1 && merge_clip_rect.Contains(ImRect(channel->_CmdBuffer[0].ClipRect))); + channel->_CmdBuffer[0].ClipRect = merge_clip_rect.ToVec4(); + memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); + } + } + + // Make sure Bg2DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0/Bg1 and Bg2 frozen are fixed to 0 and 1) + if (merge_group_n == 1 && has_freeze_v) + memcpy(dst_tmp++, &splitter->_Channels[table->Bg2DrawChannelUnfrozen], sizeof(ImDrawChannel)); + } + + // Append unmergeable channels that we didn't reorder at the end of the list + for (int n = 0; n < splitter->_Count && remaining_count != 0; n++) + { + if (!IM_BITARRAY_TESTBIT(remaining_mask, n)) + continue; + ImDrawChannel* channel = &splitter->_Channels[n]; + memcpy(dst_tmp++, channel, sizeof(ImDrawChannel)); + remaining_count--; + } + IM_ASSERT(dst_tmp == g.DrawChannelsTempMergeBuffer.Data + g.DrawChannelsTempMergeBuffer.Size); + memcpy(splitter->_Channels.Data + LEADING_DRAW_CHANNELS, g.DrawChannelsTempMergeBuffer.Data, (splitter->_Count - LEADING_DRAW_CHANNELS) * sizeof(ImDrawChannel)); + } +} + +// FIXME-TABLE: This is a mess, need to redesign how we render borders (as some are also done in TableEndRow) +void ImGui::TableDrawBorders(ImGuiTable* table) +{ + ImGuiWindow* inner_window = table->InnerWindow; + if (!table->OuterWindow->ClipRect.Overlaps(table->OuterRect)) + return; + + ImDrawList* inner_drawlist = inner_window->DrawList; + table->DrawSplitter->SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0); + inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false); + + // Draw inner border and resizing feedback + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); + const float border_size = TABLE_BORDER_SIZE; + const float draw_y1 = table->InnerRect.Min.y; + const float draw_y2_body = table->InnerRect.Max.y; + const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1; + if (table->Flags & ImGuiTableFlags_BordersInnerV) + { + for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + { + if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) + continue; + + const int column_n = table->DisplayOrderToIndex[order_n]; + ImGuiTableColumn* column = &table->Columns[column_n]; + const bool is_hovered = (table->HoveredColumnBorder == column_n); + const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent); + const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0; + const bool is_frozen_separator = (table->FreezeColumnsCount == order_n + 1); + if (column->MaxX > table->InnerClipRect.Max.x && !is_resized) + continue; + + // Decide whether right-most column is visible + if (column->NextEnabledColumn == -1 && !is_resizable) + if ((table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame || (table->Flags & ImGuiTableFlags_NoHostExtendX)) + continue; + if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size.. + continue; + + // Draw in outer window so right-most column won't be clipped + // Always draw full height border when being resized/hovered, or on the delimitation of frozen column scrolling. + ImU32 col; + float draw_y2; + if (is_hovered || is_resized || is_frozen_separator) + { + draw_y2 = draw_y2_body; + col = is_resized ? GetColorU32(ImGuiCol_SeparatorActive) : is_hovered ? GetColorU32(ImGuiCol_SeparatorHovered) : table->BorderColorStrong; + } + else + { + draw_y2 = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? draw_y2_head : draw_y2_body; + col = (table->Flags & (ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_NoBordersInBodyUntilResize)) ? table->BorderColorStrong : table->BorderColorLight; + } + + if (draw_y2 > draw_y1) + inner_drawlist->AddLine(ImVec2(column->MaxX, draw_y1), ImVec2(column->MaxX, draw_y2), col, border_size); + } + } + + // Draw outer border + // FIXME: could use AddRect or explicit VLine/HLine helper? + if (table->Flags & ImGuiTableFlags_BordersOuter) + { + // Display outer border offset by 1 which is a simple way to display it without adding an extra draw call + // (Without the offset, in outer_window it would be rendered behind cells, because child windows are above their + // parent. In inner_window, it won't reach out over scrollbars. Another weird solution would be to display part + // of it in inner window, and the part that's over scrollbars in the outer window..) + // Either solution currently won't allow us to use a larger border size: the border would clipped. + const ImRect outer_border = table->OuterRect; + const ImU32 outer_col = table->BorderColorStrong; + if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter) + { + inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size); + } + else if (table->Flags & ImGuiTableFlags_BordersOuterV) + { + inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size); + inner_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size); + } + else if (table->Flags & ImGuiTableFlags_BordersOuterH) + { + inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size); + inner_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size); + } + } + if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y) + { + // Draw bottom-most row border + const float border_y = table->RowPosY2; + if (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y) + inner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size); + } + + inner_drawlist->PopClipRect(); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Sorting +//------------------------------------------------------------------------- +// - TableGetSortSpecs() +// - TableFixColumnSortDirection() [Internal] +// - TableGetColumnNextSortDirection() [Internal] +// - TableSetColumnSortDirection() [Internal] +// - TableSortSpecsSanitize() [Internal] +// - TableSortSpecsBuild() [Internal] +//------------------------------------------------------------------------- + +// Return NULL if no sort specs (most often when ImGuiTableFlags_Sortable is not set) +// You can sort your data again when 'SpecsChanged == true'. It will be true with sorting specs have changed since +// last call, or the first time. +// Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()! +ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + + if (!(table->Flags & ImGuiTableFlags_Sortable)) + return NULL; + + // Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + TableSortSpecsBuild(table); + return &table->SortSpecs; +} + +static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n) +{ + IM_ASSERT(n < column->SortDirectionsAvailCount); + return (column->SortDirectionsAvailList >> (n << 1)) & 0x03; +} + +// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending) +void ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column) +{ + if (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0) + return; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + table->IsSortSpecsDirty = true; +} + +// Calculate next sort direction that would be set after clicking the column +// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click. +// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op. +IM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2); +ImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column) +{ + IM_ASSERT(column->SortDirectionsAvailCount > 0); + if (column->SortOrder == -1) + return TableGetColumnAvailSortDirection(column, 0); + for (int n = 0; n < 3; n++) + if (column->SortDirection == TableGetColumnAvailSortDirection(column, n)) + return TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount); + IM_ASSERT(0); + return ImGuiSortDirection_None; +} + +// Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert +// the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code. +void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + if (!(table->Flags & ImGuiTableFlags_SortMulti)) + append_to_sort_specs = false; + if (!(table->Flags & ImGuiTableFlags_SortTristate)) + IM_ASSERT(sort_direction != ImGuiSortDirection_None); + + ImGuiTableColumnIdx sort_order_max = 0; + if (append_to_sort_specs) + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder); + + ImGuiTableColumn* column = &table->Columns[column_n]; + column->SortDirection = (ImU8)sort_direction; + if (column->SortDirection == ImGuiSortDirection_None) + column->SortOrder = -1; + else if (column->SortOrder == -1 || !append_to_sort_specs) + column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0; + + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + { + ImGuiTableColumn* other_column = &table->Columns[other_column_n]; + if (other_column != column && !append_to_sort_specs) + other_column->SortOrder = -1; + TableFixColumnSortDirection(table, other_column); + } + table->IsSettingsDirty = true; + table->IsSortSpecsDirty = true; +} + +void ImGui::TableSortSpecsSanitize(ImGuiTable* table) +{ + IM_ASSERT(table->Flags & ImGuiTableFlags_Sortable); + + // Clear SortOrder from hidden column and verify that there's no gap or duplicate. + int sort_order_count = 0; + ImU64 sort_order_mask = 0x00; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder != -1 && !column->IsEnabled) + column->SortOrder = -1; + if (column->SortOrder == -1) + continue; + sort_order_count++; + sort_order_mask |= ((ImU64)1 << column->SortOrder); + IM_ASSERT(sort_order_count < (int)sizeof(sort_order_mask) * 8); + } + + const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1); + const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti); + if (need_fix_linearize || need_fix_single_sort_order) + { + ImU64 fixed_mask = 0x00; + for (int sort_n = 0; sort_n < sort_order_count; sort_n++) + { + // Fix: Rewrite sort order fields if needed so they have no gap or duplicate. + // (e.g. SortOrder 0 disappeared, SortOrder 1..2 exists --> rewrite then as SortOrder 0..1) + int column_with_smallest_sort_order = -1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if ((fixed_mask & ((ImU64)1 << (ImU64)column_n)) == 0 && table->Columns[column_n].SortOrder != -1) + if (column_with_smallest_sort_order == -1 || table->Columns[column_n].SortOrder < table->Columns[column_with_smallest_sort_order].SortOrder) + column_with_smallest_sort_order = column_n; + IM_ASSERT(column_with_smallest_sort_order != -1); + fixed_mask |= ((ImU64)1 << column_with_smallest_sort_order); + table->Columns[column_with_smallest_sort_order].SortOrder = (ImGuiTableColumnIdx)sort_n; + + // Fix: Make sure only one column has a SortOrder if ImGuiTableFlags_MultiSortable is not set. + if (need_fix_single_sort_order) + { + sort_order_count = 1; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + if (column_n != column_with_smallest_sort_order) + table->Columns[column_n].SortOrder = -1; + break; + } + } + } + + // Fallback default sort order (if no column with the ImGuiTableColumnFlags_DefaultSort flag) + if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + sort_order_count = 1; + column->SortOrder = 0; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + break; + } + } + + table->SortSpecsCount = (ImGuiTableColumnIdx)sort_order_count; +} + +void ImGui::TableSortSpecsBuild(ImGuiTable* table) +{ + bool dirty = table->IsSortSpecsDirty; + if (dirty) + { + TableSortSpecsSanitize(table); + table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + table->SortSpecs.SpecsDirty = true; // Mark as dirty for user + table->IsSortSpecsDirty = false; // Mark as not dirty for us + } + + // Write output + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; + if (dirty && sort_specs != NULL) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->SortOrder == -1) + continue; + IM_ASSERT(column->SortOrder < table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; + sort_spec->ColumnUserID = column->UserID; + sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; + sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; + sort_spec->SortDirection = column->SortDirection; + } + + table->SortSpecs.Specs = sort_specs; + table->SortSpecs.SpecsCount = table->SortSpecsCount; +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Headers +//------------------------------------------------------------------------- +// - TableGetHeaderRowHeight() [Internal] +// - TableHeadersRow() +// - TableHeader() +//------------------------------------------------------------------------- + +float ImGui::TableGetHeaderRowHeight() +{ + // Caring for a minor edge case: + // Calculate row height, for the unlikely case that some labels may be taller than others. + // If we didn't do that, uneven header height would highlight but smaller one before the tallest wouldn't catch input for all height. + // In your custom header row you may omit this all together and just call TableNextRow() without a height... + float row_height = GetTextLineHeight(); + int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + ImGuiTableColumnFlags flags = TableGetColumnFlags(column_n); + if ((flags & ImGuiTableColumnFlags_IsEnabled) && !(flags & ImGuiTableColumnFlags_NoHeaderLabel)) + row_height = ImMax(row_height, CalcTextSize(TableGetColumnName(column_n)).y); + } + row_height += GetStyle().CellPadding.y * 2.0f; + return row_height; +} + +// [Public] This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn(). +// The intent is that advanced users willing to create customized headers would not need to use this helper +// and can create their own! For example: TableHeader() may be preceeded by Checkbox() or other custom widgets. +// See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this. +// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy. +// FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public. +void ImGui::TableHeadersRow() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); + + // Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout) + if (!table->IsLayoutLocked) + TableUpdateLayout(table); + + // Open row + const float row_y1 = GetCursorScreenPos().y; + const float row_height = TableGetHeaderRowHeight(); + TableNextRow(ImGuiTableRowFlags_Headers, row_height); + if (table->HostSkipItems) // Merely an optimization, you may skip in your own code. + return; + + const int columns_count = TableGetColumnCount(); + for (int column_n = 0; column_n < columns_count; column_n++) + { + if (!TableSetColumnIndex(column_n)) + continue; + + // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) + // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide. + const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); + PushID(column_n); + TableHeader(name); + PopID(); + } + + // Allow opening popup from the right-most section after the last column. + ImVec2 mouse_pos = ImGui::GetMousePos(); + if (IsMouseReleased(1) && TableGetHoveredColumn() == columns_count) + if (mouse_pos.y >= row_y1 && mouse_pos.y < row_y1 + row_height) + TableOpenContextMenu(-1); // Will open a non-column-specific popup. +} + +// Emit a column header (text + optional sort order) +// We cpu-clip text here so that all columns headers can be merged into a same draw call. +// Note that because of how we cpu-clip and display sorting indicators, you _cannot_ use SameLine() after a TableHeader() +void ImGui::TableHeader(const char* label) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!"); + IM_ASSERT(table->CurrentColumn != -1); + const int column_n = table->CurrentColumn; + ImGuiTableColumn* column = &table->Columns[column_n]; + + // Label + if (label == NULL) + label = ""; + const char* label_end = FindRenderedTextEnd(label); + ImVec2 label_size = CalcTextSize(label, label_end, true); + ImVec2 label_pos = window->DC.CursorPos; + + // If we already got a row height, there's use that. + // FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect? + ImRect cell_r = TableGetCellBgRect(table, column_n); + float label_height = ImMax(label_size.y, table->RowMinHeight - table->CellPaddingY * 2.0f); + + // Calculate ideal size for sort order arrow + float w_arrow = 0.0f; + float w_sort_text = 0.0f; + char sort_order_suf[4] = ""; + const float ARROW_SCALE = 0.65f; + if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + w_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x); + if (column->SortOrder > 0) + { + ImFormatString(sort_order_suf, IM_ARRAYSIZE(sort_order_suf), "%d", column->SortOrder + 1); + w_sort_text = g.Style.ItemInnerSpacing.x + CalcTextSize(sort_order_suf).x; + } + } + + // We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considering for merging. + float max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow; + column->ContentMaxXHeadersUsed = ImMax(column->ContentMaxXHeadersUsed, column->WorkMaxX); + column->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x); + + // Keep header highlighted when context menu is open. + const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent); + ImGuiID id = window->GetID(label); + ImRect bb(cell_r.Min.x, cell_r.Min.y, cell_r.Max.x, ImMax(cell_r.Max.y, cell_r.Min.y + label_height + g.Style.CellPadding.y * 2.0f)); + ItemSize(ImVec2(0.0f, label_height)); // Don't declare unclipped width, it'll be fed ContentMaxPosHeadersIdeal + if (!ItemAdd(bb, id)) + return; + + //GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + //GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG] + + // Using AllowOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items. + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowOverlap); + if (held || hovered || selected) + { + const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + //RenderFrame(bb.Min, bb.Max, col, false, 0.0f); + TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); + } + else + { + // Submit single cell bg color in the case we didn't submit a full header row + if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + if (held) + table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; + window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; + + // Drag and drop to re-order columns. + // FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone. + if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive) + { + // While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x + table->ReorderColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + + // We don't reorder: through the frozen<>unfrozen line, or through a column that is marked with ImGuiTableColumnFlags_NoReorder. + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x) + if (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL) + if (!((column->Flags | prev_column->Flags) & ImGuiTableColumnFlags_NoReorder)) + if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (prev_column->IndexWithinEnabledSet < table->FreezeColumnsRequest)) + table->ReorderColumnDir = -1; + if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x) + if (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL) + if (!((column->Flags | next_column->Flags) & ImGuiTableColumnFlags_NoReorder)) + if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (next_column->IndexWithinEnabledSet < table->FreezeColumnsRequest)) + table->ReorderColumnDir = +1; + } + + // Sort order arrow + const float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x); + if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) + { + if (column->SortOrder != -1) + { + float x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text); + float y = label_pos.y; + if (column->SortOrder > 0) + { + PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text, 0.70f)); + RenderText(ImVec2(x + g.Style.ItemInnerSpacing.x, y), sort_order_suf); + PopStyleColor(); + x += w_sort_text; + } + RenderArrow(window->DrawList, ImVec2(x, y), GetColorU32(ImGuiCol_Text), column->SortDirection == ImGuiSortDirection_Ascending ? ImGuiDir_Up : ImGuiDir_Down, ARROW_SCALE); + } + + // Handle clicking on column header to adjust Sort Order + if (pressed && table->ReorderColumn != column_n) + { + ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column); + TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift); + } + } + + // Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will + // be merged into a single draw call. + //window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); + + const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); + if (text_clipped && hovered && g.ActiveId == 0) + SetItemTooltip("%.*s", (int)(label_end - label), label); + + // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden + if (IsMouseReleased(1) && IsItemHovered()) + TableOpenContextMenu(column_n); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Context Menu +//------------------------------------------------------------------------- +// - TableOpenContextMenu() [Internal] +// - TableDrawContextMenu() [Internal] +//------------------------------------------------------------------------- + +// Use -1 to open menu not specific to a given column. +void ImGui::TableOpenContextMenu(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (column_n == -1 && table->CurrentColumn != -1) // When called within a column automatically use this one (for consistency) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) // To facilitate using with TableGetHoveredColumn() + column_n = -1; + IM_ASSERT(column_n >= -1 && column_n < table->ColumnsCount); + if (table->Flags & (ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + { + table->IsContextPopupOpen = true; + table->ContextPopupColumn = (ImGuiTableColumnIdx)column_n; + table->InstanceInteracted = table->InstanceCurrent; + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + OpenPopupEx(context_menu_id, ImGuiPopupFlags_None); + } +} + +bool ImGui::TableBeginContextMenuPopup(ImGuiTable* table) +{ + if (!table->IsContextPopupOpen || table->InstanceCurrent != table->InstanceInteracted) + return false; + const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID); + if (BeginPopupEx(context_menu_id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings)) + return true; + table->IsContextPopupOpen = false; + return false; +} + +// Output context menu into current window (generally a popup) +// FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data? +void ImGui::TableDrawContextMenu(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + bool want_separator = false; + const int column_n = (table->ContextPopupColumn >= 0 && table->ContextPopupColumn < table->ColumnsCount) ? table->ContextPopupColumn : -1; + ImGuiTableColumn* column = (column_n != -1) ? &table->Columns[column_n] : NULL; + + // Sizing + if (table->Flags & ImGuiTableFlags_Resizable) + { + if (column != NULL) + { + const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled; + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableSizeOne), NULL, false, can_resize)) // "###SizeOne" + TableSetColumnWidthAutoSingle(table, column_n); + } + + const char* size_all_desc; + if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame) + size_all_desc = LocalizeGetMsg(ImGuiLocKey_TableSizeAllFit); // "###SizeAll" All fixed + else + size_all_desc = LocalizeGetMsg(ImGuiLocKey_TableSizeAllDefault); // "###SizeAll" All stretch or mixed + if (MenuItem(size_all_desc, NULL)) + TableSetColumnWidthAutoAll(table); + want_separator = true; + } + + // Ordering + if (table->Flags & ImGuiTableFlags_Reorderable) + { + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) + table->IsResetDisplayOrderRequest = true; + want_separator = true; + } + + // Reset all (should work but seems unnecessary/noisy to expose?) + //if (MenuItem("Reset all")) + // table->IsResetAllRequest = true; + + // Sorting + // (modify TableOpenContextMenu() to add _Sortable flag if enabling this) +#if 0 + if ((table->Flags & ImGuiTableFlags_Sortable) && column != NULL && (column->Flags & ImGuiTableColumnFlags_NoSort) == 0) + { + if (want_separator) + Separator(); + want_separator = true; + + bool append_to_sort_specs = g.IO.KeyShift; + if (MenuItem("Sort in Ascending Order", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Ascending, (column->Flags & ImGuiTableColumnFlags_NoSortAscending) == 0)) + TableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Ascending, append_to_sort_specs); + if (MenuItem("Sort in Descending Order", NULL, column->SortOrder != -1 && column->SortDirection == ImGuiSortDirection_Descending, (column->Flags & ImGuiTableColumnFlags_NoSortDescending) == 0)) + TableSetColumnSortDirection(table, column_n, ImGuiSortDirection_Descending, append_to_sort_specs); + } +#endif + + // Hiding / Visibility + if (table->Flags & ImGuiTableFlags_Hideable) + { + if (want_separator) + Separator(); + want_separator = true; + + PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true); + for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) + { + ImGuiTableColumn* other_column = &table->Columns[other_column_n]; + if (other_column->Flags & ImGuiTableColumnFlags_Disabled) + continue; + + const char* name = TableGetColumnName(table, other_column_n); + if (name == NULL || name[0] == 0) + name = ""; + + // Make sure we can't hide the last active column + bool menu_item_active = (other_column->Flags & ImGuiTableColumnFlags_NoHide) ? false : true; + if (other_column->IsUserEnabled && table->ColumnsEnabledCount <= 1) + menu_item_active = false; + if (MenuItem(name, NULL, other_column->IsUserEnabled, menu_item_active)) + other_column->IsUserEnabledNextFrame = !other_column->IsUserEnabled; + } + PopItemFlag(); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Settings (.ini data) +//------------------------------------------------------------------------- +// FIXME: The binding/finding/creating flow are too confusing. +//------------------------------------------------------------------------- +// - TableSettingsInit() [Internal] +// - TableSettingsCalcChunkSize() [Internal] +// - TableSettingsCreate() [Internal] +// - TableSettingsFindByID() [Internal] +// - TableGetBoundSettings() [Internal] +// - TableResetSettings() +// - TableSaveSettings() [Internal] +// - TableLoadSettings() [Internal] +// - TableSettingsHandler_ClearAll() [Internal] +// - TableSettingsHandler_ApplyAll() [Internal] +// - TableSettingsHandler_ReadOpen() [Internal] +// - TableSettingsHandler_ReadLine() [Internal] +// - TableSettingsHandler_WriteAll() [Internal] +// - TableSettingsInstallHandler() [Internal] +//------------------------------------------------------------------------- +// [Init] 1: TableSettingsHandler_ReadXXXX() Load and parse .ini file into TableSettings. +// [Main] 2: TableLoadSettings() When table is created, bind Table to TableSettings, serialize TableSettings data into Table. +// [Main] 3: TableSaveSettings() When table properties are modified, serialize Table data into bound or new TableSettings, mark .ini as dirty. +// [Main] 4: TableSettingsHandler_WriteAll() When .ini file is dirty (which can come from other source), save TableSettings into .ini file. +//------------------------------------------------------------------------- + +// Clear and initialize empty settings instance +static void TableSettingsInit(ImGuiTableSettings* settings, ImGuiID id, int columns_count, int columns_count_max) +{ + IM_PLACEMENT_NEW(settings) ImGuiTableSettings(); + ImGuiTableColumnSettings* settings_column = settings->GetColumnSettings(); + for (int n = 0; n < columns_count_max; n++, settings_column++) + IM_PLACEMENT_NEW(settings_column) ImGuiTableColumnSettings(); + settings->ID = id; + settings->ColumnsCount = (ImGuiTableColumnIdx)columns_count; + settings->ColumnsCountMax = (ImGuiTableColumnIdx)columns_count_max; + settings->WantApply = true; +} + +static size_t TableSettingsCalcChunkSize(int columns_count) +{ + return sizeof(ImGuiTableSettings) + (size_t)columns_count * sizeof(ImGuiTableColumnSettings); +} + +ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count) +{ + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count)); + TableSettingsInit(settings, id, columns_count, columns_count); + return settings; +} + +// Find existing settings +ImGuiTableSettings* ImGui::TableSettingsFindByID(ImGuiID id) +{ + // FIXME-OPT: Might want to store a lookup map for this? + ImGuiContext& g = *GImGui; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +// Get settings for a given table, NULL if none +ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table) +{ + if (table->SettingsOffset != -1) + { + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset); + IM_ASSERT(settings->ID == table->ID); + if (settings->ColumnsCountMax >= table->ColumnsCount) + return settings; // OK + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } + return NULL; +} + +// Restore initial state of table (with or without saved settings) +void ImGui::TableResetSettings(ImGuiTable* table) +{ + table->IsInitializing = table->IsSettingsDirty = true; + table->IsResetAllRequest = false; + table->IsSettingsRequestLoad = false; // Don't reload from ini + table->SettingsLoadedFlags = ImGuiTableFlags_None; // Mark as nothing loaded so our initialized data becomes authoritative +} + +void ImGui::TableSaveSettings(ImGuiTable* table) +{ + table->IsSettingsDirty = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + // Bind or create settings data + ImGuiContext& g = *GImGui; + ImGuiTableSettings* settings = TableGetBoundSettings(table); + if (settings == NULL) + { + settings = TableSettingsCreate(table->ID, table->ColumnsCount); + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + settings->ColumnsCount = (ImGuiTableColumnIdx)table->ColumnsCount; + + // Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings + IM_ASSERT(settings->ID == table->ID); + IM_ASSERT(settings->ColumnsCount == table->ColumnsCount && settings->ColumnsCountMax >= settings->ColumnsCount); + ImGuiTableColumn* column = table->Columns.Data; + ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); + + bool save_ref_scale = false; + settings->SaveFlags = ImGuiTableFlags_None; + for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++) + { + const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest; + column_settings->WidthOrWeight = width_or_weight; + column_settings->Index = (ImGuiTableColumnIdx)n; + column_settings->DisplayOrder = column->DisplayOrder; + column_settings->SortOrder = column->SortOrder; + column_settings->SortDirection = column->SortDirection; + column_settings->IsEnabled = column->IsUserEnabled; + column_settings->IsStretch = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? 1 : 0; + if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) == 0) + save_ref_scale = true; + + // We skip saving some data in the .ini file when they are unnecessary to restore our state. + // Note that fixed width where initial width was derived from auto-fit will always be saved as InitStretchWeightOrWidth will be 0.0f. + // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present. + if (width_or_weight != column->InitStretchWeightOrWidth) + settings->SaveFlags |= ImGuiTableFlags_Resizable; + if (column->DisplayOrder != n) + settings->SaveFlags |= ImGuiTableFlags_Reorderable; + if (column->SortOrder != -1) + settings->SaveFlags |= ImGuiTableFlags_Sortable; + if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0)) + settings->SaveFlags |= ImGuiTableFlags_Hideable; + } + settings->SaveFlags &= table->Flags; + settings->RefScale = save_ref_scale ? table->RefScale : 0.0f; + + MarkIniSettingsDirty(); +} + +void ImGui::TableLoadSettings(ImGuiTable* table) +{ + ImGuiContext& g = *GImGui; + table->IsSettingsRequestLoad = false; + if (table->Flags & ImGuiTableFlags_NoSavedSettings) + return; + + // Bind settings + ImGuiTableSettings* settings; + if (table->SettingsOffset == -1) + { + settings = TableSettingsFindByID(table->ID); + if (settings == NULL) + return; + if (settings->ColumnsCount != table->ColumnsCount) // Allow settings if columns count changed. We could otherwise decide to return... + table->IsSettingsDirty = true; + table->SettingsOffset = g.SettingsTables.offset_from_ptr(settings); + } + else + { + settings = TableGetBoundSettings(table); + } + + table->SettingsLoadedFlags = settings->SaveFlags; + table->RefScale = settings->RefScale; + + // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn + ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); + ImU64 display_order_mask = 0; + for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++) + { + int column_n = column_settings->Index; + if (column_n < 0 || column_n >= table->ColumnsCount) + continue; + + ImGuiTableColumn* column = &table->Columns[column_n]; + if (settings->SaveFlags & ImGuiTableFlags_Resizable) + { + if (column_settings->IsStretch) + column->StretchWeight = column_settings->WidthOrWeight; + else + column->WidthRequest = column_settings->WidthOrWeight; + column->AutoFitQueue = 0x00; + } + if (settings->SaveFlags & ImGuiTableFlags_Reorderable) + column->DisplayOrder = column_settings->DisplayOrder; + else + column->DisplayOrder = (ImGuiTableColumnIdx)column_n; + display_order_mask |= (ImU64)1 << column->DisplayOrder; + column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled; + column->SortOrder = column_settings->SortOrder; + column->SortDirection = column_settings->SortDirection; + } + + // Validate and fix invalid display order data + const ImU64 expected_display_order_mask = (settings->ColumnsCount == 64) ? ~0 : ((ImU64)1 << settings->ColumnsCount) - 1; + if (display_order_mask != expected_display_order_mask) + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->Columns[column_n].DisplayOrder = (ImGuiTableColumnIdx)column_n; + + // Rebuild index + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; +} + +static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetMapSize(); i++) + if (ImGuiTable* table = g.Tables.TryGetMapData(i)) + table->SettingsOffset = -1; + g.SettingsTables.clear(); +} + +// Apply to existing windows (if any) +static void TableSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*) +{ + ImGuiContext& g = *ctx; + for (int i = 0; i != g.Tables.GetMapSize(); i++) + if (ImGuiTable* table = g.Tables.TryGetMapData(i)) + { + table->IsSettingsRequestLoad = true; + table->SettingsOffset = -1; + } +} + +static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) +{ + ImGuiID id = 0; + int columns_count = 0; + if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2) + return NULL; + + if (ImGuiTableSettings* settings = ImGui::TableSettingsFindByID(id)) + { + if (settings->ColumnsCountMax >= columns_count) + { + TableSettingsInit(settings, id, columns_count, settings->ColumnsCountMax); // Recycle + return settings; + } + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } + return ImGui::TableSettingsCreate(id, columns_count); +} + +static void TableSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) +{ + // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + ImGuiTableSettings* settings = (ImGuiTableSettings*)entry; + float f = 0.0f; + int column_n = 0, r = 0, n = 0; + + if (sscanf(line, "RefScale=%f", &f) == 1) { settings->RefScale = f; return; } + + if (sscanf(line, "Column %d%n", &column_n, &r) == 1) + { + if (column_n < 0 || column_n >= settings->ColumnsCount) + return; + line = ImStrSkipBlank(line + r); + char c = 0; + ImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n; + column->Index = (ImGuiTableColumnIdx)column_n; + if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; } + if (sscanf(line, "Width=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; } + if (sscanf(line, "Weight=%f%n", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; } + if (sscanf(line, "Visible=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; } + if (sscanf(line, "Order=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; } + if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; } + } +} + +static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) +{ + ImGuiContext& g = *ctx; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + { + if (settings->ID == 0) // Skip ditched settings + continue; + + // TableSaveSettings() may clear some of those flags when we establish that the data can be stripped + // (e.g. Order was unchanged) + const bool save_size = (settings->SaveFlags & ImGuiTableFlags_Resizable) != 0; + const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0; + const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0; + const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0; + if (!save_size && !save_visible && !save_order && !save_sort) + continue; + + buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve + buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount); + if (settings->RefScale != 0.0f) + buf->appendf("RefScale=%g\n", settings->RefScale); + ImGuiTableColumnSettings* column = settings->GetColumnSettings(); + for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++) + { + // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" + bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); + if (!save_column) + continue; + buf->appendf("Column %-2d", column_n); + if (column->UserID != 0) { buf->appendf(" UserID=%08X", column->UserID); } + if (save_size && column->IsStretch) { buf->appendf(" Weight=%.4f", column->WidthOrWeight); } + if (save_size && !column->IsStretch) { buf->appendf(" Width=%d", (int)column->WidthOrWeight); } + if (save_visible) { buf->appendf(" Visible=%d", column->IsEnabled); } + if (save_order) { buf->appendf(" Order=%d", column->DisplayOrder); } + if (save_sort && column->SortOrder != -1) { buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); } + buf->append("\n"); + } + buf->append("\n"); + } +} + +void ImGui::TableSettingsAddSettingsHandler() +{ + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "Table"; + ini_handler.TypeHash = ImHashStr("Table"); + ini_handler.ClearAllFn = TableSettingsHandler_ClearAll; + ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen; + ini_handler.ReadLineFn = TableSettingsHandler_ReadLine; + ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll; + ini_handler.WriteAllFn = TableSettingsHandler_WriteAll; + AddSettingsHandler(&ini_handler); +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Garbage Collection +//------------------------------------------------------------------------- +// - TableRemove() [Internal] +// - TableGcCompactTransientBuffers() [Internal] +// - TableGcCompactSettings() [Internal] +//------------------------------------------------------------------------- + +// Remove Table (currently only used by TestEngine) +void ImGui::TableRemove(ImGuiTable* table) +{ + //IMGUI_DEBUG_PRINT("TableRemove() id=0x%08X\n", table->ID); + ImGuiContext& g = *GImGui; + int table_idx = g.Tables.GetIndex(table); + //memset(table->RawData.Data, 0, table->RawData.size_in_bytes()); + //memset(table, 0, sizeof(ImGuiTable)); + g.Tables.Remove(table->ID, table); + g.TablesLastTimeActive[table_idx] = -1.0f; +} + +// Free up/compact internal Table buffers for when it gets unused +void ImGui::TableGcCompactTransientBuffers(ImGuiTable* table) +{ + //IMGUI_DEBUG_PRINT("TableGcCompactTransientBuffers() id=0x%08X\n", table->ID); + ImGuiContext& g = *GImGui; + IM_ASSERT(table->MemoryCompacted == false); + table->SortSpecs.Specs = NULL; + table->SortSpecsMulti.clear(); + table->IsSortSpecsDirty = true; // FIXME: In theory shouldn't have to leak into user performing a sort on resume. + table->ColumnsNames.clear(); + table->MemoryCompacted = true; + for (int n = 0; n < table->ColumnsCount; n++) + table->Columns[n].NameOffset = -1; + g.TablesLastTimeActive[g.Tables.GetIndex(table)] = -1.0f; +} + +void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) +{ + temp_data->DrawSplitter.ClearFreeMemory(); + temp_data->LastTimeActive = -1.0f; +} + +// Compact and remove unused settings data (currently only used by TestEngine) +void ImGui::TableGcCompactSettings() +{ + ImGuiContext& g = *GImGui; + int required_memory = 0; + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID != 0) + required_memory += (int)TableSettingsCalcChunkSize(settings->ColumnsCount); + if (required_memory == g.SettingsTables.Buf.Size) + return; + ImChunkStream new_chunk_stream; + new_chunk_stream.Buf.reserve(required_memory); + for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) + if (settings->ID != 0) + memcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount)); + g.SettingsTables.swap(new_chunk_stream); +} + + +//------------------------------------------------------------------------- +// [SECTION] Tables: Debugging +//------------------------------------------------------------------------- +// - DebugNodeTable() [Internal] +//------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + +static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy) +{ + sizing_policy &= ImGuiTableFlags_SizingMask_; + if (sizing_policy == ImGuiTableFlags_SizingFixedFit) { return "FixedFit"; } + if (sizing_policy == ImGuiTableFlags_SizingFixedSame) { return "FixedSame"; } + if (sizing_policy == ImGuiTableFlags_SizingStretchProp) { return "StretchProp"; } + if (sizing_policy == ImGuiTableFlags_SizingStretchSame) { return "StretchSame"; } + return "N/A"; +} + +void ImGui::DebugNodeTable(ImGuiTable* table) +{ + const bool is_active = (table->LastFrameActive >= GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here. + if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); } + bool open = TreeNode(table, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*"); + if (!is_active) { PopStyleColor(); } + if (IsItemHovered()) + GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); + if (IsItemVisible() && table->HoveredColumnBody != -1) + GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + if (!open) + return; + if (table->InstanceCurrent > 0) + Text("** %d instances of same table! Some data below will refer to last instance.", table->InstanceCurrent + 1); + bool clear_settings = SmallButton("Clear settings"); + BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags)); + BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); + BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); + BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); + BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn); + for (int n = 0; n < table->InstanceCurrent + 1; n++) + { + ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, n); + BulletText("Instance %d: HoveredRow: %d, LastOuterHeight: %.2f", n, table_instance->HoveredRowLast, table_instance->LastOuterHeight); + } + //BulletText("BgDrawChannels: %d/%d", 0, table->BgDrawChannelUnfrozen); + float sum_weights = 0.0f; + for (int n = 0; n < table->ColumnsCount; n++) + if (table->Columns[n].Flags & ImGuiTableColumnFlags_WidthStretch) + sum_weights += table->Columns[n].StretchWeight; + for (int n = 0; n < table->ColumnsCount; n++) + { + ImGuiTableColumn* column = &table->Columns[n]; + const char* name = TableGetColumnName(table, n); + char buf[512]; + ImFormatString(buf, IM_ARRAYSIZE(buf), + "Column %d order %d '%s': offset %+.2f to %+.2f%s\n" + "Enabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\n" + "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\n" + "MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n" + "ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\n" + "Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s..", + n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? " (Frozen)" : "", + column->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen, + column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f, + column->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x, + column->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX, + column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags, + (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", + (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "", + (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); + Bullet(); + Selectable(buf); + if (IsItemHovered()) + { + ImRect r(column->MinX, table->OuterRect.Min.y, column->MaxX, table->OuterRect.Max.y); + GetForegroundDrawList()->AddRect(r.Min, r.Max, IM_COL32(255, 255, 0, 255)); + } + } + if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) + DebugNodeTableSettings(settings); + if (clear_settings) + table->IsResetAllRequest = true; + TreePop(); +} + +void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings) +{ + if (!TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount)) + return; + BulletText("SaveFlags: 0x%08X", settings->SaveFlags); + BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); + for (int n = 0; n < settings->ColumnsCount; n++) + { + ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; + ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; + BulletText("Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X", + n, column_settings->DisplayOrder, column_settings->SortOrder, + (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", + column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->UserID); + } + TreePop(); +} + +#else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS + +void ImGui::DebugNodeTable(ImGuiTable*) {} +void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {} + +#endif + + +//------------------------------------------------------------------------- +// [SECTION] Columns, BeginColumns, EndColumns, etc. +// (This is a legacy API, prefer using BeginTable/EndTable!) +//------------------------------------------------------------------------- +// FIXME: sizing is lossy when columns width is very small (default width may turn negative etc.) +//------------------------------------------------------------------------- +// - SetWindowClipRectBeforeSetChannel() [Internal] +// - GetColumnIndex() +// - GetColumnsCount() +// - GetColumnOffset() +// - GetColumnWidth() +// - SetColumnOffset() +// - SetColumnWidth() +// - PushColumnClipRect() [Internal] +// - PushColumnsBackground() [Internal] +// - PopColumnsBackground() [Internal] +// - FindOrCreateColumns() [Internal] +// - GetColumnsID() [Internal] +// - BeginColumns() +// - NextColumn() +// - EndColumns() +// - Columns() +//------------------------------------------------------------------------- + +// [Internal] Small optimization to avoid calls to PopClipRect/SetCurrentChannel/PushClipRect in sequences, +// they would meddle many times with the underlying ImDrawCmd. +// Instead, we do a preemptive overwrite of clipping rectangle _without_ altering the command-buffer and let +// the subsequent single call to SetCurrentChannel() does it things once. +void ImGui::SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect) +{ + ImVec4 clip_rect_vec4 = clip_rect.ToVec4(); + window->ClipRect = clip_rect; + window->DrawList->_CmdHeader.ClipRect = clip_rect_vec4; + window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 1] = clip_rect_vec4; +} + +int ImGui::GetColumnIndex() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0; +} + +int ImGui::GetColumnsCount() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1; +} + +float ImGui::GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm) +{ + return offset_norm * (columns->OffMaxX - columns->OffMinX); +} + +float ImGui::GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset) +{ + return offset / (columns->OffMaxX - columns->OffMinX); +} + +static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f; + +static float GetDraggedColumnOffset(ImGuiOldColumns* columns, int column_index) +{ + // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing + // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(column_index > 0); // We are not supposed to drag column 0. + IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index)); + + float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x; + x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing); + if ((columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths)) + x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing); + + return x; +} + +float ImGui::GetColumnOffset(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return 0.0f; + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const float t = columns->Columns[column_index].OffsetNorm; + const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t); + return x_offset; +} + +static float GetColumnWidthEx(ImGuiOldColumns* columns, int column_index, bool before_resize = false) +{ + if (column_index < 0) + column_index = columns->Current; + + float offset_norm; + if (before_resize) + offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize; + else + offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm; + return ImGui::GetColumnOffsetFromNorm(columns, offset_norm); +} + +float ImGui::GetColumnWidth(int column_index) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns == NULL) + return GetContentRegionAvail().x; + + if (column_index < 0) + column_index = columns->Current; + return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm); +} + +void ImGui::SetColumnOffset(int column_index, float offset) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + IM_ASSERT(column_index < columns->Columns.Size); + + const bool preserve_width = !(columns->Flags & ImGuiOldColumnFlags_NoPreserveWidths) && (column_index < columns->Count - 1); + const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f; + + if (!(columns->Flags & ImGuiOldColumnFlags_NoForceWithinWindow)) + offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index)); + columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX); + + if (preserve_width) + SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width)); +} + +void ImGui::SetColumnWidth(int column_index, float width) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + if (column_index < 0) + column_index = columns->Current; + SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width); +} + +void ImGui::PushColumnClipRect(int column_index) +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (column_index < 0) + column_index = columns->Current; + + ImGuiOldColumnData* column = &columns->Columns[column_index]; + PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false); +} + +// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns) +void ImGui::PushColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + columns->HostBackupClipRect = window->ClipRect; + SetWindowClipRectBeforeSetChannel(window, columns->HostInitialClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, 0); +} + +void ImGui::PopColumnsBackground() +{ + ImGuiWindow* window = GetCurrentWindowRead(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns->Count == 1) + return; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + SetWindowClipRectBeforeSetChannel(window, columns->HostBackupClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); +} + +ImGuiOldColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id) +{ + // We have few columns per window so for now we don't need bother much with turning this into a faster lookup. + for (int n = 0; n < window->ColumnsStorage.Size; n++) + if (window->ColumnsStorage[n].ID == id) + return &window->ColumnsStorage[n]; + + window->ColumnsStorage.push_back(ImGuiOldColumns()); + ImGuiOldColumns* columns = &window->ColumnsStorage.back(); + columns->ID = id; + return columns; +} + +ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count) +{ + ImGuiWindow* window = GetCurrentWindow(); + + // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget. + // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer. + PushID(0x11223347 + (str_id ? 0 : columns_count)); + ImGuiID id = window->GetID(str_id ? str_id : "columns"); + PopID(); + + return id; +} + +void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiOldColumnFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + IM_ASSERT(columns_count >= 1); + IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported + + // Acquire storage for the columns set + ImGuiID id = GetColumnsID(str_id, columns_count); + ImGuiOldColumns* columns = FindOrCreateColumns(window, id); + IM_ASSERT(columns->ID == id); + columns->Current = 0; + columns->Count = columns_count; + columns->Flags = flags; + window->DC.CurrentColumns = columns; + window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX(); + + columns->HostCursorPosY = window->DC.CursorPos.y; + columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x; + columns->HostInitialClipRect = window->ClipRect; + columns->HostBackupParentWorkRect = window->ParentWorkRect; + window->ParentWorkRect = window->WorkRect; + + // Set state for first column + // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect + const float column_padding = g.Style.ItemSpacing.x; + const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize)); + const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f); + const float max_2 = window->WorkRect.Max.x + half_clip_extend_x; + columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f); + columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f); + columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y; + + // Clear data if columns count changed + if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1) + columns->Columns.resize(0); + + // Initialize default widths + columns->IsFirstFrame = (columns->Columns.Size == 0); + if (columns->Columns.Size == 0) + { + columns->Columns.reserve(columns_count + 1); + for (int n = 0; n < columns_count + 1; n++) + { + ImGuiOldColumnData column; + column.OffsetNorm = n / (float)columns_count; + columns->Columns.push_back(column); + } + } + + for (int n = 0; n < columns_count; n++) + { + // Compute clipping rectangle + ImGuiOldColumnData* column = &columns->Columns[n]; + float clip_x1 = IM_ROUND(window->Pos.x + GetColumnOffset(n)); + float clip_x2 = IM_ROUND(window->Pos.x + GetColumnOffset(n + 1) - 1.0f); + column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX); + column->ClipRect.ClipWithFull(window->ClipRect); + } + + if (columns->Count > 1) + { + columns->Splitter.Split(window->DrawList, 1 + columns->Count); + columns->Splitter.SetCurrentChannel(window->DrawList, 1); + PushColumnClipRect(0); + } + + // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; + window->WorkRect.Max.y = window->ContentRegionRect.Max.y; +} + +void ImGui::NextColumn() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems || window->DC.CurrentColumns == NULL) + return; + + ImGuiContext& g = *GImGui; + ImGuiOldColumns* columns = window->DC.CurrentColumns; + + if (columns->Count == 1) + { + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + IM_ASSERT(columns->Current == 0); + return; + } + + // Next column + if (++columns->Current == columns->Count) + columns->Current = 0; + + PopItemWidth(); + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + PushClipRect() + // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), + ImGuiOldColumnData* column = &columns->Columns[columns->Current]; + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); + + const float column_padding = g.Style.ItemSpacing.x; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + if (columns->Current > 0) + { + // Columns 1+ ignore IndentX (by canceling it out) + // FIXME-COLUMNS: Unnecessary, could be locked? + window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding; + } + else + { + // New row/line: column 0 honor IndentX. + window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); + window->DC.IsSameLine = false; + columns->LineMinY = columns->LineMaxY; + } + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = columns->LineMinY; + window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.CurrLineTextBaseOffset = 0.0f; + + // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. + float offset_0 = GetColumnOffset(columns->Current); + float offset_1 = GetColumnOffset(columns->Current + 1); + float width = offset_1 - offset_0; + PushItemWidth(width * 0.65f); + window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding; +} + +void ImGui::EndColumns() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + ImGuiOldColumns* columns = window->DC.CurrentColumns; + IM_ASSERT(columns != NULL); + + PopItemWidth(); + if (columns->Count > 1) + { + PopClipRect(); + columns->Splitter.Merge(window->DrawList); + } + + const ImGuiOldColumnFlags flags = columns->Flags; + columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); + window->DC.CursorPos.y = columns->LineMaxY; + if (!(flags & ImGuiOldColumnFlags_GrowParentContentsSize)) + window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent + + // Draw columns borders and handle resize + // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy + bool is_being_resized = false; + if (!(flags & ImGuiOldColumnFlags_NoBorder) && !window->SkipItems) + { + // We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers. + const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y); + const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y); + int dragging_column = -1; + for (int n = 1; n < columns->Count; n++) + { + ImGuiOldColumnData* column = &columns->Columns[n]; + float x = window->Pos.x + GetColumnOffset(n); + const ImGuiID column_id = columns->ID + ImGuiID(n); + const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH; + const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2)); + if (!ItemAdd(column_hit_rect, column_id, NULL, ImGuiItemFlags_NoNav)) + continue; + + bool hovered = false, held = false; + if (!(flags & ImGuiOldColumnFlags_NoResize)) + { + ButtonBehavior(column_hit_rect, column_id, &hovered, &held); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; + if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) + dragging_column = n; + } + + // Draw column + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + const float xi = IM_FLOOR(x); + window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col); + } + + // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame. + if (dragging_column != -1) + { + if (!columns->IsBeingResized) + for (int n = 0; n < columns->Count + 1; n++) + columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm; + columns->IsBeingResized = is_being_resized = true; + float x = GetDraggedColumnOffset(columns, dragging_column); + SetColumnOffset(dragging_column, x); + } + } + columns->IsBeingResized = is_being_resized; + + window->WorkRect = window->ParentWorkRect; + window->ParentWorkRect = columns->HostBackupParentWorkRect; + window->DC.CurrentColumns = NULL; + window->DC.ColumnsOffset.x = 0.0f; + window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + NavUpdateCurrentWindowIsScrollPushableX(); +} + +void ImGui::Columns(int columns_count, const char* id, bool border) +{ + ImGuiWindow* window = GetCurrentWindow(); + IM_ASSERT(columns_count >= 1); + + ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); + //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior + ImGuiOldColumns* columns = window->DC.CurrentColumns; + if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) + return; + + if (columns != NULL) + EndColumns(); + + if (columns_count != 1) + BeginColumns(id, columns_count, flags); +} + +//------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imgui_widgets.cpp b/Amalgam/include/ImGui/imgui_widgets.cpp new file mode 100644 index 0000000..ebbca5d --- /dev/null +++ b/Amalgam/include/ImGui/imgui_widgets.cpp @@ -0,0 +1,8637 @@ +// dear imgui, v1.89.8 +// (widgets code) + +/* + +Index of this file: + +// [SECTION] Forward Declarations +// [SECTION] Widgets: Text, etc. +// [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, Bullet, etc.) +// [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separator, etc.) +// [SECTION] Widgets: ComboBox +// [SECTION] Data Type and Data Formatting Helpers +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +// [SECTION] Widgets: InputText, InputTextMultiline +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +// [SECTION] Widgets: Selectable +// [SECTION] Widgets: ListBox +// [SECTION] Widgets: PlotLines, PlotHistogram +// [SECTION] Widgets: Value helpers +// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc. +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc. + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_internal.h" + +// System includes +#include // intptr_t + +//------------------------------------------------------------------------- +// Warnings +//------------------------------------------------------------------------- + +// Visual Studio warnings +#ifdef _MSC_VER +#pragma warning (disable: 4127) // condition expression is constant +#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen +#if defined(_MSC_VER) && _MSC_VER >= 1922 // MSVC 2019 16.2 or later +#pragma warning (disable: 5054) // operator '|': deprecated between enumerations of different types +#endif +#pragma warning (disable: 26451) // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2). +#pragma warning (disable: 26812) // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). +#endif + +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. +#pragma clang diagnostic ignored "-Wenum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') +#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#endif + +//------------------------------------------------------------------------- +// Data +//------------------------------------------------------------------------- + +// Widgets +static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f; // Time for drag-hold to activate items accepting the ImGuiButtonFlags_PressedOnDragDropHold button behavior. +static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f; // Multiplier for the default value of io.MouseDragThreshold to make DragFloat/DragInt react faster to mouse drags. + +// Those MIN/MAX values are not define because we need to point to them +static const signed char IM_S8_MIN = -128; +static const signed char IM_S8_MAX = 127; +static const unsigned char IM_U8_MIN = 0; +static const unsigned char IM_U8_MAX = 0xFF; +static const signed short IM_S16_MIN = -32768; +static const signed short IM_S16_MAX = 32767; +static const unsigned short IM_U16_MIN = 0; +static const unsigned short IM_U16_MAX = 0xFFFF; +static const ImS32 IM_S32_MIN = INT_MIN; // (-2147483647 - 1), (0x80000000); +static const ImS32 IM_S32_MAX = INT_MAX; // (2147483647), (0x7FFFFFFF) +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = UINT_MAX; // (0xFFFFFFFF) +#ifdef LLONG_MIN +static const ImS64 IM_S64_MIN = LLONG_MIN; // (-9223372036854775807ll - 1ll); +static const ImS64 IM_S64_MAX = LLONG_MAX; // (9223372036854775807ll); +#else +static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1; +static const ImS64 IM_S64_MAX = 9223372036854775807LL; +#endif +static const ImU64 IM_U64_MIN = 0; +#ifdef ULLONG_MAX +static const ImU64 IM_U64_MAX = ULLONG_MAX; // (0xFFFFFFFFFFFFFFFFull); +#else +static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); +#endif + +//------------------------------------------------------------------------- +// [SECTION] Forward Declarations +//------------------------------------------------------------------------- + +// For InputTextEx() +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Text, etc. +//------------------------------------------------------------------------- +// - TextEx() [Internal] +// - TextUnformatted() +// - Text() +// - TextV() +// - TextColored() +// - TextColoredV() +// - TextDisabled() +// - TextDisabledV() +// - TextWrapped() +// - TextWrappedV() +// - LabelText() +// - LabelTextV() +// - BulletText() +// - BulletTextV() +//------------------------------------------------------------------------- + +void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Accept null ranges + if (text == text_end) + text = text_end = ""; + + // Calculate length + const char* text_begin = text; + if (text_end == NULL) + text_end = text + strlen(text); // FIXME-OPT + + const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + const float wrap_pos_x = window->DC.TextWrapPos; + const bool wrap_enabled = (wrap_pos_x >= 0.0f); + if (text_end - text <= 2000 || wrap_enabled) + { + // Common case + const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f; + const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width); + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + if (!ItemAdd(bb, 0)) + return; + + // Render (we don't hide text after ## in this end-user function) + RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width); + } + else + { + // Long text! + // Perform manual coarse clipping to optimize for long multi-line text + // - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled. + // - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line. + // - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop. + const char* line = text; + const float line_height = GetTextLineHeight(); + ImVec2 text_size(0, 0); + + // Lines to skip (can't skip when logging text) + ImVec2 pos = text_pos; + if (!g.LogEnabled) + { + int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height); + if (lines_skippable > 0) + { + int lines_skipped = 0; + while (line < text_end && lines_skipped < lines_skippable) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + } + + // Lines to render + if (line < text_end) + { + ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height)); + while (line < text_end) + { + if (IsClippedEx(line_rect, 0)) + break; + + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + RenderText(pos, line, line_end, false); + line = line_end + 1; + line_rect.Min.y += line_height; + line_rect.Max.y += line_height; + pos.y += line_height; + } + + // Count remaining lines + int lines_skipped = 0; + while (line < text_end) + { + const char* line_end = (const char*)memchr(line, '\n', text_end - line); + if (!line_end) + line_end = text_end; + if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) + text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); + line = line_end + 1; + lines_skipped++; + } + pos.y += lines_skipped * line_height; + } + text_size.y = (pos - text_pos).y; + + ImRect bb(text_pos, text_pos + text_size); + ItemSize(text_size, 0.0f); + ItemAdd(bb, 0); + } +} + +void ImGui::TextUnformatted(const char* text, const char* text_end) +{ + TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::Text(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextV(fmt, args); + va_end(args); +} + +void ImGui::TextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + const char* text, *text_end; + ImFormatStringToTempBufferV(&text, &text_end, fmt, args); + TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); +} + +void ImGui::TextColored(const ImVec4& col, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextColoredV(col, fmt, args); + va_end(args); +} + +void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args) +{ + PushStyleColor(ImGuiCol_Text, col); + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextDisabled(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextDisabledV(fmt, args); + va_end(args); +} + +void ImGui::TextDisabledV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]); + TextV(fmt, args); + PopStyleColor(); +} + +void ImGui::TextWrapped(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextWrappedV(fmt, args); + va_end(args); +} + +void ImGui::TextWrappedV(const char* fmt, va_list args) +{ + ImGuiContext& g = *GImGui; + const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + if (need_backup) + PushTextWrapPos(0.0f); + TextV(fmt, args); + if (need_backup) + PopTextWrapPos(); +} + +void ImGui::LabelText(const char* label, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LabelTextV(label, fmt, args); + va_end(args); +} + +// Add a label+text combo aligned to other label+value widgets +void ImGui::LabelTextV(const char* label, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float w = CalcItemWidth(); + + const char* value_text_begin, *value_text_end; + ImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args); + const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const ImVec2 pos = window->DC.CursorPos; + const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2)); + const ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0)) + return; + + // Render + RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label); +} + +void ImGui::BulletText(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + BulletTextV(fmt, args); + va_end(args); +} + +// Text with a little bullet aligned to the typical tree node. +void ImGui::BulletTextV(const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const char* text_begin, *text_end; + ImFormatStringToTempBufferV(&text_begin, &text_end, fmt, args); + const ImVec2 label_size = CalcTextSize(text_begin, text_end, false); + const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(total_size, 0.0f); + const ImRect bb(pos, pos + total_size); + if (!ItemAdd(bb, 0)) + return; + + // Render + ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), text_col); + RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Main +//------------------------------------------------------------------------- +// - ButtonBehavior() [Internal] +// - Button() +// - SmallButton() +// - InvisibleButton() +// - ArrowButton() +// - CloseButton() [Internal] +// - CollapseButton() [Internal] +// - GetWindowScrollbarID() [Internal] +// - GetWindowScrollbarRect() [Internal] +// - Scrollbar() [Internal] +// - ScrollbarEx() [Internal] +// - Image() +// - ImageButton() +// - Checkbox() +// - CheckboxFlagsT() [Internal] +// - CheckboxFlags() +// - RadioButton() +// - ProgressBar() +// - Bullet() +//------------------------------------------------------------------------- + +// The ButtonBehavior() function is key to many interactions and used by many/most widgets. +// Because we handle so many cases (keyboard/gamepad navigation, drag and drop) and many specific behavior (via ImGuiButtonFlags_), +// this code is a little complex. +// By far the most common path is interacting with the Mouse using the default ImGuiButtonFlags_PressedOnClickRelease button behavior. +// See the series of events below and the corresponding state reported by dear imgui: +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnClickRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse is outside bb) - - - - - - +// Frame N+1 (mouse moves inside bb) - true - - - - +// Frame N+2 (mouse button is down) - true true true - true +// Frame N+3 (mouse button is down) - true true - - - +// Frame N+4 (mouse moves outside bb) - - true - - - +// Frame N+5 (mouse moves inside bb) - true true - - - +// Frame N+6 (mouse button is released) true true - - true - +// Frame N+7 (mouse button is released) - true - - - - +// Frame N+8 (mouse moves outside bb) - - - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) true true true true - true +// Frame N+3 (mouse button is down) - true true - - - +// Frame N+6 (mouse button is released) - true - - true - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+2 (mouse button is down) - true - - - true +// Frame N+3 (mouse button is down) - true - - - - +// Frame N+6 (mouse button is released) true true - - - - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// with PressedOnDoubleClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked() +// Frame N+0 (mouse button is down) - true - - - true +// Frame N+1 (mouse button is down) - true - - - - +// Frame N+2 (mouse button is released) - true - - - - +// Frame N+3 (mouse button is released) - true - - - - +// Frame N+4 (mouse button is down) true true true true - true +// Frame N+5 (mouse button is down) - true true - - - +// Frame N+6 (mouse button is released) - true - - true - +// Frame N+7 (mouse button is released) - true - - - - +//------------------------------------------------------------------------------------------------------------------------------------------------ +// Note that some combinations are supported, +// - PressedOnDragDropHold can generally be associated with any flag. +// - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported. +//------------------------------------------------------------------------------------------------------------------------------------------------ +// The behavior of the return-value changes when ImGuiButtonFlags_Repeat is set: +// Repeat+ Repeat+ Repeat+ Repeat+ +// PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick +//------------------------------------------------------------------------------------------------------------------------------------------------- +// Frame N+0 (mouse button is down) - true - true +// ... - - - - +// Frame N + RepeatDelay true true - true +// ... - - - - +// Frame N + RepeatDelay + RepeatRate*N true true - true +//------------------------------------------------------------------------------------------------------------------------------------------------- + +bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + // Default only reacts to left mouse button + if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) + flags |= ImGuiButtonFlags_MouseButtonDefault_; + + // Default behavior requires click + release inside bounding box + if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) + flags |= ImGuiButtonFlags_PressedOnDefault_; + + // Default behavior inherited from item flags + // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (flags & ImGuiButtonFlags_AllowOverlap) + item_flags |= ImGuiItemflags_AllowOverlap; + if (flags & ImGuiButtonFlags_Repeat) + item_flags |= ImGuiItemFlags_ButtonRepeat; + + ImGuiWindow* backup_hovered_window = g.HoveredWindow; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; + if (flatten_hovered_children) + g.HoveredWindow = window; + +#ifdef IMGUI_ENABLE_TEST_ENGINE + // Alternate registration spot, for when caller didn't use ItemAdd() + if (id != 0 && g.LastItemData.ID != id) + IMGUI_TEST_ENGINE_ITEM_ADD(id, bb, NULL); +#endif + + bool pressed = false; + bool hovered = ItemHoverable(bb, id, item_flags); + + // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button + if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) + if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + hovered = true; + SetHoveredID(id); + if (g.HoveredIdTimer - g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER && g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER) + { + pressed = true; + g.DragDropHoldJustPressedId = id; + FocusWindow(window); + } + } + + if (flatten_hovered_children) + g.HoveredWindow = backup_hovered_window; + + // Mouse handling + const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id; + if (hovered) + { + // Poll mouse buttons + // - 'mouse_button_clicked' is generally carried into ActiveIdMouseButton when setting ActiveId. + // - Technically we only need some values in one code path, but since this is gated by hovered test this is fine. + int mouse_button_clicked = -1; + int mouse_button_released = -1; + for (int button = 0; button < 3; button++) + if (flags & (ImGuiButtonFlags_MouseButtonLeft << button)) // Handle ImGuiButtonFlags_MouseButtonRight and ImGuiButtonFlags_MouseButtonMiddle here. + { + if (IsMouseClicked(button, test_owner_id) && mouse_button_clicked == -1) { mouse_button_clicked = button; } + if (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) { mouse_button_released = button; } + } + + // Process initial action + if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) + { + if (mouse_button_clicked != -1 && g.ActiveId != id) + { + if (!(flags & ImGuiButtonFlags_NoSetKeyOwner)) + SetKeyOwner(MouseButtonToKey(mouse_button_clicked), id); + if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere)) + { + SetActiveID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + FocusWindow(window); + } + if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2)) + { + pressed = true; + if (flags & ImGuiButtonFlags_NoHoldingActiveId) + ClearActiveID(); + else + SetActiveID(id, window); // Hold on ID + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + g.ActiveIdMouseButton = mouse_button_clicked; + FocusWindow(window); + } + } + if (flags & ImGuiButtonFlags_PressedOnRelease) + { + if (mouse_button_released != -1) + { + const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior + if (!has_repeated_at_least_once) + pressed = true; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + ClearActiveID(); + } + } + + // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). + // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. + if (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat)) + if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat)) + pressed = true; + } + + if (pressed) + g.NavDisableHighlight = true; + } + + // Gamepad/Keyboard navigation + // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse. + if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId)) + if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) + hovered = true; + if (g.NavActivateDownId == id) + { + bool nav_activated_by_code = (g.NavActivateId == id); + bool nav_activated_by_inputs = (g.NavActivatePressedId == id); + if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat)) + { + // Avoid pressing multiple keys from triggering excessive amount of repeat events + const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space); + const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_Enter); + const ImGuiKeyData* key3 = GetKeyData(ImGuiKey_NavGamepadActivate); + const float t1 = ImMax(ImMax(key1->DownDuration, key2->DownDuration), key3->DownDuration); + nav_activated_by_inputs = CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0; + } + if (nav_activated_by_code || nav_activated_by_inputs) + { + // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button. + pressed = true; + SetActiveID(id, window); + g.ActiveIdSource = g.NavInputSource; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + SetFocusID(id, window); + } + } + + // Process while held + bool held = false; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (g.ActiveIdIsJustActivated) + g.ActiveIdClickOffset = g.IO.MousePos - bb.Min; + + const int mouse_button = g.ActiveIdMouseButton; + if (mouse_button == -1) + { + // Fallback for the rare situation were g.ActiveId was set programmatically or from another widget (e.g. #6304). + ClearActiveID(); + } + else if (IsMouseDown(mouse_button, test_owner_id)) + { + held = true; + } + else + { + bool release_in = hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) != 0; + bool release_anywhere = (flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0; + if ((release_in || release_anywhere) && !g.DragDropActive) + { + // Report as pressed when releasing the mouse (this is the most common path) + bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; + bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id); + if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned) + pressed = true; + } + ClearActiveID(); + } + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + g.NavDisableHighlight = true; + } + else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + { + // When activated using Nav, we hold on the ActiveID until activation button is released + if (g.NavActivateDownId != id) + ClearActiveID(); + } + if (pressed) + g.ActiveIdHasBeenPressedBefore = true; + } + + if (out_hovered) *out_hovered = hovered; + if (out_held) *out_held = held; + + return pressed; +} + +bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + ImVec2 pos = window->DC.CursorPos; + if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag) + pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y; + ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); + + const ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); + + if (g.LogEnabled) + LogSetNextTextDecoration("[", "]"); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + + // Automatically close popups + //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + // CloseCurrentPopup(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; +} + +bool ImGui::Button(const char* label, const ImVec2& size_arg) +{ + return ButtonEx(label, size_arg, ImGuiButtonFlags_None); +} + +// Small buttons fits within text without additional vertical spacing. +bool ImGui::SmallButton(const char* label) +{ + ImGuiContext& g = *GImGui; + float backup_padding_y = g.Style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine); + g.Style.FramePadding.y = backup_padding_y; + return pressed; +} + +// Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. +// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) +bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + // Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. + IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); + + const ImGuiID id = window->GetID(str_id); + ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); + return pressed; +} + +bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiID id = window->GetID(str_id); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + const float default_size = GetFrameHeight(); + ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); + RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); + return pressed; +} + +bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) +{ + float sz = GetFrameHeight(); + return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); +} + +// Button to close a window +bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) + // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? + const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ImRect bb_interact = bb; + const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); + if (area_to_visible_ratio < 1.5f) + bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f)); + + // Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window. + // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + bool is_clipped = !ItemAdd(bb_interact, id); + + bool hovered, held; + bool pressed = ButtonBehavior(bb_interact, id, &hovered, &held); + if (is_clipped) + return pressed; + + // Render + // FIXME: Clarify this mess + ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); + ImVec2 center = bb.GetCenter(); + if (hovered) + window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col); + + float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; + ImU32 cross_col = GetColorU32(ImGuiCol_Text); + center -= ImVec2(0.5f, 0.5f); + window->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f); + window->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f); + + return pressed; +} + +bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ItemAdd(bb, id); + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); + + // Render + ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + if (hovered || held) + window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col); + RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); + + // Switch to moving the window after mouse is moved beyond the initial drag threshold + if (IsItemActive() && IsMouseDragging(0)) + StartMouseMovingWindow(window); + + return pressed; +} + +ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) +{ + return window->GetID(axis == ImGuiAxis_X ? "#SCROLLX" : "#SCROLLY"); +} + +// Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. +ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) +{ + const ImRect outer_rect = window->Rect(); + const ImRect inner_rect = window->InnerRect; + const float border_size = window->WindowBorderSize; + const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) + IM_ASSERT(scrollbar_size > 0.0f); + if (axis == ImGuiAxis_X) + return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); + else + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); +} + +void ImGui::Scrollbar(ImGuiAxis axis) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiID id = GetWindowScrollbarID(window, axis); + + // Calculate scrollbar bounding box + ImRect bb = GetWindowScrollbarRect(window, axis); + ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone; + if (axis == ImGuiAxis_X) + { + rounding_corners |= ImDrawFlags_RoundCornersBottomLeft; + if (!window->ScrollbarY) + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; + } + else + { + if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) + rounding_corners |= ImDrawFlags_RoundCornersTopRight; + if (!window->ScrollbarX) + rounding_corners |= ImDrawFlags_RoundCornersBottomRight; + } + float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; + float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; + ImS64 scroll = (ImS64)window->Scroll[axis]; + ScrollbarEx(bb, id, axis, &scroll, (ImS64)size_avail, (ImS64)size_contents, rounding_corners); + window->Scroll[axis] = (float)scroll; +} + +// Vertical/Horizontal scrollbar +// The entire piece of code below is rather confusing because: +// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab) +// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar +// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. +// Still, the code should probably be made simpler.. +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_avail_v, ImS64 size_contents_v, ImDrawFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const float bb_frame_width = bb_frame.GetWidth(); + const float bb_frame_height = bb_frame.GetHeight(); + if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f) + return false; + + // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab) + float alpha = 1.0f; + if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f) + alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if (alpha <= 0.0f) + return false; + + const ImGuiStyle& style = g.Style; + const bool allow_interaction = (alpha >= 1.0f); + + ImRect bb = bb_frame; + bb.Expand(ImVec2(-ImClamp(IM_FLOOR((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_FLOOR((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f))); + + // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar) + const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight(); + + // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount) + // But we maintain a minimum size in pixel to allow for the user to still aim inside. + IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. + const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), (ImS64)1); + const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_avail_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v); + const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). + bool held = false; + bool hovered = false; + ItemAdd(bb_frame, id, NULL, ImGuiItemFlags_NoNav); + ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + + const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_avail_v); + float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); + float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; // Grab position in normalized space + if (held && allow_interaction && grab_h_norm < 1.0f) + { + const float scrollbar_pos_v = bb.Min[axis]; + const float mouse_pos_v = g.IO.MousePos[axis]; + + // Click position in scrollbar normalized space (0.0f->1.0f) + const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v); + SetHoveredID(id); + + bool seek_absolute = false; + if (g.ActiveIdIsJustActivated) + { + // On initial click calculate the distance between mouse and the center of the grab + seek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm); + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = 0.0f; + else + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + // Apply scroll (p_scroll_v will generally point on one member of window->Scroll) + // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position + const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm)); + *p_scroll_v = (ImS64)(scroll_v_norm * scroll_max); + + // Update values for rendering + scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); + grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v; + + // Update distance to grab now that we have seeked and saturated + if (seek_absolute) + g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f; + } + + // Render + const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); + const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags); + ImRect grab_rect; + if (axis == ImGuiAxis_X) + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); + else + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels); + window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); + + return held; +} + +void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + if (border_col.w > 0.0f) + bb.Max += ImVec2(2, 2); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + return; + + if (border_col.w > 0.0f) + { + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f); + window->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col)); + } + else + { + window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col)); + } +} + +// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) +// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImVec2 padding = g.Style.FramePadding; + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2.0f); + ItemSize(bb); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); + if (bg_col.w > 0.0f) + window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); + window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + + return pressed; +} + +bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + return ImageButtonEx(window->GetID(str_id), user_texture_id, size, uv0, uv1, bg_col, tint_col); +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy API obsoleted in 1.89. Two differences with new ImageButton() +// - new ImageButton() requires an explicit 'const char* str_id' Old ImageButton() used opaque imTextureId (created issue with: multiple buttons with same image, transient texture id values, opaque computation of ID) +// - new ImageButton() always use style.FramePadding Old ImageButton() had an override argument. +// If you need to change padding with new ImageButton() you can use PushStyleVar(ImGuiStyleVar_FramePadding, value), consistent with other Button functions. +bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + // Default to using texture ID as ID. User can still push string/integer prefixes. + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + + if (frame_padding >= 0) + PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((float)frame_padding, (float)frame_padding)); + bool ret = ImageButtonEx(id, user_texture_id, size, uv0, uv1, bg_col, tint_col); + if (frame_padding >= 0) + PopStyleVar(); + return ret; +} +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +bool ImGui::Checkbox(const char* label, bool* v) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + { + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return false; + } + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + { + *v = !(*v); + MarkItemEdited(id); + } + + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + RenderNavHighlight(total_bb, id); + RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); + bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + if (mixed_value) + { + // Undocumented tristate/mixed/indeterminate checkbox (#2644) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) + ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); + window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); + } + else if (*v) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + if (g.LogEnabled) + LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + if (label_size.x > 0.0f) + RenderText(label_pos, label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; +} + +template +bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value) +{ + bool all_on = (*flags & flags_value) == flags_value; + bool any_on = (*flags & flags_value) != 0; + bool pressed; + if (!all_on && any_on) + { + ImGuiContext& g = *GImGui; + g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue; + pressed = Checkbox(label, &all_on); + } + else + { + pressed = Checkbox(label, &all_on); + + } + if (pressed) + { + if (all_on) + *flags |= flags_value; + else + *flags &= ~flags_value; + } + return pressed; +} + +bool ImGui::CheckboxFlags(const char* label, int* flags, int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value) +{ + return CheckboxFlagsT(label, flags, flags_value); +} + +bool ImGui::RadioButton(const char* label, bool active) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id)) + return false; + + ImVec2 center = check_bb.GetCenter(); + center.x = IM_ROUND(center.x); + center.y = IM_ROUND(center.y); + const float radius = (square_sz - 1.0f) * 0.5f; + + bool hovered, held; + bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) + MarkItemEdited(id); + + RenderNavHighlight(total_bb, id); + const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); + window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); + if (active) + { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark)); + } + + if (style.FrameBorderSize > 0.0f) + { + window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize); + window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + if (g.LogEnabled) + LogRenderedText(&label_pos, active ? "(x)" : "( )"); + if (label_size.x > 0.0f) + RenderText(label_pos, label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; +} + +// FIXME: This would work nicely if it was a public template, e.g. 'template RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it.. +bool ImGui::RadioButton(const char* label, int* v, int v_button) +{ + const bool pressed = RadioButton(label, *v == v_button); + if (pressed) + *v = v_button; + return pressed; +} + +// size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size +void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + ImVec2 pos = window->DC.CursorPos; + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0f); + ImRect bb(pos, pos + size); + ItemSize(size, style.FramePadding.y); + if (!ItemAdd(bb, 0)) + return; + + // Render + fraction = ImSaturate(fraction); + RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize)); + const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y); + RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding); + + // Default displaying the fraction as percentage string, but user can override it + char overlay_buf[32]; + if (!overlay) + { + ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f); + overlay = overlay_buf; + } + + ImVec2 overlay_size = CalcTextSize(overlay, NULL); + if (overlay_size.x > 0.0f) + RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb); +} + +void ImGui::Bullet() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); + ItemSize(bb); + if (!ItemAdd(bb, 0)) + { + SameLine(0, style.FramePadding.x * 2); + return; + } + + // Render and stay on same line + ImU32 text_col = GetColorU32(ImGuiCol_Text); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, line_height * 0.5f), text_col); + SameLine(0, style.FramePadding.x * 2.0f); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Low-level Layout helpers +//------------------------------------------------------------------------- +// - Spacing() +// - Dummy() +// - NewLine() +// - AlignTextToFramePadding() +// - SeparatorEx() [Internal] +// - Separator() +// - SplitterBehavior() [Internal] +// - ShrinkWidths() [Internal] +//------------------------------------------------------------------------- + +void ImGui::Spacing() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ItemSize(ImVec2(0, 0)); +} + +void ImGui::Dummy(const ImVec2& size) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(size); + ItemAdd(bb, 0); +} + +void ImGui::NewLine() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + const ImGuiLayoutType backup_layout_type = window->DC.LayoutType; + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.IsSameLine = false; + if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. + ItemSize(ImVec2(0, 0)); + else + ItemSize(ImVec2(0.0f, g.FontSize)); + window->DC.LayoutType = backup_layout_type; +} + +void ImGui::AlignTextToFramePadding() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y); +} + +// Horizontal/vertical separating line +// FIXME: Surprisingly, this seemingly trivial widget is a victim of many different legacy/tricky layout issues. +// Note how thickness == 1.0f is handled specifically as not moving CursorPos by 'thickness', but other values are. +void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + ImGuiContext& g = *GImGui; + IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected + IM_ASSERT(thickness > 0.0f); + + if (flags & ImGuiSeparatorFlags_Vertical) + { + // Vertical separator, for menu bars (use current line height). + float y1 = window->DC.CursorPos.y; + float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2)); + ItemSize(ImVec2(thickness, 0.0f)); + if (!ItemAdd(bb, 0)) + return; + + // Draw + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogText(" |"); + } + else if (flags & ImGuiSeparatorFlags_Horizontal) + { + // Horizontal Separator + float x1 = window->Pos.x; + float x2 = window->Pos.x + window->Size.x; + + // FIXME-WORKRECT: old hack (#205) until we decide of consistent behavior with WorkRect/Indent and Separator + if (g.GroupStack.Size > 0 && g.GroupStack.back().WindowID == window->ID) + x1 += window->DC.Indent.x; + + // FIXME-WORKRECT: In theory we should simply be using WorkRect.Min.x/Max.x everywhere but it isn't aesthetically what we want, + // need to introduce a variant of WorkRect for that purpose. (#4787) + if (ImGuiTable* table = g.CurrentTable) + { + x1 = table->Columns[table->CurrentColumn].MinX; + x2 = table->Columns[table->CurrentColumn].MaxX; + } + + // Before Tables API happened, we relied on Separator() to span all columns of a Columns() set. + // We currently don't need to provide the same feature for tables because tables naturally have border features. + ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; + if (columns) + PushColumnsBackground(); + + // We don't provide our width to the layout so that it doesn't get feed back into AutoFit + // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) + const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); + ItemSize(ImVec2(0.0f, thickness_for_layout)); + + if (ItemAdd(bb, 0)) + { + // Draw + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); + if (g.LogEnabled) + LogRenderedText(&bb.Min, "--------------------------------\n"); + + } + if (columns) + { + PopColumnsBackground(); + columns->LineMinY = window->DC.CursorPos.y; + } + } +} + +void ImGui::Separator() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + // Those flags should eventually be configurable by the user + // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f. + ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; + flags |= ImGuiSeparatorFlags_SpanAllColumns; // NB: this only applies to legacy Columns() api as they relied on Separator() a lot. + SeparatorEx(flags, 1.0f); +} + +void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStyle& style = g.Style; + + const ImVec2 label_size = CalcTextSize(label, label_end, false); + const ImVec2 pos = window->DC.CursorPos; + const ImVec2 padding = style.SeparatorTextPadding; + + const float separator_thickness = style.SeparatorTextBorderSize; + const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); + const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); + const float text_baseline_y = ImFloor((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); + ItemSize(min_size, text_baseline_y); + if (!ItemAdd(bb, id)) + return; + + const float sep1_x1 = pos.x; + const float sep2_x2 = bb.Max.x; + const float seps_y = ImFloor((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f); + + const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); + const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN + + // This allows using SameLine() to position something in the 'extra_w' + window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x; + + const ImU32 separator_col = GetColorU32(ImGuiCol_Separator); + if (label_size.x > 0.0f) + { + const float sep1_x2 = label_pos.x - style.ItemSpacing.x; + const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x; + if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness); + if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + if (g.LogEnabled) + LogSetNextTextDecoration("---", NULL); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size); + } + else + { + if (g.LogEnabled) + LogText("---"); + if (separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + } +} + +void ImGui::SeparatorText(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + // The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want: + // - allow separator-text to be draggable items (would require a stable ID + a noticeable highlight) + // - this high-level entry point to allow formatting? (which in turns may require ID separate from formatted string) + // - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...' + // Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item, + // and then we can turn this into a format function. + SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f); +} + +// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. +bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + if (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav)) + return false; + + // FIXME: AFAIK the only leftover reason for passing ImGuiButtonFlags_AllowOverlap here is + // to allow caller of SplitterBehavior() to call SetItemAllowOverlap() after the item. + // Nowadays we would instead want to use SetNextItemAllowOverlap() before the item. + ImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + button_flags |= ImGuiButtonFlags_AllowOverlap; +#endif + + bool hovered, held; + ImRect bb_interact = bb; + bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f)); + ButtonBehavior(bb_interact, id, &hovered, &held, button_flags); + if (hovered) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb + + if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay)) + SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW); + + ImRect bb_render = bb; + if (held) + { + ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min; + float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x; + + // Minimum pane size + float size_1_maximum_delta = ImMax(0.0f, *size1 - min_size1); + float size_2_maximum_delta = ImMax(0.0f, *size2 - min_size2); + if (mouse_delta < -size_1_maximum_delta) + mouse_delta = -size_1_maximum_delta; + if (mouse_delta > size_2_maximum_delta) + mouse_delta = size_2_maximum_delta; + + // Apply resize + if (mouse_delta != 0.0f) + { + if (mouse_delta < 0.0f) + IM_ASSERT(*size1 + mouse_delta >= min_size1); + if (mouse_delta > 0.0f) + IM_ASSERT(*size2 - mouse_delta >= min_size2); + *size1 += mouse_delta; + *size2 -= mouse_delta; + bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta)); + MarkItemEdited(id); + } + } + + // Render at new position + if (bg_col & IM_COL32_A_MASK) + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0f); + const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered && g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator); + window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f); + + return held; +} + +static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs) +{ + const ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs; + const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs; + if (int d = (int)(b->Width - a->Width)) + return d; + return (b->Index - a->Index); +} + +// Shrink excess width from a set of item, by removing width from the larger items first. +// Set items Width to -1.0f to disable shrinking this item. +void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess) +{ + if (count == 1) + { + if (items[0].Width >= 0.0f) + items[0].Width = ImMax(items[0].Width - width_excess, 1.0f); + return; + } + ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer); + int count_same_width = 1; + while (width_excess > 0.0f && count_same_width < count) + { + while (count_same_width < count && items[0].Width <= items[count_same_width].Width) + count_same_width++; + float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f); + if (max_width_to_remove_per_item <= 0.0f) + break; + float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item); + for (int item_n = 0; item_n < count_same_width; item_n++) + items[item_n].Width -= width_to_remove_per_item; + width_excess -= width_to_remove_per_item * count_same_width; + } + + // Round width and redistribute remainder + // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator. + width_excess = 0.0f; + for (int n = 0; n < count; n++) + { + float width_rounded = ImFloor(items[n].Width); + width_excess += items[n].Width - width_rounded; + items[n].Width = width_rounded; + } + while (width_excess > 0.0f) + for (int n = 0; n < count && width_excess > 0.0f; n++) + { + float width_to_add = ImMin(items[n].InitialWidth - items[n].Width, 1.0f); + items[n].Width += width_to_add; + width_excess -= width_to_add; + } +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ComboBox +//------------------------------------------------------------------------- +// - CalcMaxPopupHeightFromItemCount() [Internal] +// - BeginCombo() +// - BeginComboPopup() [Internal] +// - EndCombo() +// - BeginComboPreview() [Internal] +// - EndComboPreview() [Internal] +// - Combo() +//------------------------------------------------------------------------- + +static float CalcMaxPopupHeightFromItemCount(int items_count) +{ + ImGuiContext& g = *GImGui; + if (items_count <= 0) + return FLT_MAX; + return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); +} + +bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + + ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags; + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together + + const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight(); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth(); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &bb)) + return false; + + // Open on click + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + const ImGuiID popup_id = ImHashStr("##ComboPopup", 0, id); + bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None); + if (pressed && !popup_open) + { + OpenPopupEx(popup_id, ImGuiPopupFlags_None); + popup_open = true; + } + + // Render shape + const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); + RenderNavHighlight(bb, id); + if (!(flags & ImGuiComboFlags_NoPreview)) + window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); + if (!(flags & ImGuiComboFlags_NoArrowButton)) + { + ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + ImU32 text_col = GetColorU32(ImGuiCol_Text); + window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); + if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x) + RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + } + RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); + + // Custom preview + if (flags & ImGuiComboFlags_CustomPreview) + { + g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y); + IM_ASSERT(preview_value == NULL || preview_value[0] == 0); + preview_value = NULL; + } + + // Render preview and label + if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) + { + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL); + } + if (label_size.x > 0) + RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label); + + if (!popup_open) + return false; + + g.NextWindowData.Flags = backup_next_window_data_flags; + return BeginComboPopup(popup_id, bb, flags); +} + +bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); + return false; + } + + // Set popup size + float w = bb.GetWidth(); + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + { + g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); + } + else + { + if ((flags & ImGuiComboFlags_HeightMask_) == 0) + flags |= ImGuiComboFlags_HeightRegular; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_)); // Only one + int popup_max_height_in_items = -1; + if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8; + else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; + else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; + ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX); + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size + constraint_min.x = w; + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f) + constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items); + SetNextWindowSizeConstraints(constraint_min, constraint_max); + } + + // This is essentially a specialized version of BeginPopupEx() + char name[16]; + ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth + + // Set position given a custom constraint (peak into expected window size so we can position it) + // FIXME: This might be easier to express with an hypothetical SetNextWindowPosConstraints() function? + // FIXME: This might be moved to Begin() or at least around the same spot where Tooltips and other Popups are calling FindBestWindowPosForPopupEx()? + if (ImGuiWindow* popup_window = FindWindowByName(name)) + if (popup_window->WasActive) + { + // Always override 'AutoPosLastDirection' to not leave a chance for a past value to affect us. + ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window); + popup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down; // Left = "Below, Toward Left", Down = "Below, Toward Right (default)" + ImRect r_outer = GetPopupAllowedExtentRect(popup_window); + ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox); + SetNextWindowPos(pos); + } + + // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() + ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text + bool ret = Begin(name, NULL, window_flags); + PopStyleVar(); + if (!ret) + { + EndPopup(); + IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above + return false; + } + return true; +} + +void ImGui::EndCombo() +{ + EndPopup(); +} + +// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements +// (Experimental, see GitHub issues: #1658, #4168) +bool ImGui::BeginComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + if (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)) + return false; + IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag? + if (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional) + return false; + + // FIXME: This could be contained in a PushWorkRect() api + preview_data->BackupCursorPos = window->DC.CursorPos; + preview_data->BackupCursorMaxPos = window->DC.CursorMaxPos; + preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine; + preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + preview_data->BackupLayout = window->DC.LayoutType; + window->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding; + window->DC.CursorMaxPos = window->DC.CursorPos; + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.IsSameLine = false; + PushClipRect(preview_data->PreviewRect.Min, preview_data->PreviewRect.Max, true); + + return true; +} + +void ImGui::EndComboPreview() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiComboPreviewData* preview_data = &g.ComboPreviewData; + + // FIXME: Using CursorMaxPos approximation instead of correct AABB which we will store in ImDrawCmd in the future + ImDrawList* draw_list = window->DrawList; + if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y) + if (draw_list->CmdBuffer.Size > 1) // Unlikely case that the PushClipRect() didn't create a command + { + draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect; + draw_list->_TryMergeDrawCmds(); + } + PopClipRect(); + window->DC.CursorPos = preview_data->BackupCursorPos; + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); + window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine; + window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset; + window->DC.LayoutType = preview_data->BackupLayout; + window->DC.IsSameLine = false; + preview_data->PreviewRect = ImRect(); +} + +// Getter for the old Combo() API: const char*[] +static bool Items_ArrayGetter(void* data, int idx, const char** out_text) +{ + const char* const* items = (const char* const*)data; + if (out_text) + *out_text = items[idx]; + return true; +} + +// Getter for the old Combo() API: "item1\0item2\0item3\0" +static bool Items_SingleStringGetter(void* data, int idx, const char** out_text) +{ + // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited. + const char* items_separated_by_zeros = (const char*)data; + int items_count = 0; + const char* p = items_separated_by_zeros; + while (*p) + { + if (idx == items_count) + break; + p += strlen(p) + 1; + items_count++; + } + if (!*p) + return false; + if (out_text) + *out_text = p; + return true; +} + +// Old API, prefer using BeginCombo() nowadays if you can. +bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items) +{ + ImGuiContext& g = *GImGui; + + // Call the getter to obtain the preview string which is a parameter to BeginCombo() + const char* preview_value = NULL; + if (*current_item >= 0 && *current_item < items_count) + items_getter(data, *current_item, &preview_value); + + // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. + if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)) + SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); + + if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) + return false; + + // Display items + // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed) + bool value_changed = false; + for (int i = 0; i < items_count; i++) + { + PushID(i); + const bool item_selected = (i == *current_item); + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + if (Selectable(item_text, item_selected) && *current_item != i) + { + value_changed = true; + *current_item = i; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + + EndCombo(); + + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +// Combo box helper allowing to pass an array of strings. +bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items) +{ + const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items); + return value_changed; +} + +// Combo box helper allowing to pass all items in a single string literal holding multiple zero-terminated items "item1\0item2\0" +bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items) +{ + int items_count = 0; + const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open + while (*p) + { + p += strlen(p) + 1; + items_count++; + } + bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Data Type and Data Formatting Helpers [Internal] +//------------------------------------------------------------------------- +// - DataTypeGetInfo() +// - DataTypeFormatString() +// - DataTypeApplyOp() +// - DataTypeApplyOpFromText() +// - DataTypeCompare() +// - DataTypeClamp() +// - GetMinimumStepAtDecimalPrecision +// - RoundScalarWithFormat<>() +//------------------------------------------------------------------------- + +static const ImGuiDataTypeInfo GDataTypeInfo[] = +{ + { sizeof(char), "S8", "%d", "%d" }, // ImGuiDataType_S8 + { sizeof(unsigned char), "U8", "%u", "%u" }, + { sizeof(short), "S16", "%d", "%d" }, // ImGuiDataType_S16 + { sizeof(unsigned short), "U16", "%u", "%u" }, + { sizeof(int), "S32", "%d", "%d" }, // ImGuiDataType_S32 + { sizeof(unsigned int), "U32", "%u", "%u" }, +#ifdef _MSC_VER + { sizeof(ImS64), "S64", "%I64d","%I64d" }, // ImGuiDataType_S64 + { sizeof(ImU64), "U64", "%I64u","%I64u" }, +#else + { sizeof(ImS64), "S64", "%lld", "%lld" }, // ImGuiDataType_S64 + { sizeof(ImU64), "U64", "%llu", "%llu" }, +#endif + { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) + { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double +}; +IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); + +const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type) +{ + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + return &GDataTypeInfo[data_type]; +} + +int ImGui::DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format) +{ + // Signedness doesn't matter when pushing integer arguments + if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) + return ImFormatString(buf, buf_size, format, *(const ImU32*)p_data); + if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) + return ImFormatString(buf, buf_size, format, *(const ImU64*)p_data); + if (data_type == ImGuiDataType_Float) + return ImFormatString(buf, buf_size, format, *(const float*)p_data); + if (data_type == ImGuiDataType_Double) + return ImFormatString(buf, buf_size, format, *(const double*)p_data); + if (data_type == ImGuiDataType_S8) + return ImFormatString(buf, buf_size, format, *(const ImS8*)p_data); + if (data_type == ImGuiDataType_U8) + return ImFormatString(buf, buf_size, format, *(const ImU8*)p_data); + if (data_type == ImGuiDataType_S16) + return ImFormatString(buf, buf_size, format, *(const ImS16*)p_data); + if (data_type == ImGuiDataType_U16) + return ImFormatString(buf, buf_size, format, *(const ImU16*)p_data); + IM_ASSERT(0); + return 0; +} + +void ImGui::DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg1, const void* arg2) +{ + IM_ASSERT(op == '+' || op == '-'); + switch (data_type) + { + case ImGuiDataType_S8: + if (op == '+') { *(ImS8*)output = ImAddClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + if (op == '-') { *(ImS8*)output = ImSubClampOverflow(*(const ImS8*)arg1, *(const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); } + return; + case ImGuiDataType_U8: + if (op == '+') { *(ImU8*)output = ImAddClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + if (op == '-') { *(ImU8*)output = ImSubClampOverflow(*(const ImU8*)arg1, *(const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); } + return; + case ImGuiDataType_S16: + if (op == '+') { *(ImS16*)output = ImAddClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + if (op == '-') { *(ImS16*)output = ImSubClampOverflow(*(const ImS16*)arg1, *(const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); } + return; + case ImGuiDataType_U16: + if (op == '+') { *(ImU16*)output = ImAddClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + if (op == '-') { *(ImU16*)output = ImSubClampOverflow(*(const ImU16*)arg1, *(const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); } + return; + case ImGuiDataType_S32: + if (op == '+') { *(ImS32*)output = ImAddClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + if (op == '-') { *(ImS32*)output = ImSubClampOverflow(*(const ImS32*)arg1, *(const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); } + return; + case ImGuiDataType_U32: + if (op == '+') { *(ImU32*)output = ImAddClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + if (op == '-') { *(ImU32*)output = ImSubClampOverflow(*(const ImU32*)arg1, *(const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); } + return; + case ImGuiDataType_S64: + if (op == '+') { *(ImS64*)output = ImAddClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + if (op == '-') { *(ImS64*)output = ImSubClampOverflow(*(const ImS64*)arg1, *(const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); } + return; + case ImGuiDataType_U64: + if (op == '+') { *(ImU64*)output = ImAddClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + if (op == '-') { *(ImU64*)output = ImSubClampOverflow(*(const ImU64*)arg1, *(const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); } + return; + case ImGuiDataType_Float: + if (op == '+') { *(float*)output = *(const float*)arg1 + *(const float*)arg2; } + if (op == '-') { *(float*)output = *(const float*)arg1 - *(const float*)arg2; } + return; + case ImGuiDataType_Double: + if (op == '+') { *(double*)output = *(const double*)arg1 + *(const double*)arg2; } + if (op == '-') { *(double*)output = *(const double*)arg1 - *(const double*)arg2; } + return; + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); +} + +// User can input math operators (e.g. +100) to edit a numerical values. +// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. +bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format) +{ + while (ImCharIsBlankA(*buf)) + buf++; + if (!buf[0]) + return false; + + // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, type_info->Size); + + // Sanitize format + // - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf + // - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %. + char format_sanitized[32]; + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + format = type_info->ScanFmt; + else + format = ImParseFormatSanitizeForScanning(format, format_sanitized, IM_ARRAYSIZE(format_sanitized)); + + // Small types need a 32-bit buffer to receive the result from scanf() + int v32 = 0; + if (sscanf(buf, format, type_info->Size >= 4 ? p_data : &v32) < 1) + return false; + if (type_info->Size < 4) + { + if (data_type == ImGuiDataType_S8) + *(ImS8*)p_data = (ImS8)ImClamp(v32, (int)IM_S8_MIN, (int)IM_S8_MAX); + else if (data_type == ImGuiDataType_U8) + *(ImU8*)p_data = (ImU8)ImClamp(v32, (int)IM_U8_MIN, (int)IM_U8_MAX); + else if (data_type == ImGuiDataType_S16) + *(ImS16*)p_data = (ImS16)ImClamp(v32, (int)IM_S16_MIN, (int)IM_S16_MAX); + else if (data_type == ImGuiDataType_U16) + *(ImU16*)p_data = (ImU16)ImClamp(v32, (int)IM_U16_MIN, (int)IM_U16_MAX); + else + IM_ASSERT(0); + } + + return memcmp(&data_backup, p_data, type_info->Size) != 0; +} + +template +static int DataTypeCompareT(const T* lhs, const T* rhs) +{ + if (*lhs < *rhs) return -1; + if (*lhs > *rhs) return +1; + return 0; +} + +int ImGui::DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2) +{ + switch (data_type) + { + case ImGuiDataType_S8: return DataTypeCompareT((const ImS8* )arg_1, (const ImS8* )arg_2); + case ImGuiDataType_U8: return DataTypeCompareT((const ImU8* )arg_1, (const ImU8* )arg_2); + case ImGuiDataType_S16: return DataTypeCompareT((const ImS16* )arg_1, (const ImS16* )arg_2); + case ImGuiDataType_U16: return DataTypeCompareT((const ImU16* )arg_1, (const ImU16* )arg_2); + case ImGuiDataType_S32: return DataTypeCompareT((const ImS32* )arg_1, (const ImS32* )arg_2); + case ImGuiDataType_U32: return DataTypeCompareT((const ImU32* )arg_1, (const ImU32* )arg_2); + case ImGuiDataType_S64: return DataTypeCompareT((const ImS64* )arg_1, (const ImS64* )arg_2); + case ImGuiDataType_U64: return DataTypeCompareT((const ImU64* )arg_1, (const ImU64* )arg_2); + case ImGuiDataType_Float: return DataTypeCompareT((const float* )arg_1, (const float* )arg_2); + case ImGuiDataType_Double: return DataTypeCompareT((const double*)arg_1, (const double*)arg_2); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return 0; +} + +template +static bool DataTypeClampT(T* v, const T* v_min, const T* v_max) +{ + // Clamp, both sides are optional, return true if modified + if (v_min && *v < *v_min) { *v = *v_min; return true; } + if (v_max && *v > *v_max) { *v = *v_max; return true; } + return false; +} + +bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max) +{ + switch (data_type) + { + case ImGuiDataType_S8: return DataTypeClampT((ImS8* )p_data, (const ImS8* )p_min, (const ImS8* )p_max); + case ImGuiDataType_U8: return DataTypeClampT((ImU8* )p_data, (const ImU8* )p_min, (const ImU8* )p_max); + case ImGuiDataType_S16: return DataTypeClampT((ImS16* )p_data, (const ImS16* )p_min, (const ImS16* )p_max); + case ImGuiDataType_U16: return DataTypeClampT((ImU16* )p_data, (const ImU16* )p_min, (const ImU16* )p_max); + case ImGuiDataType_S32: return DataTypeClampT((ImS32* )p_data, (const ImS32* )p_min, (const ImS32* )p_max); + case ImGuiDataType_U32: return DataTypeClampT((ImU32* )p_data, (const ImU32* )p_min, (const ImU32* )p_max); + case ImGuiDataType_S64: return DataTypeClampT((ImS64* )p_data, (const ImS64* )p_min, (const ImS64* )p_max); + case ImGuiDataType_U64: return DataTypeClampT((ImU64* )p_data, (const ImU64* )p_min, (const ImU64* )p_max); + case ImGuiDataType_Float: return DataTypeClampT((float* )p_data, (const float* )p_min, (const float* )p_max); + case ImGuiDataType_Double: return DataTypeClampT((double*)p_data, (const double*)p_min, (const double*)p_max); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +static float GetMinimumStepAtDecimalPrecision(int decimal_precision) +{ + static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; + if (decimal_precision < 0) + return FLT_MIN; + return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); +} + +template +TYPE ImGui::RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, TYPE v) +{ + IM_UNUSED(data_type); + IM_ASSERT(data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); + const char* fmt_start = ImParseFormatFindStart(format); + if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string + return v; + + // Sanitize format + char fmt_sanitized[32]; + ImParseFormatSanitizeForPrinting(fmt_start, fmt_sanitized, IM_ARRAYSIZE(fmt_sanitized)); + fmt_start = fmt_sanitized; + + // Format value with our rounding, and read back + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + const char* p = v_str; + while (*p == ' ') + p++; + v = (TYPE)ImAtof(p); + + return v; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: DragScalar, DragFloat, DragInt, etc. +//------------------------------------------------------------------------- +// - DragBehaviorT<>() [Internal] +// - DragBehavior() [Internal] +// - DragScalar() +// - DragScalarN() +// - DragFloat() +// - DragFloat2() +// - DragFloat3() +// - DragFloat4() +// - DragFloatRange2() +// - DragInt() +// - DragInt2() +// - DragInt3() +// - DragInt4() +// - DragIntRange2() +//------------------------------------------------------------------------- + +// This is called by DragBehavior() when the widget is active (held by mouse or being manipulated with Nav controls) +template +bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiContext& g = *GImGui; + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_clamped = (v_min < v_max); + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + + // Default tweak speed + if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX)) + v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); + + // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings + float adjust_delta = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + { + adjust_delta = g.IO.MouseDelta[axis]; + if (g.IO.KeyAlt) + adjust_delta *= 1.0f / 100.0f; + if (g.IO.KeyShift) + adjust_delta *= 10.0f; + } + else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + { + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; + const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); + const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); + const float tweak_factor = tweak_slow ? 1.0f / 1.0f : tweak_fast ? 10.0f : 1.0f; + adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor; + v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); + } + adjust_delta *= v_speed; + + // For vertical drag we currently assume that Up=higher value (like we do with vertical sliders). This may become a parameter. + if (axis == ImGuiAxis_Y) + adjust_delta = -adjust_delta; + + // For logarithmic use our range is effectively 0..1 so scale the delta into that range + if (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f)) // Epsilon to avoid /0 + adjust_delta /= (float)(v_max - v_min); + + // Clear current value on activation + // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. + bool is_just_activated = g.ActiveIdIsJustActivated; + bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + if (is_just_activated || is_already_past_limits_and_pushing_outward) + { + g.DragCurrentAccum = 0.0f; + g.DragCurrentAccumDirty = false; + } + else if (adjust_delta != 0.0f) + { + g.DragCurrentAccum += adjust_delta; + g.DragCurrentAccumDirty = true; + } + + if (!g.DragCurrentAccumDirty) + return false; + + TYPE v_cur = *v; + FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; + + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + const float zero_deadzone_halfsize = 0.0f; // Drag widgets have no deadzone (as it doesn't make sense) + if (is_logarithmic) + { + // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + + // Convert to parametric space, apply delta, convert back + float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_new_parametric = v_old_parametric + g.DragCurrentAccum; + v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + v_old_ref_for_accum_remainder = v_old_parametric; + } + else + { + v_cur += (SIGNEDTYPE)g.DragCurrentAccum; + } + + // Round to user desired precision based on format string + if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_cur = RoundScalarWithFormatT(format, data_type, v_cur); + + // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. + g.DragCurrentAccumDirty = false; + if (is_logarithmic) + { + // Convert to parametric space, apply delta, convert back + float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); + } + else + { + g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v); + } + + // Lose zero sign for float/double + if (v_cur == (TYPE)-0) + v_cur = (TYPE)0; + + // Clamp values (+ handle overflow/wrap-around for integer types) + if (*v != v_cur && is_clamped) + { + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point)) + v_cur = v_max; + } + + // Apply result + if (*v == v_cur) + return false; + *v = v_cur; + return true; +} + +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + { + // Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation. + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (g.ActiveId != id) + return false; + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + return false; + + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX, format, flags); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX, format, flags); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = DragBehaviorT(ImGuiDataType_S32, &v32, v_speed, p_min ? *(const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX, format, flags); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = DragBehaviorT(ImGuiDataType_U32, &v32, v_speed, p_min ? *(const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX, format, flags); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)p_v, v_speed, p_min ? *(const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX, format, flags); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)p_v, v_speed, p_min ? *(const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX, format, flags); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)p_v, v_speed, p_min ? *(const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX, format, flags); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)p_v, v_speed, p_min ? *(const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX, format, flags); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)p_v, v_speed, p_min ? *(const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX, format, flags); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)p_v, v_speed, p_min ? *(const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX, format, flags); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. +// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) + { + // Tabbing or CTRL-clicking on Drag turns it into an InputText + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = hovered && IsMouseClicked(0, id); + const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id)); + const bool make_active = (input_requested_by_tabbing || clicked || double_clicked || g.NavActivateId == id); + if (make_active && (clicked || double_clicked)) + SetKeyOwner(ImGuiKey_MouseLeft, id); + if (make_active && temp_input_allowed) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || double_clicked || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + temp_input_is_active = true; + + // (Optional) simple click (without moving) turns Drag into an InputText + if (g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active) + if (g.ActiveId == id && hovered && g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) + { + g.NavActivateId = id; + g.NavActivateFlags = ImGuiActivateFlags_PreferInput; + temp_input_is_active = true; + } + + if (make_active && !temp_input_is_active) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + } + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0 && (p_min == NULL || p_max == NULL || DataTypeCompare(data_type, p_min, p_max) < 0); + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + + // Drag behavior + const bool value_changed = DragBehavior(id, data_type, p_data, v_speed, p_min, p_max, format, flags); + if (value_changed) + MarkItemEdited(id); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); + return value_changed; +} + +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= DragScalar("", data_type, p_data, v_speed, p_min, p_max, format, flags); + PopID(); + PopItemWidth(); + p_data = (void*)((char*)p_data + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags); +} + +// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. +bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2, CalcItemWidth()); + + float min_min = (v_min >= v_max) ? -FLT_MAX : v_min; + float min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); + ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); + bool value_changed = DragScalar("##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + float max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); + float max_max = (v_min >= v_max) ? FLT_MAX : v_max; + ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); + value_changed |= DragScalar("##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max : format, max_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + + return value_changed; +} + +// NB: v_speed is float to allow adjusting the drag speed with more precision +bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags); +} + +bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags); +} + +// NB: You likely want to specify the ImGuiSliderFlags_AlwaysClamp when using this. +bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + PushID(label); + BeginGroup(); + PushMultiItemsWidths(2, CalcItemWidth()); + + int min_min = (v_min >= v_max) ? INT_MIN : v_min; + int min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max); + ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0); + bool value_changed = DragInt("##min", v_current_min, v_speed, min_min, min_max, format, min_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + int max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min); + int max_max = (v_min >= v_max) ? INT_MAX : v_max; + ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0); + value_changed |= DragInt("##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max : format, max_flags); + PopItemWidth(); + SameLine(0, g.Style.ItemInnerSpacing.x); + + TextEx(label, FindRenderedTextEnd(label)); + EndGroup(); + PopID(); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc. +//------------------------------------------------------------------------- +// - ScaleRatioFromValueT<> [Internal] +// - ScaleValueFromRatioT<> [Internal] +// - SliderBehaviorT<>() [Internal] +// - SliderBehavior() [Internal] +// - SliderScalar() +// - SliderScalarN() +// - SliderFloat() +// - SliderFloat2() +// - SliderFloat3() +// - SliderFloat4() +// - SliderAngle() +// - SliderInt() +// - SliderInt2() +// - SliderInt3() +// - SliderInt4() +// - VSliderScalar() +// - VSliderFloat() +// - VSliderInt() +//------------------------------------------------------------------------- + +// Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) +template +float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +{ + if (v_min == v_max) + return 0.0f; + IM_UNUSED(data_type); + + const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); + if (is_logarithmic) + { + bool flipped = v_max < v_min; + + if (flipped) // Handle the case where the range is backwards + ImSwap(v_min, v_max); + + // Fudge min/max to avoid getting close to log(0) + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + + // Awkward special cases - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + if ((v_min == 0.0f) && (v_max < 0.0f)) + v_min_fudged = -logarithmic_zero_epsilon; + else if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float result; + if (v_clamped <= v_min_fudged) + result = 0.0f; // Workaround for values that are in-range but below our fudge + else if (v_clamped >= v_max_fudged) + result = 1.0f; // Workaround for values that are in-range but above our fudge + else if ((v_min * v_max) < 0.0f) // Range crosses zero, so split into two portions + { + float zero_point_center = (-(float)v_min) / ((float)v_max - (float)v_min); // The zero point in parametric space. There's an argument we should take the logarithmic nature into account when calculating this, but for now this should do (and the most common case of a symmetrical range works fine) + float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; + float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; + if (v == 0.0f) + result = zero_point_center; // Special case for exactly zero + else if (v < 0.0f) + result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L; + else + result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R)); + } + else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider + result = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged)); + else + result = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged)); + + return flipped ? (1.0f - result) : result; + } + else + { + // Linear slider + return (float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min)); + } +} + +// Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) +template +TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +{ + // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" + // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. + if (t <= 0.0f || v_min == v_max) + return v_min; + if (t >= 1.0f) + return v_max; + + TYPE result = (TYPE)0; + if (is_logarithmic) + { + // Fudge min/max to avoid getting silly results close to zero + FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; + FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max; + + const bool flipped = v_max < v_min; // Check if range is "backwards" + if (flipped) + ImSwap(v_min_fudged, v_max_fudged); + + // Awkward special case - we need ranges of the form (-100 .. 0) to convert to (-100 .. -epsilon), not (-100 .. epsilon) + if ((v_max == 0.0f) && (v_min < 0.0f)) + v_max_fudged = -logarithmic_zero_epsilon; + + float t_with_flip = flipped ? (1.0f - t) : t; // t, but flipped if necessary to account for us flipping the range + + if ((v_min * v_max) < 0.0f) // Range crosses zero, so we have to do this in two parts + { + float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((float)v_max - (float)v_min); // The zero point in parametric space + float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize; + float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize; + if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R) + result = (TYPE)0.0f; // Special case to make getting exactly zero possible (the epsilon prevents it otherwise) + else if (t_with_flip < zero_point_center) + result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L)))); + else + result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R)))); + } + else if ((v_min < 0.0f) || (v_max < 0.0f)) // Entirely negative slider + result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip))); + else + result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip)); + } + else + { + // Linear slider + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + if (is_floating_point) + { + result = ImLerp(v_min, v_max, t); + } + else if (t < 1.0) + { + // - For integer values we want the clicking position to match the grab box so we round above + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. + // - Not doing a *1.0 multiply at the end of a range as it tends to be lossy. While absolute aiming at a large s64/u64 + // range is going to be imprecise anyway, with this check we at least make the edge values matches expected limits. + FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) * t; + result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5))); + } + } + + return result; +} + +// FIXME: Try to move more of the code into shared SliderBehavior() +template +bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; + const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; + const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + + // Calculate bounds + const float grab_padding = 2.0f; // FIXME: Should be part of style. + const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; + float grab_sz = style.GrabMinSize; + if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + grab_sz = ImMin(grab_sz, slider_sz); + const float slider_usable_sz = slider_sz - grab_sz; + const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; + const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f; + + float logarithmic_zero_epsilon = 0.0f; // Only valid when is_logarithmic is true + float zero_deadzone_halfsize = 0.0f; // Only valid when is_logarithmic is true + if (is_logarithmic) + { + // When using logarithmic sliders, we need to clamp to avoid hitting zero, but our choice of clamp value greatly affects slider precision. We attempt to use the specified precision to estimate a good lower bound. + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1; + logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); + zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f); + } + + // Process interacting with the slider + bool value_changed = false; + if (g.ActiveId == id) + { + bool set_new_value = false; + float clicked_t = 0.0f; + if (g.ActiveIdSource == ImGuiInputSource_Mouse) + { + if (!g.IO.MouseDown[0]) + { + ClearActiveID(); + } + else + { + const float mouse_abs_pos = g.IO.MousePos[axis]; + if (g.ActiveIdIsJustActivated) + { + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here. + g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f; + } + if (slider_usable_sz > 0.0f) + clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz); + if (axis == ImGuiAxis_Y) + clicked_t = 1.0f - clicked_t; + set_new_value = true; + } + } + else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) + { + if (g.ActiveIdIsJustActivated) + { + g.SliderCurrentAccum = 0.0f; // Reset any stored nav delta upon activation + g.SliderCurrentAccumDirty = false; + } + + float input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis); + if (input_delta != 0.0f) + { + const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); + const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); + const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; + if (decimal_precision > 0) + { + input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + if (tweak_slow) + input_delta /= 10.0f; + } + else + { + if ((v_range >= -100.0f && v_range <= 100.0f) || tweak_slow) + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps + else + input_delta /= 100.0f; + } + if (tweak_fast) + input_delta *= 10.0f; + + g.SliderCurrentAccum += input_delta; + g.SliderCurrentAccumDirty = true; + } + + float delta = g.SliderCurrentAccum; + if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + { + ClearActiveID(); + } + else if (g.SliderCurrentAccumDirty) + { + clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits + { + set_new_value = false; + g.SliderCurrentAccum = 0.0f; // If pushing up against the limits, don't continue to accumulate + } + else + { + set_new_value = true; + float old_clicked_t = clicked_t; + clicked_t = ImSaturate(clicked_t + delta); + + // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); + float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + if (delta > 0) + g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); + else + g.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta); + } + + g.SliderCurrentAccumDirty = false; + } + } + + if (set_new_value) + { + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + + // Round to user desired precision based on format string + if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) + v_new = RoundScalarWithFormatT(format, data_type, v_new); + + // Apply result + if (*v != v_new) + { + *v = v_new; + value_changed = true; + } + } + } + + if (slider_sz < 1.0f) + { + *out_grab_bb = ImRect(bb.Min, bb.Min); + } + else + { + // Output grab position so it can be displayed by the caller + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + if (axis == ImGuiAxis_Y) + grab_t = 1.0f - grab_t; + const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); + if (axis == ImGuiAxis_X) + *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding); + else + *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f); + } + + return value_changed; +} + +// For 32-bit and larger types, slider bounds are limited to half the natural type range. +// So e.g. an integer Slider between INT_MAX-10 and INT_MAX will fail, but an integer Slider between INT_MAX/2-10 and INT_MAX/2 will be ok. +// It would be possible to lift that limitation with some work but it doesn't seem to be worth it for sliders. +bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb) +{ + // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. + IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); + + // Those are the things we can do easily outside the SliderBehaviorT<> template, saves code generation. + ImGuiContext& g = *GImGui; + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + return false; + + switch (data_type) + { + case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } + case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU8*)p_min, *(const ImU8*)p_max, format, flags, out_grab_bb); if (r) *(ImU8*)p_v = (ImU8)v32; return r; } + case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_S32, &v32, *(const ImS16*)p_min, *(const ImS16*)p_max, format, flags, out_grab_bb); if (r) *(ImS16*)p_v = (ImS16)v32; return r; } + case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v; bool r = SliderBehaviorT(bb, id, ImGuiDataType_U32, &v32, *(const ImU16*)p_min, *(const ImU16*)p_max, format, flags, out_grab_bb); if (r) *(ImU16*)p_v = (ImU16)v32; return r; } + case ImGuiDataType_S32: + IM_ASSERT(*(const ImS32*)p_min >= IM_S32_MIN / 2 && *(const ImS32*)p_max <= IM_S32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS32*)p_v, *(const ImS32*)p_min, *(const ImS32*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_U32: + IM_ASSERT(*(const ImU32*)p_max <= IM_U32_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU32*)p_v, *(const ImU32*)p_min, *(const ImU32*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_S64: + IM_ASSERT(*(const ImS64*)p_min >= IM_S64_MIN / 2 && *(const ImS64*)p_max <= IM_S64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImS64*)p_v, *(const ImS64*)p_min, *(const ImS64*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_U64: + IM_ASSERT(*(const ImU64*)p_max <= IM_U64_MAX / 2); + return SliderBehaviorT(bb, id, data_type, (ImU64*)p_v, *(const ImU64*)p_min, *(const ImU64*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_Float: + IM_ASSERT(*(const float*)p_min >= -FLT_MAX / 2.0f && *(const float*)p_max <= FLT_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (float*)p_v, *(const float*)p_min, *(const float*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_Double: + IM_ASSERT(*(const double*)p_min >= -DBL_MAX / 2.0f && *(const double*)p_max <= DBL_MAX / 2.0f); + return SliderBehaviorT(bb, id, data_type, (double*)p_v, *(const double*)p_min, *(const double*)p_max, format, flags, out_grab_bb); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required. +// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const float w = CalcItemWidth(); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); + if (!temp_input_is_active) + { + // Tabbing or CTRL-clicking on Slider turns it into an input box + const bool input_requested_by_tabbing = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool clicked = hovered && IsMouseClicked(0, id); + const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id); + if (make_active && clicked) + SetKeyOwner(ImGuiKey_MouseLeft, id); + if (make_active && temp_input_allowed) + if (input_requested_by_tabbing || (clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) + temp_input_is_active = true; + + if (make_active && !temp_input_is_active) + { + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + } + + if (temp_input_is_active) + { + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0; + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + if (grab_bb.Max.x > grab_bb.Min.x) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0)); + return value_changed; +} + +// Add multiple sliders on 1 line for compact edition of multiple components +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, flags); + PopID(); + PopItemWidth(); + v = (void*)((char*)v + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags) +{ + if (format == NULL) + format = "%.0f deg"; + float v_deg = (*v_rad) * 360.0f / (2 * IM_PI); + bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags); + *v_rad = v_deg * (2 * IM_PI) / 360.0f; + return value_changed; +} + +bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags); +} + +bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags); +} + +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size); + const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(bb, style.FramePadding.y); + if (!ItemAdd(frame_bb, id)) + return false; + + // Default format string when passing NULL + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + const bool clicked = hovered && IsMouseClicked(0, id); + if (clicked || g.NavActivateId == id) + { + if (clicked) + SetKeyOwner(ImGuiKey_MouseLeft, id); + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + } + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + // Slider behavior + ImRect grab_bb; + const bool value_changed = SliderBehavior(frame_bb, id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb); + if (value_changed) + MarkItemEdited(id); + + // Render grab + if (grab_bb.Max.y > grab_bb.Min.y) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. + // For the vertical slider we allow centered text to overlap the frame padding + char value_buf[64]; + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f)); + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + return value_changed; +} + +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, ImGuiSliderFlags flags) +{ + return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags); +} + +bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format, ImGuiSliderFlags flags) +{ + return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc. +//------------------------------------------------------------------------- +// - ImParseFormatFindStart() [Internal] +// - ImParseFormatFindEnd() [Internal] +// - ImParseFormatTrimDecorations() [Internal] +// - ImParseFormatSanitizeForPrinting() [Internal] +// - ImParseFormatSanitizeForScanning() [Internal] +// - ImParseFormatPrecision() [Internal] +// - TempInputTextScalar() [Internal] +// - InputScalar() +// - InputScalarN() +// - InputFloat() +// - InputFloat2() +// - InputFloat3() +// - InputFloat4() +// - InputInt() +// - InputInt2() +// - InputInt3() +// - InputInt4() +// - InputDouble() +//------------------------------------------------------------------------- + +// We don't use strchr() because our strings are usually very short and often start with '%' +const char* ImParseFormatFindStart(const char* fmt) +{ + while (char c = fmt[0]) + { + if (c == '%' && fmt[1] != '%') + return fmt; + else if (c == '%') + fmt++; + fmt++; + } + return fmt; +} + +const char* ImParseFormatFindEnd(const char* fmt) +{ + // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. + if (fmt[0] != '%') + return fmt; + const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); + const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); + for (char c; (c = *fmt) != 0; fmt++) + { + if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0) + return fmt + 1; + if (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0) + return fmt + 1; + } + return fmt; +} + +// Extract the format out of a format string with leading or trailing decorations +// fmt = "blah blah" -> return "" +// fmt = "%.3f" -> return fmt +// fmt = "hello %.3f" -> return fmt + 6 +// fmt = "%.3f hello" -> return buf written with "%.3f" +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_size) +{ + const char* fmt_start = ImParseFormatFindStart(fmt); + if (fmt_start[0] != '%') + return ""; + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data. + return fmt_start; + ImStrncpy(buf, fmt_start, ImMin((size_t)(fmt_end - fmt_start) + 1, buf_size)); + return buf; +} + +// Sanitize format +// - Zero terminate so extra characters after format (e.g. "%f123") don't confuse atof/atoi +// - stb_sprintf.h supports several new modifiers which format numbers in a way that also makes them incompatible atof/atoi. +void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t fmt_out_size) +{ + const char* fmt_end = ImParseFormatFindEnd(fmt_in); + IM_UNUSED(fmt_out_size); + IM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! + while (fmt_in < fmt_end) + { + char c = *fmt_in++; + if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. + *(fmt_out++) = c; + } + *fmt_out = 0; // Zero-terminate +} + +// - For scanning we need to remove all width and precision fields and flags "%+3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d" +const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size) +{ + const char* fmt_end = ImParseFormatFindEnd(fmt_in); + const char* fmt_out_begin = fmt_out; + IM_UNUSED(fmt_out_size); + IM_ASSERT((size_t)(fmt_end - fmt_in + 1) < fmt_out_size); // Format is too long, let us know if this happens to you! + bool has_type = false; + while (fmt_in < fmt_end) + { + char c = *fmt_in++; + if (!has_type && ((c >= '0' && c <= '9') || c == '.' || c == '+' || c == '#')) + continue; + has_type |= ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); // Stop skipping digits + if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '. + *(fmt_out++) = c; + } + *fmt_out = 0; // Zero-terminate + return fmt_out_begin; +} + +template +static const char* ImAtoi(const char* src, TYPE* output) +{ + int negative = 0; + if (*src == '-') { negative = 1; src++; } + if (*src == '+') { src++; } + TYPE v = 0; + while (*src >= '0' && *src <= '9') + v = (v * 10) + (*src++ - '0'); + *output = negative ? -v : v; + return src; +} + +// Parse display precision back from the display format string +// FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. +int ImParseFormatPrecision(const char* fmt, int default_precision) +{ + fmt = ImParseFormatFindStart(fmt); + if (fmt[0] != '%') + return default_precision; + fmt++; + while (*fmt >= '0' && *fmt <= '9') + fmt++; + int precision = INT_MAX; + if (*fmt == '.') + { + fmt = ImAtoi(fmt + 1, &precision); + if (precision < 0 || precision > 99) + precision = default_precision; + } + if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation + precision = -1; + if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX) + precision = -1; + return (precision == INT_MAX) ? default_precision : precision; +} + +// Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) +// FIXME: Facilitate using this in variety of other situations. +bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) +{ + // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. + // We clear ActiveID on the first frame to allow the InputText() taking it back. + ImGuiContext& g = *GImGui; + const bool init = (g.TempInputId != id); + if (init) + ClearActiveID(); + + g.CurrentWindow->DC.CursorPos = bb.Min; + bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); + if (init) + { + // First frame we started displaying the InputText widget, we expect it to take the active id. + IM_ASSERT(g.ActiveId == id); + g.TempInputId = g.ActiveId; + } + return value_changed; +} + +static inline ImGuiInputTextFlags InputScalar_DefaultCharsFilter(ImGuiDataType data_type, const char* format) +{ + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + return ImGuiInputTextFlags_CharsScientific; + const char format_last_char = format[0] ? format[strlen(format) - 1] : 0; + return (format_last_char == 'x' || format_last_char == 'X') ? ImGuiInputTextFlags_CharsHexadecimal : ImGuiInputTextFlags_CharsDecimal; +} + +// Note that Drag/Slider functions are only forwarding the min/max values clamping values if the ImGuiSliderFlags_AlwaysClamp flag is set! +// This is intended: this way we allow CTRL+Click manual input to set a value out of bounds, for maximum flexibility. +// However this may not be ideal for all uses, as some user code may break on out of bound values. +bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) +{ + // FIXME: May need to clarify display behavior if format doesn't contain %. + // "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405 + const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); + char fmt_buf[32]; + char data_buf[32]; + format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + if (format[0] == 0) + format = type_info->PrintFmt; + DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); + ImStrTrimBlanks(data_buf); + + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; + flags |= InputScalar_DefaultCharsFilter(data_type, format); + + bool value_changed = false; + if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) + { + // Backup old value + size_t data_type_size = type_info->Size; + ImGuiDataTypeTempStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + // Apply new value (or operations) then clamp + DataTypeApplyFromText(data_buf, data_type, p_data, format); + if (p_clamp_min || p_clamp_max) + { + if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) + ImSwap(p_clamp_min, p_clamp_max); + DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); + } + + // Only mark as edited if new value is different + value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (value_changed) + MarkItemEdited(id); + } + return value_changed; +} + +// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional. +// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + + if (format == NULL) + format = DataTypeGetInfo(data_type)->PrintFmt; + + char buf[64]; + DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); + + // Testing ActiveId as a minor optimization as filtering is not needed until active + if (g.ActiveId == 0 && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) + flags |= InputScalar_DefaultCharsFilter(data_type, format); + flags |= ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. + + bool value_changed = false; + if (p_step == NULL) + { + if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); + } + else + { + const float button_size = GetFrameHeight(); + + BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive() + PushID(label); + SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); + if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view + value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); + + // Step buttons + const ImVec2 backup_frame_padding = style.FramePadding; + style.FramePadding.x = style.FramePadding.y; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; + if (flags & ImGuiInputTextFlags_ReadOnly) + BeginDisabled(); + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); + value_changed = true; + } + SameLine(0, style.ItemInnerSpacing.x); + if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) + { + DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); + value_changed = true; + } + if (flags & ImGuiInputTextFlags_ReadOnly) + EndDisabled(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + style.FramePadding = backup_frame_padding; + + PopID(); + EndGroup(); + } + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step, const void* p_step_fast, const char* format, ImGuiInputTextFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + bool value_changed = false; + BeginGroup(); + PushID(label); + PushMultiItemsWidths(components, CalcItemWidth()); + size_t type_size = GDataTypeInfo[data_type].Size; + for (int i = 0; i < components; i++) + { + PushID(i); + if (i > 0) + SameLine(0, g.Style.ItemInnerSpacing.x); + value_changed |= InputScalar("", data_type, p_data, p_step, p_step_fast, format, flags); + PopID(); + PopItemWidth(); + p_data = (void*)((char*)p_data + type_size); + } + PopID(); + + const char* label_end = FindRenderedTextEnd(label); + if (label != label_end) + { + SameLine(0.0f, g.Style.ItemInnerSpacing.x); + TextEx(label, label_end); + } + + EndGroup(); + return value_changed; +} + +bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags); +} + +bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags); +} + +bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags flags) +{ + // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. + const char* format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL), format, flags); +} + +bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", flags); +} + +bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags) +{ + return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", flags); +} + +bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags flags) +{ + flags |= ImGuiInputTextFlags_CharsScientific; + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL), format, flags); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint +//------------------------------------------------------------------------- +// - InputText() +// - InputTextWithHint() +// - InputTextMultiline() +// - InputTextGetCharInfo() [Internal] +// - InputTextReindexLines() [Internal] +// - InputTextReindexLinesRange() [Internal] +// - InputTextEx() [Internal] +// - DebugNodeInputTextState() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() + return InputTextEx(label, NULL, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); +} + +bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + return InputTextEx(label, NULL, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); +} + +bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) +{ + IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() or InputTextEx() manually if you need multi-line + hint. + return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); +} + +static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) +{ + int line_count = 0; + const char* s = text_begin; + while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding + if (c == '\n') + line_count++; + s--; + if (s[0] != '\n' && s[0] != '\r') + line_count++; + *out_text_end = s; + return line_count; +} + +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) +{ + ImGuiContext& g = *ctx; + ImFont* font = g.Font; + const float line_height = g.FontSize; + const float scale = line_height / font->FontSize; + + ImVec2 text_size = ImVec2(0, 0); + float line_width = 0.0f; + + const ImWchar* s = text_begin; + while (s < text_end) + { + unsigned int c = (unsigned int)(*s++); + if (c == '\n') + { + text_size.x = ImMax(text_size.x, line_width); + text_size.y += line_height; + line_width = 0.0f; + if (stop_on_new_line) + break; + continue; + } + if (c == '\r') + continue; + + const float char_width = font->GetCharAdvance((ImWchar)c) * scale; + line_width += char_width; + } + + if (text_size.x < line_width) + text_size.x = line_width; + + if (out_offset) + *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n + + if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n + text_size.y += line_height; + + if (remaining) + *remaining = s; + + return text_size; +} + +// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) +namespace ImStb +{ + +static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); } +static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } +static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; +static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) +{ + const ImWchar* text = obj->TextW.Data; + const ImWchar* text_remaining = NULL; + const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); + r->x0 = 0.0f; + r->x1 = size.x; + r->baseline_y_delta = size.y; + r->ymin = 0.0f; + r->ymax = size.y; + r->num_chars = (int)(text_remaining - (text + line_start_idx)); +} + +static bool is_separator(unsigned int c) +{ + return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!'; +} + +static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) +{ + // When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators. + if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) + return 0; + + bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]); + bool prev_separ = is_separator(obj->TextW[idx - 1]); + bool curr_white = ImCharIsBlankW(obj->TextW[idx]); + bool curr_separ = is_separator(obj->TextW[idx]); + return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); +} +static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) +{ + if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) + return 0; + + bool prev_white = ImCharIsBlankW(obj->TextW[idx]); + bool prev_separ = is_separator(obj->TextW[idx]); + bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]); + bool curr_separ = is_separator(obj->TextW[idx - 1]); + return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); +} +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL + +static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) +{ + ImWchar* dst = obj->TextW.Data + pos; + + // We maintain our buffer length in both UTF-8 and wchar formats + obj->Edited = true; + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + // Offset remaining text (FIXME-OPT: Use memmove) + const ImWchar* src = obj->TextW.Data + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; +} + +static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len) +{ + const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; + const int text_len = obj->CurLenW; + IM_ASSERT(pos <= text_len); + + const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); + if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) + return false; + + // Grow internal buffer if needed + if (new_text_len + text_len + 1 > obj->TextW.Size) + { + if (!is_resizable) + return false; + IM_ASSERT(text_len < obj->TextW.Size); + obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1); + } + + ImWchar* text = obj->TextW.Data; + if (pos != text_len) + memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); + memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); + + obj->Edited = true; + obj->CurLenW += new_text_len; + obj->CurLenA += new_text_len_utf8; + obj->TextW[obj->CurLenW] = '\0'; + + return true; +} + +// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols) +#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left +#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right +#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up +#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down +#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line +#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line +#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text +#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text +#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor +#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor +#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo +#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo +#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word +#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word +#define STB_TEXTEDIT_K_PGUP 0x20000E // keyboard input to move cursor up a page +#define STB_TEXTEDIT_K_PGDOWN 0x20000F // keyboard input to move cursor down a page +#define STB_TEXTEDIT_K_SHIFT 0x400000 + +#define STB_TEXTEDIT_IMPLEMENTATION +#define STB_TEXTEDIT_memmove memmove +#include "imstb_textedit.h" + +// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling +// the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) +static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const STB_TEXTEDIT_CHARTYPE* text, int text_len) +{ + stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len); + ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW); + state->cursor = state->select_start = state->select_end = 0; + if (text_len <= 0) + return; + if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len)) + { + state->cursor = state->select_start = state->select_end = text_len; + state->has_preferred_x = 0; + return; + } + IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() +} + +} // namespace ImStb + +void ImGuiInputTextState::OnKeyPressed(int key) +{ + stb_textedit_key(this, &Stb, key); + CursorFollow = true; + CursorAnimReset(); +} + +ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() +{ + memset(this, 0, sizeof(*this)); +} + +// Public API to manipulate UTF-8 text +// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) +// FIXME: The existence of this rarely exercised code path is a bit of a nuisance. +void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) +{ + IM_ASSERT(pos + bytes_count <= BufTextLen); + char* dst = Buf + pos; + const char* src = Buf + pos + bytes_count; + while (char c = *src++) + *dst++ = c; + *dst = '\0'; + + if (CursorPos >= pos + bytes_count) + CursorPos -= bytes_count; + else if (CursorPos >= pos) + CursorPos = pos; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen -= bytes_count; +} + +void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end) +{ + // Accept null ranges + if (new_text == new_text_end) + return; + + const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; + const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); + if (new_text_len + BufTextLen >= BufSize) + { + if (!is_resizable) + return; + + // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) + ImGuiContext& g = *Ctx; + ImGuiInputTextState* edit_state = &g.InputTextState; + IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); + IM_ASSERT(Buf == edit_state->TextA.Data); + int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; + edit_state->TextA.reserve(new_buf_size + 1); + Buf = edit_state->TextA.Data; + BufSize = edit_state->BufCapacityA = new_buf_size; + } + + if (BufTextLen != pos) + memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos)); + memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); + Buf[BufTextLen + new_text_len] = '\0'; + + if (CursorPos >= pos) + CursorPos += new_text_len; + SelectionStart = SelectionEnd = CursorPos; + BufDirty = true; + BufTextLen += new_text_len; +} + +// Return false to discard a character. +static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) +{ + IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard); + unsigned int c = *p_char; + + // Filter non-printable (NB: isprint is unreliable! see #2467) + bool apply_named_filters = true; + if (c < 0x20) + { + bool pass = false; + pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline)); // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) + pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput)); + if (!pass) + return false; + apply_named_filters = false; // Override named filters below so newline and tabs can still be inserted. + } + + if (input_source != ImGuiInputSource_Clipboard) + { + // We ignore Ascii representation of delete (emitted from Backspace on OSX, see #2578, #2817) + if (c == 127) + return false; + + // Filter private Unicode range. GLFW on OSX seems to send private characters for special keys like arrow keys (FIXME) + if (c >= 0xE000 && c <= 0xF8FF) + return false; + } + + // Filter Unicode ranges we are not handling in this build + if (c > IM_UNICODE_CODEPOINT_MAX) + return false; + + // Generic named filters + if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific))) + { + // The libc allows overriding locale, with e.g. 'setlocale(LC_NUMERIC, "de_DE.UTF-8");' which affect the output/input of printf/scanf to use e.g. ',' instead of '.'. + // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. + // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. + // Change the default decimal_point with: + // ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; + // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. + ImGuiContext& g = *GImGui; + const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + + // Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) + // While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may + // scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font. + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal)) + if (c >= 0xFF01 && c <= 0xFF5E) + c = c - 0xFF01 + 0x21; + + // Allow 0-9 . - + * / + if (flags & ImGuiInputTextFlags_CharsDecimal) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/')) + return false; + + // Allow 0-9 . - + * / e E + if (flags & ImGuiInputTextFlags_CharsScientific) + if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E')) + return false; + + // Allow 0-9 a-F A-F + if (flags & ImGuiInputTextFlags_CharsHexadecimal) + if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F')) + return false; + + // Turn a-z into A-Z + if (flags & ImGuiInputTextFlags_CharsUppercase) + if (c >= 'a' && c <= 'z') + c += (unsigned int)('A' - 'a'); + + if (flags & ImGuiInputTextFlags_CharsNoBlank) + if (ImCharIsBlankW(c)) + return false; + + *p_char = c; + } + + // Custom callback filter + if (flags & ImGuiInputTextFlags_CallbackCharFilter) + { + ImGuiContext& g = *GImGui; + ImGuiInputTextCallbackData callback_data; + callback_data.Ctx = &g; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; + callback_data.EventChar = (ImWchar)c; + callback_data.Flags = flags; + callback_data.UserData = user_data; + if (callback(&callback_data) != 0) + return false; + *p_char = callback_data.EventChar; + if (!callback_data.EventChar) + return false; + } + + return true; +} + +// Find the shortest single replacement we can make to get the new text from the old text. +// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end. +// FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly. +static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a) +{ + ImGuiContext& g = *GImGui; + const ImWchar* old_buf = state->TextW.Data; + const int old_length = state->CurLenW; + const int new_length = ImTextCountCharsFromUtf8(new_buf_a, new_buf_a + new_length_a); + g.TempBuffer.reserve_discard((new_length + 1) * sizeof(ImWchar)); + ImWchar* new_buf = (ImWchar*)(void*)g.TempBuffer.Data; + ImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a); + + const int shorter_length = ImMin(old_length, new_length); + int first_diff; + for (first_diff = 0; first_diff < shorter_length; first_diff++) + if (old_buf[first_diff] != new_buf[first_diff]) + break; + if (first_diff == old_length && first_diff == new_length) + return; + + int old_last_diff = old_length - 1; + int new_last_diff = new_length - 1; + for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--) + if (old_buf[old_last_diff] != new_buf[new_last_diff]) + break; + + const int insert_len = new_last_diff - first_diff + 1; + const int delete_len = old_last_diff - first_diff + 1; + if (insert_len > 0 || delete_len > 0) + if (STB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len)) + for (int i = 0; i < delete_len; i++) + p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i); +} + +// As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables) +// we need some form of hook to reapply data back to user buffer on deactivation frame. (#4714) +// It would be more desirable that we discourage users from taking advantage of the "user not retaining data" trick, +// but that more likely be attractive when we do have _NoLiveEdit flag available. +void ImGui::InputTextDeactivateHook(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiInputTextState* state = &g.InputTextState; + if (id == 0 || state->ID != id) + return; + g.InputTextDeactivatedState.ID = state->ID; + if (state->Flags & ImGuiInputTextFlags_ReadOnly) + { + g.InputTextDeactivatedState.TextA.resize(0); // In theory this data won't be used, but clear to be neat. + } + else + { + IM_ASSERT(state->TextA.Data != 0); + g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1); + memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1); + } +} + +// Edit a string of text +// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!". +// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match +// Note that in std::string world, capacity() would omit 1 byte used by the zero-terminator. +// - When active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while the InputText is active has no effect. +// - If you want to use ImGui::InputText() with std::string, see misc/cpp/imgui_stdlib.h +// (FIXME: Rather confusing and messy function, among the worse part of our codebase, expecting to rewrite a V2 at some point.. Partly because we are +// doing UTF8 > U16 > UTF8 conversions on the go to easily interface with stb_textedit. Ideally should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188) +bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* callback_user_data) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + IM_ASSERT(buf != NULL && buf_size >= 0); + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) + IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) + + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + const ImGuiStyle& style = g.Style; + + const bool RENDER_SELECTION_WHEN_INACTIVE = false; + const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; + const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; + const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; + const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; + if (is_resizable) + IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! + + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar) + BeginGroup(); + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line + const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size); + + ImGuiWindow* draw_window = window; + ImVec2 inner_size = frame_size; + ImGuiItemStatusFlags item_status_flags = 0; + ImGuiLastItemData item_data_backup; + if (is_multiline) + { + ImVec2 backup_pos = window->DC.CursorPos; + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) + { + EndGroup(); + return false; + } + item_status_flags = g.LastItemData.StatusFlags; + item_data_backup = g.LastItemData; + window->DC.CursorPos = backup_pos; + + // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. + // FIXME-NAV: Pressing NavActivate will trigger general child activation right before triggering our own below. Harmless but bizarre. + PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); + PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove); + PopStyleVar(3); + PopStyleColor(); + if (!child_visible) + { + EndChild(); + EndGroup(); + return false; + } + draw_window = g.CurrentWindow; // Child window + draw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + draw_window->DC.CursorPos += style.FramePadding; + inner_size.x -= draw_window->ScrollbarSizes.x; + } + else + { + // Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd) + ItemSize(total_bb, style.FramePadding.y); + if (!(flags & ImGuiInputTextFlags_MergedItem)) + if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) + return false; + item_status_flags = g.LastItemData.StatusFlags; + } + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + if (hovered) + g.MouseCursor = ImGuiMouseCursor_TextInput; + + // We are only allowed to access the state if we are already the active widget. + ImGuiInputTextState* state = GetInputTextState(id); + + const bool input_requested_by_tabbing = (item_status_flags & ImGuiItemStatusFlags_FocusedByTabbing) != 0; + const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); + + const bool user_clicked = hovered && io.MouseClicked[0]; + const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); + bool clear_active_id = false; + bool select_all = false; + + float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; + + const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state. + const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_tabbing); + const bool init_state = (init_make_active || user_scroll_active); + if ((init_state && g.ActiveId != id) || init_changed_specs) + { + // Access state even if we don't own it yet. + state = &g.InputTextState; + state->CursorAnimReset(); + + // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) + InputTextDeactivateHook(state->ID); + + // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar) + // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode) + const int buf_len = (int)strlen(buf); + state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->InitialTextA.Data, buf, buf_len + 1); + + // Preserve cursor position and undo/redo stack if we come back to same widget + // FIXME: Since we reworked this on 2022/06, may want to differenciate recycle_cursor vs recycle_undostate? + bool recycle_state = (state->ID == id && !init_changed_specs); + if (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0))) + recycle_state = false; + + // Start edition + const char* buf_end = NULL; + state->ID = id; + state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(0); + state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then) + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. + + if (recycle_state) + { + // Recycle existing cursor/selection/undo stack but clamp position + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. + state->CursorClamp(); + } + else + { + state->ScrollX = 0.0f; + stb_textedit_initialize_state(&state->Stb, !is_multiline); + } + + if (!is_multiline) + { + if (flags & ImGuiInputTextFlags_AutoSelectAll) + select_all = true; + if (input_requested_by_nav && (!recycle_state || !(g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState))) + select_all = true; + if (input_requested_by_tabbing || (user_clicked && io.KeyCtrl)) + select_all = true; + } + + if (flags & ImGuiInputTextFlags_AlwaysOverwrite) + state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) + } + + const bool is_osx = io.ConfigMacOSXBehaviors; + if (g.ActiveId != id && init_make_active) + { + IM_ASSERT(state && state->ID == id); + SetActiveID(id, window); + SetFocusID(id, window); + FocusWindow(window); + } + if (g.ActiveId == id) + { + // Declare some inputs, the other are registered and polled via Shortcut() routing system. + if (user_clicked) + SetKeyOwner(ImGuiKey_MouseLeft, id); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); + SetKeyOwner(ImGuiKey_Home, id); + SetKeyOwner(ImGuiKey_End, id); + if (is_multiline) + { + SetKeyOwner(ImGuiKey_PageUp, id); + SetKeyOwner(ImGuiKey_PageDown, id); + } + if (is_osx) + SetKeyOwner(ImGuiMod_Alt, id); + if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character. + SetShortcutRouting(ImGuiKey_Tab, id); + } + + // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) + if (g.ActiveId == id && state == NULL) + ClearActiveID(); + + // Release focus when we click outside + if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_active) //-V560 + clear_active_id = true; + + // Lock the decision of whether we are going to take the path displaying the cursor or selection + bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active); + bool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + bool value_changed = false; + bool validated = false; + + // When read-only we always use the live data passed to the function + // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :( + if (is_readonly && state != NULL && (render_cursor || render_selection)) + { + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); + state->CursorClamp(); + render_selection &= state->HasSelection(); + } + + // Select the buffer to render. + const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid; + const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + + // Password pushes a temporary font with only a fallback glyph + if (is_password && !is_displaying_hint) + { + const ImFontGlyph* glyph = g.Font->FindGlyph('*'); + ImFont* password_font = &g.InputTextPasswordFont; + password_font->FontSize = g.Font->FontSize; + password_font->Scale = g.Font->Scale; + password_font->Ascent = g.Font->Ascent; + password_font->Descent = g.Font->Descent; + password_font->ContainerAtlas = g.Font->ContainerAtlas; + password_font->FallbackGlyph = glyph; + password_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); + PushFont(password_font); + } + + // Process mouse inputs and character inputs + int backup_current_text_length = 0; + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + backup_current_text_length = state->CurLenA; + state->Edited = false; + state->BufCapacityA = buf_size; + state->Flags = flags; + + // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. + // Down the line we should have a cleaner library-wide concept of Selected vs Active. + g.ActiveIdAllowOverlap = !io.MouseDown[0]; + + // Edit in progress + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); + + if (select_all) + { + state->SelectAll(); + state->SelectedAllMouseLock = true; + } + else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift) + { + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + const int multiclick_count = (io.MouseClickedCount[0] - 2); + if ((multiclick_count % 2) == 0) + { + // Double-click: Select word + // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant: + // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) + const bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) == '\n'; + if (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); + //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + if (!STB_TEXT_HAS_SELECTION(&state->Stb)) + ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb); + state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor); + state->Stb.select_end = state->Stb.cursor; + ImStb::stb_textedit_clamp(state, &state->Stb); + } + else + { + // Triple-click: Select line + const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) == '\n'; + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART); + state->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT); + state->OnKeyPressed(STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT); + if (!is_eol && is_multiline) + { + ImSwap(state->Stb.select_start, state->Stb.select_end); + state->Stb.cursor = state->Stb.select_end; + } + state->CursorFollow = false; + } + state->CursorAnimReset(); + } + else if (io.MouseClicked[0] && !state->SelectedAllMouseLock) + { + if (hovered) + { + if (io.KeyShift) + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + else + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + } + } + else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) + { + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); + state->CursorAnimReset(); + state->CursorFollow = true; + } + if (state->SelectedAllMouseLock && !io.MouseDown[0]) + state->SelectedAllMouseLock = false; + + // We expect backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336) + // (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. For Space they all send all threes) + if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly) + { + unsigned int c = '\t'; // Insert TAB + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } + + // Process regular text input (before we check for Return because using some IME will effectively send a Return?) + // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. + const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); + if (io.InputQueueCharacters.Size > 0) + { + if (!ignore_char_inputs && !is_readonly && !input_requested_by_nav) + for (int n = 0; n < io.InputQueueCharacters.Size; n++) + { + // Insert character if they pass filtering + unsigned int c = (unsigned int)io.InputQueueCharacters[n]; + if (c == '\t') // Skip Tab, see above. + continue; + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } + + // Consume characters + io.InputQueueCharacters.resize(0); + } + } + + // Process other shortcuts/key-presses + bool revert_edit = false; + if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id) + { + IM_ASSERT(state != NULL); + + const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1); + state->Stb.row_count_per_page = row_count_per_page; + + const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); + const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl + const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + + // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText) + // Otherwise we could simply assume that we own the keys as we are active. + const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat; + const bool is_cut = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_X, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, id, f_repeat)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); + const bool is_copy = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_C, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, id)) && !is_password && (!is_multiline || state->HasSelection()); + const bool is_paste = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_V, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, id, f_repeat)) && !is_readonly; + const bool is_undo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Z, id, f_repeat)) && !is_readonly && is_undoable; + const bool is_redo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Y, id, f_repeat) || (is_osx && Shortcut(ImGuiMod_Shortcut | ImGuiMod_Shift | ImGuiKey_Z, id, f_repeat))) && !is_readonly && is_undoable; + const bool is_select_all = Shortcut(ImGuiMod_Shortcut | ImGuiKey_A, id); + + // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + const bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter, true) || IsKeyPressed(ImGuiKey_KeypadEnter, true); + const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false)); + const bool is_cancel = Shortcut(ImGuiKey_Escape, id, f_repeat) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, id, f_repeat)); + + // FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of. + if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } + else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } + else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } + else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } + else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) + { + if (!state->HasSelection()) + { + // OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace) + if (is_wordmove_key_down) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); + } + state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); + } + else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly) + { + if (!state->HasSelection()) + { + if (is_wordmove_key_down) + state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT); + else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) + state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT); + } + state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); + } + else if (is_enter_pressed || is_gamepad_validate) + { + // Determine if we turn Enter into a \n character + bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; + if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl)) + { + validated = true; + if (io.ConfigInputTextEnterKeepActive && !is_multiline) + state->SelectAll(); // No need to scroll + else + clear_active_id = true; + } + else if (!is_readonly) + { + unsigned int c = '\n'; // Insert new line + if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + state->OnKeyPressed((int)c); + } + } + else if (is_cancel) + { + if (flags & ImGuiInputTextFlags_EscapeClearsAll) + { + if (buf[0] != 0) + { + revert_edit = true; + } + else + { + render_cursor = render_selection = false; + clear_active_id = true; + } + } + else + { + clear_active_id = revert_edit = true; + render_cursor = render_selection = false; + } + } + else if (is_undo || is_redo) + { + state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO); + state->ClearSelection(); + } + else if (is_select_all) + { + state->SelectAll(); + state->CursorFollow = true; + } + else if (is_cut || is_copy) + { + // Cut, Copy + if (io.SetClipboardTextFn) + { + const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; + const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; + const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; + char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char)); + ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); + SetClipboardText(clipboard_data); + MemFree(clipboard_data); + } + if (is_cut) + { + if (!state->HasSelection()) + state->SelectAll(); + state->CursorFollow = true; + stb_textedit_cut(state, &state->Stb); + } + } + else if (is_paste) + { + if (const char* clipboard = GetClipboardText()) + { + // Filter pasted buffer + const int clipboard_len = (int)strlen(clipboard); + ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar)); + int clipboard_filtered_len = 0; + for (const char* s = clipboard; *s != 0; ) + { + unsigned int c; + s += ImTextCharFromUtf8(&c, s, NULL); + if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) + continue; + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; + } + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation + { + stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); + state->CursorFollow = true; + } + MemFree(clipboard_filtered); + } + } + + // Update render selection flag after events have been handled, so selection highlight can be displayed during the same frame. + render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor); + } + + // Process callbacks and apply result back to user's buffer. + const char* apply_new_text = NULL; + int apply_new_text_length = 0; + if (g.ActiveId == id) + { + IM_ASSERT(state != NULL); + if (revert_edit && !is_readonly) + { + if (flags & ImGuiInputTextFlags_EscapeClearsAll) + { + // Clear input + IM_ASSERT(buf[0] != 0); + apply_new_text = ""; + apply_new_text_length = 0; + value_changed = true; + STB_TEXTEDIT_CHARTYPE empty_string; + stb_textedit_replace(state, &state->Stb, &empty_string, 0); + } + else if (strcmp(buf, state->InitialTextA.Data) != 0) + { + // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. + // Push records into the undo stack so we can CTRL+Z the revert operation itself + apply_new_text = state->InitialTextA.Data; + apply_new_text_length = state->InitialTextA.Size - 1; + value_changed = true; + ImVector w_text; + if (apply_new_text_length > 0) + { + w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1); + ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length); + } + stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); + } + } + + // Apply ASCII value + if (!is_readonly) + { + state->TextAIsValid = true; + state->TextA.resize(state->TextW.Size * 4 + 1); + ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); + } + + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer + // before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. + // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. + // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage + // (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object + // unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). + const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + if (apply_edit_back_to_user_buffer) + { + // Apply new value immediately - copy modified buffer back + // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. + // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. + + // User callback + if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) + { + IM_ASSERT(callback != NULL); + + // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. + ImGuiInputTextFlags event_flag = 0; + ImGuiKey event_key = ImGuiKey_None; + if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab, id)) + { + event_flag = ImGuiInputTextFlags_CallbackCompletion; + event_key = ImGuiKey_Tab; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_UpArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow)) + { + event_flag = ImGuiInputTextFlags_CallbackHistory; + event_key = ImGuiKey_DownArrow; + } + else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited) + { + event_flag = ImGuiInputTextFlags_CallbackEdit; + } + else if (flags & ImGuiInputTextFlags_CallbackAlways) + { + event_flag = ImGuiInputTextFlags_CallbackAlways; + } + + if (event_flag) + { + ImGuiInputTextCallbackData callback_data; + callback_data.Ctx = &g; + callback_data.EventFlag = event_flag; + callback_data.Flags = flags; + callback_data.UserData = callback_user_data; + + char* callback_buf = is_readonly ? buf : state->TextA.Data; + callback_data.EventKey = event_key; + callback_data.Buf = callback_buf; + callback_data.BufTextLen = state->CurLenA; + callback_data.BufSize = state->BufCapacityA; + callback_data.BufDirty = false; + + // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) + ImWchar* text = state->TextW.Data; + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end); + + // Call user code + callback(&callback_data); + + // Read back what user may have modified + callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback + IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields + IM_ASSERT(callback_data.BufSize == state->BufCapacityA); + IM_ASSERT(callback_data.Flags == flags); + const bool buf_dirty = callback_data.BufDirty; + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (buf_dirty) + { + IM_ASSERT((flags & ImGuiInputTextFlags_ReadOnly) == 0); + IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? + if (callback_data.BufTextLen > backup_current_text_length && is_resizable) + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); + state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + state->CursorAnimReset(); + } + } + } + + // Will copy result string if modified + if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) + { + apply_new_text = state->TextA.Data; + apply_new_text_length = state->CurLenA; + value_changed = true; + } + } + } + + // Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details) + if (g.InputTextDeactivatedState.ID == id) + { + if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0) + { + apply_new_text = g.InputTextDeactivatedState.TextA.Data; + apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1; + value_changed = true; + //IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text); + } + g.InputTextDeactivatedState.ID = 0; + } + + // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) + if (apply_new_text != NULL) + { + // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size + // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used + // without any storage on user's side. + IM_ASSERT(apply_new_text_length >= 0); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.Ctx = &g; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); + } + //IMGUI_DEBUG_PRINT("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + } + + // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) + // Otherwise request text input ahead for next frame. + if (g.ActiveId == id && clear_active_id) + ClearActiveID(); + else if (g.ActiveId == id) + g.WantTextInputNextFrame = 1; + + // Render frame + if (!is_multiline) + { + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + } + + const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y); // Not using frame_bb.Max because we have adjusted size + ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; + ImVec2 text_size(0.0f, 0.0f); + + // Set upper limit of single-line InputTextEx() at 2 million characters strings. The current pathological worst case is a long line + // without any carriage return, which would makes ImFont::RenderText() reserve too many vertices and probably crash. Avoid it altogether. + // Note that we only use this limit on single-line InputText(), so a pathologically large line on a InputTextMultiline() would still crash. + const int buf_display_max_length = 2 * 1024 * 1024; + const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 + const char* buf_display_end = NULL; // We have specialized paths below for setting the length + if (is_displaying_hint) + { + buf_display = hint; + buf_display_end = hint + strlen(hint); + } + + // Render text. We currently only render selection when the widget is active or while scrolling. + // FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive. + if (render_cursor || render_selection) + { + IM_ASSERT(state != NULL); + if (!is_displaying_hint) + buf_display_end = buf_display + state->CurLenA; + + // Render text (with cursor and selection) + // This is going to be messy. We need to: + // - Display the text (this alone can be more easily clipped) + // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation) + // - Measure text height (for scrollbar) + // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) + // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. + const ImWchar* text_begin = state->TextW.Data; + ImVec2 cursor_offset, select_start_offset; + + { + // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions. + const ImWchar* searches_input_ptr[2] = { NULL, NULL }; + int searches_result_line_no[2] = { -1000, -1000 }; + int searches_remaining = 0; + if (render_cursor) + { + searches_input_ptr[0] = text_begin + state->Stb.cursor; + searches_result_line_no[0] = -1; + searches_remaining++; + } + if (render_selection) + { + searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + searches_result_line_no[1] = -1; + searches_remaining++; + } + + // Iterate all lines to find our line numbers + // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. + searches_remaining += is_multiline ? 1 : 0; + int line_count = 0; + //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit + for (const ImWchar* s = text_begin; *s != 0; s++) + if (*s == '\n') + { + line_count++; + if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } + } + line_count++; + if (searches_result_line_no[0] == -1) + searches_result_line_no[0] = line_count; + if (searches_result_line_no[1] == -1) + searches_result_line_no[1] = line_count; + + // Calculate 2d position by finding the beginning of the line and measuring distance + cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.y = searches_result_line_no[0] * g.FontSize; + if (searches_result_line_no[1] >= 0) + { + select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.y = searches_result_line_no[1] * g.FontSize; + } + + // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) + if (is_multiline) + text_size = ImVec2(inner_size.x, line_count * g.FontSize); + } + + // Scroll + if (render_cursor && state->CursorFollow) + { + // Horizontal scroll in chunks of quarter width + if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) + { + const float scroll_increment_x = inner_size.x * 0.25f; + const float visible_width = inner_size.x - style.FramePadding.x; + if (cursor_offset.x < state->ScrollX) + state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); + else if (cursor_offset.x - visible_width >= state->ScrollX) + state->ScrollX = IM_FLOOR(cursor_offset.x - visible_width + scroll_increment_x); + } + else + { + state->ScrollX = 0.0f; + } + + // Vertical scroll + if (is_multiline) + { + // Test if cursor is vertically visible + if (cursor_offset.y - g.FontSize < scroll_y) + scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); + else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y) + scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f; + const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f); + scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y); + draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag + draw_window->Scroll.y = scroll_y; + } + + state->CursorFollow = false; + } + + // Draw selection + const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f); + if (render_selection) + { + const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); + + ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. + float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. + float bg_offy_dn = is_multiline ? 0.0f : 2.0f; + ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; + for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) + { + if (rect_pos.y > clip_rect.w + g.FontSize) + break; + if (rect_pos.y < clip_rect.y) + { + //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit + //p = p ? p + 1 : text_selected_end; + while (p < text_selected_end) + if (*p++ == '\n') + break; + } + else + { + ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true); + if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); + rect.ClipWith(clip_rect); + if (rect.Overlaps(clip_rect)) + draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); + } + rect_pos.x = draw_pos.x - draw_scroll.x; + rect_pos.y += g.FontSize; + } + } + + // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + + // Draw blinking cursor + if (render_cursor) + { + state->CursorAnim += io.DeltaTime; + bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; + ImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_scroll); + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); + if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); + + // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) + if (!is_readonly) + { + g.PlatformImeData.WantVisible = true; + g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + g.PlatformImeData.InputLineHeight = g.FontSize; + } + } + } + else + { + // Render text only (no selection, no cursor) + if (is_multiline) + text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width + else if (!is_displaying_hint && g.ActiveId == id) + buf_display_end = buf_display + state->CurLenA; + else if (!is_displaying_hint) + buf_display_end = buf_display + strlen(buf_display); + + if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) + { + ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + } + } + + if (is_password && !is_displaying_hint) + PopFont(); + + if (is_multiline) + { + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... + Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); + g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + EndChild(); + item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); + + // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... + // FIXME: This quite messy/tricky, should attempt to get rid of the child window. + EndGroup(); + if (g.LastItemData.ID == 0) + { + g.LastItemData.ID = id; + g.LastItemData.InFlags = item_data_backup.InFlags; + g.LastItemData.StatusFlags = item_data_backup.StatusFlags; + } + } + + // Log as text + if (g.LogEnabled && (!is_password || is_displaying_hint)) + { + LogSetNextTextDecoration("{", "}"); + LogRenderedText(&draw_pos, buf_display, buf_display_end); + } + + if (label_size.x > 0) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + + if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) + MarkItemEdited(id); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); + if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0) + return validated; + else + return value_changed; +} + +void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) +{ +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + ImGuiContext& g = *GImGui; + ImStb::STB_TexteditState* stb_state = &state->Stb; + ImStb::StbUndoState* undo_state = &stb_state->undostate; + Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); + DebugLocateItemOnHover(state->ID); + Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); + Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); + Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); + if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 15), true)) // Visualize undo state + { + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + for (int n = 0; n < STB_TEXTEDIT_UNDOSTATECOUNT; n++) + { + ImStb::StbUndoRecord* undo_rec = &undo_state->undo_rec[n]; + const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' '; + if (undo_rec_type == ' ') + BeginDisabled(); + char buf[64] = ""; + if (undo_rec_type != ' ' && undo_rec->char_storage != -1) + ImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length); + Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%s\"", + undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf); + if (undo_rec_type == ' ') + EndDisabled(); + } + PopStyleVar(); + } + EndChild(); +#else + IM_UNUSED(state); +#endif +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ColorEdit, ColorPicker, ColorButton, etc. +//------------------------------------------------------------------------- +// - ColorEdit3() +// - ColorEdit4() +// - ColorPicker3() +// - RenderColorRectWithAlphaCheckerboard() [Internal] +// - ColorPicker4() +// - ColorButton() +// - SetColorEditOptions() +// - ColorTooltip() [Internal] +// - ColorEditOptionsPopup() [Internal] +// - ColorPickerOptionsPopup() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags, const ImVec2& size_arg) +{ + return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha, size_arg); +} + +static void ColorEditRestoreH(const float* col, float* H) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ColorEditCurrentID != 0); + if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + return; + *H = g.ColorEditSavedHue; +} + +// ColorEdit supports RGB and HSV inputs. In case of RGB input resulting color may have undefined hue and/or saturation. +// Since widget displays both RGB and HSV values we must preserve hue and saturation to prevent these values resetting. +static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(g.ColorEditCurrentID != 0); + if (g.ColorEditSavedID != g.ColorEditCurrentID || g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0))) + return; + + // When S == 0, H is undefined. + // When H == 1 it wraps around to 0. + if (*S == 0.0f || (*H == 0.0f && g.ColorEditSavedHue == 1)) + *H = g.ColorEditSavedHue; + + // When V == 0, S is undefined. + if (*V == 0.0f) + *S = g.ColorEditSavedSat; +} + +// Edit colors components (each component in 0.0f..1.0f range). +// See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. +bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const float square_sz = GetFrameHeight(); + const float w_full = CalcItemWidth(); + const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x); + const float w_inputs = w_full - w_button; + const char* label_display_end = FindRenderedTextEnd(label); + g.NextItemData.ClearFlags(); + + BeginGroup(); + PushID(label); + const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); + if (set_current_color_edit_id) + g.ColorEditCurrentID = window->IDStack.back(); + + // If we're not showing any slider there's no point in doing any HSV conversions + const ImGuiColorEditFlags flags_untouched = flags; + if (flags & ImGuiColorEditFlags_NoInputs) + flags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions; + + // Context menu: display and modify options (before defaults are applied) + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorEditOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags_DisplayMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DisplayMask_); + if (!(flags & ImGuiColorEditFlags_DataTypeMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_); + if (!(flags & ImGuiColorEditFlags_PickerMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_); + if (!(flags & ImGuiColorEditFlags_InputMask_)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_InputMask_); + flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected + + const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0; + const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0; + const int components = alpha ? 4 : 3; + + // Convert to the formats we need + float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f }; + if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB)) + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV)) + { + // Hue is lost when converting from grayscale rgb (saturation=0). Restore it. + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + ColorEditRestoreHS(col, &f[0], &f[1], &f[2]); + } + int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) }; + + bool value_changed = false; + bool value_changed_as_float = false; + + const ImVec2 pos = window->DC.CursorPos; + const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f; + window->DC.CursorPos.x = pos.x + inputs_offset_x; + + if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB/HSV 0..255 Sliders + const float w_item_one = ImMax(1.0f, IM_FLOOR((w_inputs - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components)); + const float w_item_last = ImMax(1.0f, IM_FLOOR(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components - 1))); + + const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x); + static const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; + static const char* fmt_table_int[3][4] = + { + { "%3d", "%3d", "%3d", "%3d" }, // Short display + { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA + { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA + }; + static const char* fmt_table_float[3][4] = + { + { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display + { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA + { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA + }; + const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1; + + for (int n = 0; n < components; n++) + { + if (n > 0) + SameLine(0, style.ItemInnerSpacing.x); + SetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last); + + // FIXME: When ImGuiColorEditFlags_HDR flag is passed HS values snap in weird ways when SV values go below 0. + if (flags & ImGuiColorEditFlags_Float) + { + value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); + value_changed_as_float |= value_changed; + } + else + { + value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + } + } + else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0) + { + // RGB Hexadecimal Input + char buf[64]; + if (alpha) + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255)); + else + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); + SetNextItemWidth(w_inputs); + if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase)) + { + value_changed = true; + char* p = buf; + while (*p == '#' || ImCharIsBlankA(*p)) + p++; + i[0] = i[1] = i[2] = 0; + i[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. inputting #FFFFFF omitting alpha) + int r; + if (alpha) + r = sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) + else + r = sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]); + IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + } + + ImGuiWindow* picker_active_window = NULL; + if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) + { + const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x; + window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y); + + const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); + if (ColorButton("##ColorButton", col_v4, flags, size_arg)) + { + if (!(flags & ImGuiColorEditFlags_NoPicker)) + { + // Store current color and open a picker + g.ColorPickerRef = col_v4; + OpenPopup("picker"); + SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(0.0f, style.ItemSpacing.y)); + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + + if (BeginPopup("picker")) + { + if (g.CurrentWindow->BeginCount == 1) + { + picker_active_window = g.CurrentWindow; + if (label != label_display_end) + { + TextEx(label, label_display_end); + Spacing(); + } + ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar; + ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf; + SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes? + value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x); + } + EndPopup(); + } + } + + if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel)) + { + // Position not necessarily next to last submitted button (e.g. if style.ColorButtonPosition == ImGuiDir_Left), + // but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify this. + SameLine(0.0f, style.ItemInnerSpacing.x); + window->DC.CursorPos.x = pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x); + TextEx(label, label_display_end); + } + + // Convert back + if (value_changed && picker_active_window == NULL) + { + if (!value_changed_as_float) + for (int n = 0; n < 4; n++) + f[n] = i[n] / 255.0f; + if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB)) + { + g.ColorEditSavedHue = f[0]; + g.ColorEditSavedSat = f[1]; + ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]); + g.ColorEditSavedID = g.ColorEditCurrentID; + g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0)); + } + if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); + + col[0] = f[0]; + col[1] = f[1]; + col[2] = f[2]; + if (alpha) + col[3] = f[3]; + } + + if (set_current_color_edit_id) + g.ColorEditCurrentID = 0; + PopID(); + EndGroup(); + + // Drag and Drop Target + // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + { + bool accepted_drag_drop = false; + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086 + value_changed = accepted_drag_drop = true; + } + if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + { + memcpy((float*)col, payload->Data, sizeof(float) * components); + value_changed = accepted_drag_drop = true; + } + + // Drag-drop payloads are always RGB + if (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV)) + ColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]); + EndDragDropTarget(); + } + + // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4(). + if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window) + g.LastItemData.ID = g.ActiveId; + + if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags) +{ + float col4[4] = { col[0], col[1], col[2], 1.0f }; + if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha)) + return false; + col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2]; + return true; +} + +// Helper for ColorPicker4() +static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha) +{ + ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8)); + ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8)); +} + +// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.) +// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..) +// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0) +bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImDrawList* draw_list = window->DrawList; + ImGuiStyle& style = g.Style; + ImGuiIO& io = g.IO; + + const float width = CalcItemWidth(); + g.NextItemData.ClearFlags(); + + PushID(label); + const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0); + if (set_current_color_edit_id) + g.ColorEditCurrentID = window->IDStack.back(); + BeginGroup(); + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + flags |= ImGuiColorEditFlags_NoSmallPreview; + + // Context menu: display and store options. + if (!(flags & ImGuiColorEditFlags_NoOptions)) + ColorPickerOptionsPopup(col, flags); + + // Read stored options + if (!(flags & ImGuiColorEditFlags_PickerMask_)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + if (!(flags & ImGuiColorEditFlags_InputMask_)) + flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected + if (!(flags & ImGuiColorEditFlags_NoOptions)) + flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); + + // Setup + int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; + bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha); + ImVec2 picker_pos = window->DC.CursorPos; + float square_sz = GetFrameHeight(); + float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars + float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box + float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x; + float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; + float bars_triangles_half_sz = IM_FLOOR(bars_width * 0.20f); + + float backup_initial_col[4]; + memcpy(backup_initial_col, col, components * sizeof(float)); + + float wheel_thickness = sv_picker_size * 0.08f; + float wheel_r_outer = sv_picker_size * 0.50f; + float wheel_r_inner = wheel_r_outer - wheel_thickness; + ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); + + // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. + float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); + ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. + ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. + ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. + + float H = col[0], S = col[1], V = col[2]; + float R = col[0], G = col[1], B = col[2]; + if (flags & ImGuiColorEditFlags_InputRGB) + { + // Hue is lost when converting from grayscale rgb (saturation=0). Restore it. + ColorConvertRGBtoHSV(R, G, B, H, S, V); + ColorEditRestoreHS(col, &H, &S, &V); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + + bool value_changed = false, value_changed_h = false, value_changed_sv = false; + + PushItemFlag(ImGuiItemFlags_NoNav, true); + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Hue wheel + SV triangle logic + InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)); + if (IsItemActive()) + { + ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; + ImVec2 current_off = g.IO.MousePos - wheel_center; + float initial_dist2 = ImLengthSqr(initial_off); + if (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1)) + { + // Interactive with Hue wheel + H = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5f; + if (H < 0.0f) + H += 1.0f; + value_changed = value_changed_h = true; + } + float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); + if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) + { + // Interacting with SV triangle + ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); + if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) + current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); + float uu, vv, ww; + ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); + V = ImClamp(1.0f - vv, 0.0001f, 1.0f); + S = ImClamp(uu / V, 0.0001f, 1.0f); + value_changed = value_changed_sv = true; + } + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // SV rectangle logic + InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); + if (IsItemActive()) + { + S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1)); + V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + ColorEditRestoreH(col, &H); // Greatly reduces hue jitter and reset to 0 when hue == 255 and color is rapidly modified using SV square. + value_changed = value_changed_sv = true; + } + if (!(flags & ImGuiColorEditFlags_NoOptions)) + OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); + + // Hue bar logic + SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); + InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + value_changed = value_changed_h = true; + } + } + + // Alpha bar logic + if (alpha_bar) + { + SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)); + InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size)); + if (IsItemActive()) + { + col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1)); + value_changed = true; + } + } + PopItemFlag(); // ImGuiItemFlags_NoNav + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + SameLine(0, style.ItemInnerSpacing.x); + BeginGroup(); + } + + if (!(flags & ImGuiColorEditFlags_NoLabel)) + { + const char* label_display_end = FindRenderedTextEnd(label); + if (label != label_display_end) + { + if ((flags & ImGuiColorEditFlags_NoSidePreview)) + SameLine(0, style.ItemInnerSpacing.x); + TextEx(label, label_display_end); + } + } + + if (!(flags & ImGuiColorEditFlags_NoSidePreview)) + { + PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if ((flags & ImGuiColorEditFlags_NoLabel)) + Text("Current"); + + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; + ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); + if (ref_col != NULL) + { + Text("Original"); + ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]); + if (ColorButton("##original", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2))) + { + memcpy(col, ref_col, components * sizeof(float)); + value_changed = true; + } + } + PopItemFlag(); + EndGroup(); + } + + // Convert back color to RGB + if (value_changed_h || value_changed_sv) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + ColorConvertHSVtoRGB(H, S, V, col[0], col[1], col[2]); + g.ColorEditSavedHue = H; + g.ColorEditSavedSat = S; + g.ColorEditSavedID = g.ColorEditCurrentID; + g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + col[0] = H; + col[1] = S; + col[2] = V; + } + } + + // R,G,B and H,S,V slider color editor + bool value_changed_fix_hue_wrap = false; + if ((flags & ImGuiColorEditFlags_NoInputs) == 0) + { + PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; + if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) + if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) + { + // FIXME: Hackily differentiating using the DragInt (ActiveId != 0 && !ActiveIdAllowOverlap) vs. using the InputText or DropTarget. + // For the later we don't want to run the hue-wrap canceling code. If you are well versed in HSV picker please provide your input! (See #2050) + value_changed_fix_hue_wrap = (g.ActiveId != 0 && !g.ActiveIdAllowOverlap); + value_changed = true; + } + if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) + value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_DisplayHSV); + if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) + value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_DisplayHex); + PopItemWidth(); + } + + // Try to cancel hue wrap (after ColorEdit4 call), if any + if (value_changed_fix_hue_wrap && (flags & ImGuiColorEditFlags_InputRGB)) + { + float new_H, new_S, new_V; + ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V); + if (new_H <= 0 && H > 0) + { + if (new_V <= 0 && V != new_V) + ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]); + else if (new_S <= 0) + ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]); + } + } + + if (value_changed) + { + if (flags & ImGuiColorEditFlags_InputRGB) + { + R = col[0]; + G = col[1]; + B = col[2]; + ColorConvertRGBtoHSV(R, G, B, H, S, V); + ColorEditRestoreHS(col, &H, &S, &V); // Fix local Hue as display below will use it immediately. + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + H = col[0]; + S = col[1]; + V = col[2]; + ColorConvertHSVtoRGB(H, S, V, R, G, B); + } + } + + const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha); + const ImU32 col_black = IM_COL32(0,0,0,style_alpha8); + const ImU32 col_white = IM_COL32(255,255,255,style_alpha8); + const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8); + const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) }; + + ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); + ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f); + ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!! + + ImVec2 sv_cursor_pos; + + if (flags & ImGuiColorEditFlags_PickerHueWheel) + { + // Render Hue Wheel + const float aeps = 0.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out). + const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); + for (int n = 0; n < 6; n++) + { + const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps; + const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; + const int vert_start_idx = draw_list->VtxBuffer.Size; + draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); + draw_list->PathStroke(col_white, 0, wheel_thickness); + const int vert_end_idx = draw_list->VtxBuffer.Size; + + // Paint colors over existing vertices + ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner); + ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner); + ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]); + } + + // Render Cursor + preview on Hue Wheel + float cos_hue_angle = ImCos(H * 2.0f * IM_PI); + float sin_hue_angle = ImSin(H * 2.0f * IM_PI); + ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f); + float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; + int hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others. + draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); + draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); + + // Render SV triangle (rotated according to hue) + ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); + ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); + ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); + ImVec2 uv_white = GetFontTexUvWhitePixel(); + draw_list->PrimReserve(3, 3); + draw_list->PrimVtx(tra, uv_white, hue_color32); + draw_list->PrimVtx(trb, uv_white, col_black); + draw_list->PrimVtx(trc, uv_white, col_white); + draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f); + sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); + } + else if (flags & ImGuiColorEditFlags_PickerHueBar) + { + // Render SV Square + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white); + draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black); + RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f); + sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much + sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2); + + // Render Hue Bar + for (int i = 0; i < 6; ++i) + draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]); + float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size); + RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + } + + // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range) + float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f; + int sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others. + draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments); + draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments); + + // Render alpha bar + if (alpha_bar) + { + float alpha = ImSaturate(col[3]); + ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size); + RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f)); + draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK); + float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size); + RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f); + RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha); + } + + EndGroup(); + + if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0) + value_changed = false; + if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId + MarkItemEdited(g.LastItemData.ID); + + if (set_current_color_edit_id) + g.ColorEditCurrentID = 0; + PopID(); + + return value_changed; +} + +// A little color square. Return true when clicked. +// FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip. +// 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip. +// Note that 'col' may be encoded in HSV if ImGuiColorEditFlags_InputHSV is set. +bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiID id = window->GetID(desc_id); + const float default_size = GetFrameHeight(); + const ImVec2 size(size_arg.x == 0.0f ? default_size : size_arg.x, size_arg.y == 0.0f ? default_size : size_arg.y); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f); + if (!ItemAdd(bb, id)) + return false; + + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held); + + if (flags & ImGuiColorEditFlags_NoAlpha) + flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); + + ImVec4 col_rgb = col; + if (flags & ImGuiColorEditFlags_InputHSV) + ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z); + + ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f); + float grid_step = ImMin(size.x, size.y) / 2.99f; + float rounding = flags & ImGuiColorEditFlags_Round ? ImMin(size_arg.x, size_arg.y) * 0.5f : ImMin(g.Style.FrameRounding, grid_step * 0.5f); + ImRect bb_inner = bb; + float off = 0.0f; + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts. + bb_inner.Expand(off); + } + if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) + { + float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); + window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); + } + else + { + // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha + ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; + if (col_source.w < 1.0f) + RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); + else + window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); + } + RenderNavHighlight(bb, id); + if ((flags & ImGuiColorEditFlags_NoBorder) == 0) + { + if (g.Style.FrameBorderSize > 0.0f) + RenderFrameBorder(bb.Min, bb.Max, rounding); + else + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + } + + // Drag and Drop Source + // NB: The ActiveId test is merely an optional micro-optimization, BeginDragDropSource() does the same test. + if (g.ActiveId == id && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource()) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb, sizeof(float) * 3, ImGuiCond_Once); + else + SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb, sizeof(float) * 4, ImGuiCond_Once); + ColorButton(desc_id, col, flags); + SameLine(); + TextEx("Color"); + EndDragDropSource(); + } + + // Tooltip + if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + + return pressed; +} + +// Initialize/override default color options +void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_; + if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; + if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; + if ((flags & ImGuiColorEditFlags_InputMask_) == 0) + flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected + g.ColorEditOptions = flags; +} + +// Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. +void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) +{ + ImGuiContext& g = *GImGui; + + if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None)) + return; + const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; + if (text_end > text) + { + TextEx(text, text_end); + Separator(); + } + + ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); + ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); + SameLine(); + if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]); + else + Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]); + } + else if (flags & ImGuiColorEditFlags_InputHSV) + { + if (flags & ImGuiColorEditFlags_NoAlpha) + Text("H: %.3f, S: %.3f, V: %.3f", col[0], col[1], col[2]); + else + Text("H: %.3f, S: %.3f, V: %.3f, A: %.3f", col[0], col[1], col[2], col[3]); + } + EndTooltip(); +} + +void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) +{ + bool allow_opt_inputs = !(flags & ImGuiColorEditFlags_DisplayMask_); + bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_); + if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + ImGuiColorEditFlags opts = g.ColorEditOptions; + if (allow_opt_inputs) + { + if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; + if (RadioButton("HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV; + if (RadioButton("Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex; + } + if (allow_opt_datatype) + { + if (allow_opt_inputs) Separator(); + if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8; + if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float; + } + + if (allow_opt_inputs || allow_opt_datatype) + Separator(); + if (Button("Copy as..", ImVec2(-1, 0))) + OpenPopup("Copy"); + if (BeginPopup("Copy")) + { + int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); + char buf[64]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", cr, cg, cb); + if (Selectable(buf)) + SetClipboardText(buf); + if (!(flags & ImGuiColorEditFlags_NoAlpha)) + { + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", cr, cg, cb, ca); + if (Selectable(buf)) + SetClipboardText(buf); + } + EndPopup(); + } + + g.ColorEditOptions = opts; + EndPopup(); +} + +void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) +{ + bool allow_opt_picker = !(flags & ImGuiColorEditFlags_PickerMask_); + bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); + if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) + return; + ImGuiContext& g = *GImGui; + if (allow_opt_picker) + { + ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function + PushItemWidth(picker_size.x); + for (int picker_type = 0; picker_type < 2; picker_type++) + { + // Draw small/thumbnail version of each picker type (over an invisible button for selection) + if (picker_type > 0) Separator(); + PushID(picker_type); + ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha); + if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; + ImVec2 backup_pos = GetCursorScreenPos(); + if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup + g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); + SetCursorScreenPos(backup_pos); + ImVec4 previewing_ref_col; + memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); + ColorPicker4("##previewing_picker", &previewing_ref_col.x, picker_flags); + PopID(); + } + PopItemWidth(); + } + if (allow_opt_alpha_bar) + { + if (allow_opt_picker) Separator(); + CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + } + EndPopup(); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: TreeNode, CollapsingHeader, etc. +//------------------------------------------------------------------------- +// - TreeNode() +// - TreeNodeV() +// - TreeNodeEx() +// - TreeNodeExV() +// - TreeNodeBehavior() [Internal] +// - TreePush() +// - TreePop() +// - GetTreeNodeToLabelSpacing() +// - SetNextItemOpen() +// - CollapsingHeader() +//------------------------------------------------------------------------- + +bool ImGui::TreeNode(const char* str_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, 0, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNode(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + return TreeNodeBehavior(window->GetID(label), 0, label, NULL); +} + +bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) +{ + return TreeNodeExV(str_id, 0, fmt, args); +} + +bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args) +{ + return TreeNodeExV(ptr_id, 0, fmt, args); +} + +bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags, label, NULL); +} + +bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(str_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool is_open = TreeNodeExV(ptr_id, flags, fmt, args); + va_end(args); + return is_open; +} + +bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const char* label, *label_end; + ImFormatStringToTempBufferV(&label, &label_end, fmt, args); + return TreeNodeBehavior(window->GetID(str_id), flags, label, label_end); +} + +bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const char* label, *label_end; + ImFormatStringToTempBufferV(&label, &label_end, fmt, args); + return TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end); +} + +void ImGui::TreeNodeSetOpen(ImGuiID id, bool open) +{ + ImGuiContext& g = *GImGui; + ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage; + storage->SetInt(id, open ? 1 : 0); +} + +bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags) +{ + if (flags & ImGuiTreeNodeFlags_Leaf) + return true; + + // We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function) + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStorage* storage = window->DC.StateStorage; + + bool is_open; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen) + { + if (g.NextItemData.OpenCond & ImGuiCond_Always) + { + is_open = g.NextItemData.OpenVal; + TreeNodeSetOpen(id, is_open); + } + else + { + // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently. + const int stored_value = storage->GetInt(id, -1); + if (stored_value == -1) + { + is_open = g.NextItemData.OpenVal; + TreeNodeSetOpen(id, is_open); + } + else + { + is_open = stored_value != 0; + } + } + } + else + { + is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0; + } + + // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior). + // NB- If we are above max depth we still allow manually opened nodes to be logged. + if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth - g.LogDepthRef) < g.LogDepthToExpand) + is_open = true; + + return is_open; +} + +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; + const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); + + if (!label_end) + label_end = FindRenderedTextEnd(label); + const ImVec2 label_size = CalcTextSize(label, label_end, false); + + // We vertically grow up to current line height up the typical widget height. + const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); + ImRect frame_bb; + frame_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; + frame_bb.Min.y = window->DC.CursorPos.y; + frame_bb.Max.x = window->WorkRect.Max.x; + frame_bb.Max.y = window->DC.CursorPos.y + frame_height; + if (display_frame) + { + // Framed header expand a little outside the default padding, to the edge of InnerClipRect + // (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f) + frame_bb.Min.x -= IM_FLOOR(window->WindowPadding.x * 0.5f - 1.0f); + frame_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f); + } + + const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapser arrow width + Spacing + const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it + const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f); // Include collapser + ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); + ItemSize(ImVec2(text_width, frame_height), padding.y); + + // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing + ImRect interact_bb = frame_bb; + if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) + interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; + + // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. + // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). + // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero. + const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; + bool is_open = TreeNodeUpdateNextOpen(id, flags); + if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth); + + bool item_add = ItemAdd(interact_bb, id); + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + g.LastItemData.DisplayRect = frame_bb; + + if (!item_add) + { + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; + } + + ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; + if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) + button_flags |= ImGuiButtonFlags_AllowOverlap; + if (!is_leaf) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + + // We allow clicking on the arrow section with keyboard modifiers held, in order to easily + // allow browsing a tree while preserving selection with code implementing multi-selection patterns. + // When clicking on the rest of the tree node we always disallow keyboard modifiers. + const float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x; + const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; + const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); + if (window != g.HoveredWindow || !is_mouse_x_over_arrow) + button_flags |= ImGuiButtonFlags_NoKeyModifiers; + + // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. + // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. + // - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=0) + // - Single-click on arrow = Toggle on MouseDown (when _OpenOnArrow=1) + // - Double-click on label = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1) + // - Double-click on arrow = Toggle on MouseDoubleClick (when _OpenOnDoubleClick=1 and _OpenOnArrow=0) + // It is rather standard that arrow click react on Down rather than Up. + // We set ImGuiButtonFlags_PressedOnClickRelease on OpenOnDoubleClick because we want the item to be active on the initial MouseDown in order for drag and drop to work. + if (is_mouse_x_over_arrow) + button_flags |= ImGuiButtonFlags_PressedOnClick; + else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) + button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; + else + button_flags |= ImGuiButtonFlags_PressedOnClickRelease; + + bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; + const bool was_selected = selected; + + bool hovered, held; + bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); + bool toggled = false; + if (!is_leaf) + { + if (pressed && g.DragDropHoldJustPressedId != id) + { + if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id)) + toggled = true; + if (flags & ImGuiTreeNodeFlags_OpenOnArrow) + toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) + toggled = true; + } + else if (pressed && g.DragDropHoldJustPressedId == id) + { + IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); + if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. + toggled = true; + } + + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) + { + toggled = true; + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavMoveRequestCancel(); + } + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority? + { + toggled = true; + NavClearPreferredPosForAxis(ImGuiAxis_X); + NavMoveRequestCancel(); + } + + if (toggled) + { + is_open = !is_open; + window->DC.StateStorage->SetInt(id, is_open); + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen; + } + } + + // In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin; + if (display_frame) + { + // Framed type + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); + else // Leaf without bullet, left-adjusted text + text_pos.x -= text_offset_x -padding.x; + if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) + frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + + if (g.LogEnabled) + LogSetNextTextDecoration("###", "###"); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + } + else + { + // Unframed typed for tree nodes + if (hovered || selected) + { + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); + } + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); + if (g.LogEnabled) + LogSetNextTextDecoration(">", NULL); + RenderText(text_pos, label, label_end, false); + } + + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + TreePushOverrideID(id); + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); + return is_open; +} + +void ImGui::TreePush(const char* str_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(str_id); +} + +void ImGui::TreePush(const void* ptr_id) +{ + ImGuiWindow* window = GetCurrentWindow(); + Indent(); + window->DC.TreeDepth++; + PushID(ptr_id); +} + +void ImGui::TreePushOverrideID(ImGuiID id) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Indent(); + window->DC.TreeDepth++; + PushOverrideID(id); +} + +void ImGui::TreePop() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + Unindent(); + + window->DC.TreeDepth--; + ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); + + // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) + if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) + if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) + { + SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); + NavMoveRequestCancel(); + } + window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; + + IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. + PopID(); +} + +// Horizontal distance preceding label when using TreeNode() or Bullet() +float ImGui::GetTreeNodeToLabelSpacing() +{ + ImGuiContext& g = *GImGui; + return g.FontSize + (g.Style.FramePadding.x * 2.0f); +} + +// Set next TreeNode/CollapsingHeader open state. +void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) +{ + ImGuiContext& g = *GImGui; + if (g.CurrentWindow->SkipItems) + return; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen; + g.NextItemData.OpenVal = is_open; + g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always; +} + +// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). +// This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). +bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label); +} + +// p_visible == NULL : regular collapsing header +// p_visible != NULL && *p_visible == true : show a small close button on the corner of the header, clicking the button will set *p_visible = false +// p_visible != NULL && *p_visible == false : do not show the header at all +// Do not mistake this with the Open state of the header itself, which you can adjust with SetNextItemOpen() or ImGuiTreeNodeFlags_DefaultOpen. +bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + if (p_visible && !*p_visible) + return false; + + ImGuiID id = window->GetID(label); + flags |= ImGuiTreeNodeFlags_CollapsingHeader; + if (p_visible) + flags |= ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton; + bool is_open = TreeNodeBehavior(id, flags, label); + if (p_visible != NULL) + { + // Create a small overlapping close button + // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc. + // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow. + ImGuiContext& g = *GImGui; + ImGuiLastItemData last_item_backup = g.LastItemData; + float button_size = g.FontSize; + float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); + float button_y = g.LastItemData.Rect.Min.y; + ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); + if (CloseButton(close_button_id, ImVec2(button_x, button_y))) + *p_visible = false; + g.LastItemData = last_item_backup; + } + + return is_open; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Selectable +//------------------------------------------------------------------------- +// - Selectable() +//------------------------------------------------------------------------- + +// Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image. +// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id. +// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags. +// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. +bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + // Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle. + ImGuiID id = window->GetID(label); + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y); + ImVec2 pos = window->DC.CursorPos; + pos.y += window->DC.CurrLineTextBaseOffset; + ItemSize(size, 0.0f); + + // Fill horizontal space + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. + const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; + const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; + const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; + if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) + size.x = ImMax(label_size.x, max_x - min_x); + + // Text stays at the submission position, but bounding box may be extended on both sides + const ImVec2 text_min = pos; + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. + ImRect bb(min_x, pos.y, text_max.x, text_max.y); + if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) + { + const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; + const float spacing_y = style.ItemSpacing.y; + const float spacing_L = IM_FLOOR(spacing_x * 0.50f); + const float spacing_U = IM_FLOOR(spacing_y * 0.50f); + bb.Min.x -= spacing_L; + bb.Min.y -= spacing_U; + bb.Max.x += (spacing_x - spacing_L); + bb.Max.y += (spacing_y - spacing_U); + } + //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } + + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackground for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) + { + window->ClipRect.Min.x = window->ParentWorkRect.Min.x; + window->ClipRect.Max.x = window->ParentWorkRect.Max.x; + } + + const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; + const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None); + if (span_all_columns) + { + window->ClipRect.Min.x = backup_clip_rect_min_x; + window->ClipRect.Max.x = backup_clip_rect_max_x; + } + + if (!item_add) + return false; + + const bool disabled_global = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; + if (disabled_item && !disabled_global) // Only testing this as an optimization + BeginDisabled(); + + // FIXME: We can standardize the behavior of those two, we could also keep the fast path of override ClipRect + full push on render only, + // which would be advantageous since most selectable are not selected. + if (span_all_columns && window->DC.CurrentColumns) + PushColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePushBackgroundChannel(); + + // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries + ImGuiButtonFlags button_flags = 0; + if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; } + if (flags & ImGuiSelectableFlags_NoSetKeyOwner) { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; } + if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } + if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } + if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } + if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } + + const bool was_selected = selected; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + + // Auto-select when moved into + // - This will be more fully fleshed in the range-select branch + // - This is not exposed as it won't nicely work with some user side handling of shift/control + // - We cannot do 'if (g.NavJustMovedToId != id) { selected = false; pressed = was_selected; }' for two reasons + // - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope()) + // - (2) usage will fail with clipped items + // The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API. + if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId) + if (g.NavJustMovedToId == id) + selected = pressed = true; + + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard + if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) + { + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + { + SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) + g.NavDisableHighlight = true; + } + } + if (pressed) + MarkItemEdited(id); + + // In this branch, Selectable() cannot toggle the selection so this will never trigger. + if (selected != was_selected) //-V547 + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; + + // Render + if (hovered || selected) + { + const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(bb.Min, bb.Max, col, false, style.SelectableRounding); + } + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); + + if (span_all_columns && window->DC.CurrentColumns) + PopColumnsBackground(); + else if (span_all_columns && g.CurrentTable) + TablePopBackgroundChannel(); + + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); + + // Automatically close popups + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup)) + CloseCurrentPopup(); + + if (disabled_item && !disabled_global) + EndDisabled(); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + return pressed; //-V1020 +} + +bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg) +{ + if (Selectable(label, *p_selected, flags, size_arg)) + { + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: ListBox +//------------------------------------------------------------------------- +// - BeginListBox() +// - EndListBox() +// - ListBox() +//------------------------------------------------------------------------- + +// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). +bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = GetID(label); + const ImVec2 label_size = CalcTextSize(label, NULL, true); + + // Size default to hold ~7.25 items. + // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); + ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); + ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + g.NextItemData.ClearFlags(); + + if (!IsRectVisible(bb.Min, bb.Max)) + { + ItemSize(bb.GetSize(), style.FramePadding.y); + ItemAdd(bb, 0, &frame_bb); + return false; + } + + // FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well. + BeginGroup(); + if (label_size.x > 0.0f) + { + ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y); + RenderText(label_pos, label); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); + } + + BeginChildFrame(id, frame_bb.GetSize()); + return true; +} + +void ImGui::EndListBox() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); + IM_UNUSED(window); + + EndChildFrame(); + EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label +} + +bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) +{ + const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items); + return value_changed; +} + +// This is merely a helper around BeginListBox(), EndListBox(). +// Considering using those directly to submit custom data or store selection differently. +bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) +{ + ImGuiContext& g = *GImGui; + + // Calculate size from "height_in_items" + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + float height_in_items_f = height_in_items + 0.25f; + ImVec2 size(0.0f, ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f)); + + if (!BeginListBox(label, size)) + return false; + + // Assume all items have even height (= 1 line of text). If you need items of different height, + // you can create a custom version of ListBox() in your code without using the clipper. + bool value_changed = false; + ImGuiListClipper clipper; + clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + const char* item_text; + if (!items_getter(data, i, &item_text)) + item_text = "*Unknown item*"; + + PushID(i); + const bool item_selected = (i == *current_item); + if (Selectable(item_text, item_selected)) + { + *current_item = i; + value_changed = true; + } + if (item_selected) + SetItemDefaultFocus(); + PopID(); + } + EndListBox(); + + if (value_changed) + MarkItemEdited(g.LastItemData.ID); + + return value_changed; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: PlotLines, PlotHistogram +//------------------------------------------------------------------------- +// - PlotEx() [Internal] +// - PlotLines() +// - PlotHistogram() +//------------------------------------------------------------------------- +// Plot/Graph widgets are not very good. +// Consider writing your own, or using a third-party one, see: +// - ImPlot https://github.com/epezent/implot +// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions +//------------------------------------------------------------------------- + +int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, const ImVec2& size_arg) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return -1; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + + const ImVec2 label_size = CalcTextSize(label, NULL, true); + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f); + + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); + const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); + ItemSize(total_bb, style.FramePadding.y); + if (!ItemAdd(total_bb, 0, &frame_bb)) + return -1; + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); + + // Determine scale from values if not specified + if (scale_min == FLT_MAX || scale_max == FLT_MAX) + { + float v_min = FLT_MAX; + float v_max = -FLT_MAX; + for (int i = 0; i < values_count; i++) + { + const float v = values_getter(data, i); + if (v != v) // Ignore NaN values + continue; + v_min = ImMin(v_min, v); + v_max = ImMax(v_max, v); + } + if (scale_min == FLT_MAX) + scale_min = v_min; + if (scale_max == FLT_MAX) + scale_max = v_max; + } + + RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); + + const int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1; + int idx_hovered = -1; + if (values_count >= values_count_min) + { + int res_w = ImMin((int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0); + + // Tooltip on hover + if (hovered && inner_bb.Contains(g.IO.MousePos)) + { + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); + const int v_idx = (int)(t * item_count); + IM_ASSERT(v_idx >= 0 && v_idx < values_count); + + const float v0 = values_getter(data, (v_idx + values_offset) % values_count); + const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count); + if (plot_type == ImGuiPlotType_Lines) + SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1); + else if (plot_type == ImGuiPlotType_Histogram) + SetTooltip("%d: %8.4g", v_idx, v0); + idx_hovered = v_idx; + } + + const float t_step = 1.0f / (float)res_w; + const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min)); + + float v0 = values_getter(data, (0 + values_offset) % values_count); + float t0 = 0.0f; + ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) ); // Point in the normalized space of our target rectangle + float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands + + const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram); + const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered); + + for (int n = 0; n < res_w; n++) + { + const float t1 = t0 + t_step; + const int v1_idx = (int)(t0 * item_count + 0.5f); + IM_ASSERT(v1_idx >= 0 && v1_idx < values_count); + const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count); + const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) ); + + // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU. + ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0); + ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t)); + if (plot_type == ImGuiPlotType_Lines) + { + window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + } + else if (plot_type == ImGuiPlotType_Histogram) + { + if (pos1.x >= pos0.x + 2.0f) + pos1.x -= 1.0f; + window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base); + } + + t0 = t1; + tp0 = tp1; + } + } + + // Text overlay + if (overlay_text) + RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f)); + + if (label_size.x > 0.0f) + RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); + + // Return hovered index or -1 if none are hovered. + // This is currently not exposed in the public API because we need a larger redesign of the whole thing, but in the short-term we are making it available in PlotEx(). + return idx_hovered; +} + +struct ImGuiPlotArrayGetterData +{ + const float* Values; + int Stride; + + ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; } +}; + +static float Plot_ArrayGetter(void* data, int idx) +{ + ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data; + const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride); + return v; +} + +void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride) +{ + ImGuiPlotArrayGetterData data(values, stride); + PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size) +{ + PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size); +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: Value helpers +// Those is not very useful, legacy API. +//------------------------------------------------------------------------- +// - Value() +//------------------------------------------------------------------------- + +void ImGui::Value(const char* prefix, bool b) +{ + Text("%s: %s", prefix, (b ? "true" : "false")); +} + +void ImGui::Value(const char* prefix, int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, unsigned int v) +{ + Text("%s: %d", prefix, v); +} + +void ImGui::Value(const char* prefix, float v, const char* float_format) +{ + if (float_format) + { + char fmt[64]; + ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); + Text(fmt, prefix, v); + } + else + { + Text("%s: %.3f", prefix, v); + } +} + +//------------------------------------------------------------------------- +// [SECTION] MenuItem, BeginMenu, EndMenu, etc. +//------------------------------------------------------------------------- +// - ImGuiMenuColumns [Internal] +// - BeginMenuBar() +// - EndMenuBar() +// - BeginMainMenuBar() +// - EndMainMenuBar() +// - BeginMenu() +// - EndMenu() +// - MenuItemEx() [Internal] +// - MenuItem() +//------------------------------------------------------------------------- + +// Helpers for internal use +void ImGuiMenuColumns::Update(float spacing, bool window_reappearing) +{ + if (window_reappearing) + memset(Widths, 0, sizeof(Widths)); + Spacing = (ImU16)spacing; + CalcNextTotalWidth(true); + memset(Widths, 0, sizeof(Widths)); + TotalWidth = NextTotalWidth; + NextTotalWidth = 0; +} + +void ImGuiMenuColumns::CalcNextTotalWidth(bool update_offsets) +{ + ImU16 offset = 0; + bool want_spacing = false; + for (int i = 0; i < IM_ARRAYSIZE(Widths); i++) + { + ImU16 width = Widths[i]; + if (want_spacing && width > 0) + offset += Spacing; + want_spacing |= (width > 0); + if (update_offsets) + { + if (i == 1) { OffsetLabel = offset; } + if (i == 2) { OffsetShortcut = offset; } + if (i == 3) { OffsetMark = offset; } + } + offset += width; + } + NextTotalWidth = offset; +} + +float ImGuiMenuColumns::DeclColumns(float w_icon, float w_label, float w_shortcut, float w_mark) +{ + Widths[0] = ImMax(Widths[0], (ImU16)w_icon); + Widths[1] = ImMax(Widths[1], (ImU16)w_label); + Widths[2] = ImMax(Widths[2], (ImU16)w_shortcut); + Widths[3] = ImMax(Widths[3], (ImU16)w_mark); + CalcNextTotalWidth(false); + return (float)ImMax(TotalWidth, NextTotalWidth); +} + +// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere.. +// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer. +// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary. +// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars. +bool ImGui::BeginMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + if (!(window->Flags & ImGuiWindowFlags_MenuBar)) + return false; + + IM_ASSERT(!window->DC.MenuBarAppending); + BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore + PushID("##menubar"); + + // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. + // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. + ImRect bar_rect = window->MenuBarRect(); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y)); + clip_rect.ClipWith(window->OuterRectClipped); + PushClipRect(clip_rect.Min, clip_rect.Max, false); + + // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags). + window->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); + window->DC.LayoutType = ImGuiLayoutType_Horizontal; + window->DC.IsSameLine = false; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; + window->DC.MenuBarAppending = true; + AlignTextToFramePadding(); + return true; +} + +void ImGui::EndMenuBar() +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + ImGuiContext& g = *GImGui; + + // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. + if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + { + // Try to find out if the request is for one of our child menu + ImGuiWindow* nav_earliest_child = g.NavWindow; + while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) + nav_earliest_child = nav_earliest_child->ParentWindow; + if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0) + { + // To do so we claim focus back, restore NavId and then process the movement request for yet another frame. + // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering) + const ImGuiNavLayer layer = ImGuiNavLayer_Menu; + IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) + FocusWindow(window); + SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); + g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavDisableMouseHover = g.NavMousePosDirty = true; + NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat + } + } + + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + PopClipRect(); + PopID(); + window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. + g.GroupStack.back().EmitItem = false; + EndGroup(); // Restore position on layer 0 + window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.IsSameLine = false; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + window->DC.MenuBarAppending = false; +} + +// Important: calling order matters! +// FIXME: Somehow overlapping with docking tech. +// FIXME: The "rect-cut" aspect of this could be formalized into a lower-level helper (rect-cut: https://halt.software/dead-simple-layouts) +bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, ImGuiDir dir, float axis_size, ImGuiWindowFlags window_flags) +{ + IM_ASSERT(dir != ImGuiDir_None); + + ImGuiWindow* bar_window = FindWindowByName(name); + if (bar_window == NULL || bar_window->BeginCount == 0) + { + // Calculate and set window size/position + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); + ImRect avail_rect = viewport->GetBuildWorkRect(); + ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + ImVec2 pos = avail_rect.Min; + if (dir == ImGuiDir_Right || dir == ImGuiDir_Down) + pos[axis] = avail_rect.Max[axis] - axis_size; + ImVec2 size = avail_rect.GetSize(); + size[axis] = axis_size; + SetNextWindowPos(pos); + SetNextWindowSize(size); + + // Report our size into work area (for next frame) using actual window size + if (dir == ImGuiDir_Up || dir == ImGuiDir_Left) + viewport->BuildWorkOffsetMin[axis] += axis_size; + else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right) + viewport->BuildWorkOffsetMax[axis] -= axis_size; + } + + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint + bool is_open = Begin(name, NULL, window_flags); + PopStyleVar(2); + + return is_open; +} + +bool ImGui::BeginMainMenuBar() +{ + ImGuiContext& g = *GImGui; + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); + + // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. + // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea? + // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings. + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f)); + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar; + float height = GetFrameHeight(); + bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); + g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); + + if (is_open) + BeginMenuBar(); + else + End(); + return is_open; +} + +void ImGui::EndMainMenuBar() +{ + EndMenuBar(); + + // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window + // FIXME: With this strategy we won't be able to restore a NULL focus. + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) + FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); + + End(); +} + +static bool IsRootOfOpenMenuSet() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if ((g.OpenPopupStack.Size <= g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu)) + return false; + + // Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others + // (e.g. inside menu bar vs loose menu items) based on parent ID. + // This would however prevent the use of e.g. PushID() user code submitting menus. + // Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag, + // making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects. + // Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup + // doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu. + // In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer. + // This fixes the most common case of menu opening on hover when moving between window content and menu bar. Multiple different menu sets in same nav layer would still + // open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart + // it likely won't be a problem anyone runs into. + const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; + if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer) + return false; + return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true); +} + +bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); + + // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu) + // The first menu in a hierarchy isn't so hovering doesn't get across (otherwise e.g. resizing borders with ImGuiButtonFlags_FlattenChildren would react), but top-most BeginMenu() will bypass that limitation. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus; + if (window->Flags & ImGuiWindowFlags_ChildMenu) + window_flags |= ImGuiWindowFlags_ChildWindow; + + // If a menu with same the ID was already submitted, we will append to it, matching the behavior of Begin(). + // We are relying on a O(N) search - so O(N log N) over the frame - which seems like the most efficient for the expected small amount of BeginMenu() calls per frame. + // If somehow this is ever becoming a problem we can switch to use e.g. ImGuiStorage mapping key to last frame used. + if (g.MenusIdSubmittedThisFrame.contains(id)) + { + if (menu_is_open) + menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + else + g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values + return menu_is_open; + } + + // Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu + g.MenusIdSubmittedThisFrame.push_back(id); + + ImVec2 label_size = CalcTextSize(label, NULL, true); + + // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window) + // This is only done for items for the menu set and not the full parent window. + const bool menuset_is_open = IsRootOfOpenMenuSet(); + if (menuset_is_open) + PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); + + // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, + // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). + // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. + ImVec2 popup_pos, pos = window->DC.CursorPos; + PushID(label); + if (!enabled) + BeginDisabled(); + const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + bool pressed; + + // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Menu inside an horizontal menu bar + // Selectable extend their highlight by half ItemSpacing in each direction. + // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() + popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + float w = label_size.x; + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); + RenderText(text_pos, label); + PopStyleVar(); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu inside a regular/vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); + float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; + float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame + float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + RenderText(text_pos, label); + if (icon_w > 0.0f) + RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); + RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); + } + if (!enabled) + EndDisabled(); + + const bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover; + if (menuset_is_open) + PopItemFlag(); + + bool want_open = false; + bool want_close = false; + if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) + { + // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu + // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. + bool moving_toward_child_menu = false; + ImGuiPopupData* child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) ? &g.OpenPopupStack[g.BeginPopupStack.Size] : NULL; // Popup candidate (testing below) + ImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL; + if (g.HoveredWindow == window && child_menu_window != NULL) + { + float ref_unit = g.FontSize; // FIXME-DPI + float child_dir = (window->Pos.x < child_menu_window->Pos.x) ? 1.0f : -1.0f; + ImRect next_window_rect = child_menu_window->Rect(); + ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta); + ImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR(); + ImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR(); + float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack. + ta.x += child_dir * -0.5f; + tb.x += child_dir * ref_unit; + tc.x += child_dir * ref_unit; + tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle has maximum height to limit the slope and the bias toward large sub-menus + tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f); + moving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); + //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] + } + + // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) + // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. + // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) + if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover) + want_close = true; + + // Open + if (!menu_is_open && pressed) // Click/activate to open + want_open = true; + else if (!menu_is_open && hovered && !moving_toward_child_menu) // Hover to open + want_open = true; + if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + else + { + // Menu bar + if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it + { + want_close = true; + want_open = menu_is_open = false; + } + else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others + { + want_open = true; + } + else if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open + { + want_open = true; + NavMoveRequestCancel(); + } + } + + if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }' + want_close = true; + if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None)) + ClosePopupToLevel(g.BeginPopupStack.Size, true); + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0)); + PopID(); + + if (want_open && !menu_is_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size) + { + // Don't reopen/recycle same menu level in the same frame, first close the other menu and yield for a frame. + OpenPopup(label); + } + else if (want_open) + { + menu_is_open = true; + OpenPopup(label); + } + + if (menu_is_open) + { + ImGuiLastItemData last_item_in_parent = g.LastItemData; + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos. + PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding + menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + PopStyleVar(); + if (menu_is_open) + { + // Restore LastItemData so IsItemXXXX functions can work after BeginMenu()/EndMenu() + // (This fixes using IsItemClicked() and IsItemHovered(), but IsItemHovered() also relies on its support for ImGuiItemFlags_NoWindowHoverableCheck) + g.LastItemData = last_item_in_parent; + if (g.HoveredWindow == window) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + } + } + else + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + } + + return menu_is_open; +} + +bool ImGui::BeginMenu(const char* label, bool enabled) +{ + return BeginMenuEx(label, NULL, enabled); +} + +void ImGui::EndMenu() +{ + // Nav: When a left move request our menu failed, close ourselves. + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls + ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. + if (window->BeginCount == window->BeginCountPreviousFrame) + if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet()) + if (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical) + { + ClosePopupToLevel(g.BeginPopupStack.Size - 1, true); + NavMoveRequestCancel(); + } + + EndPopup(); +} + +bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut, bool selected, bool enabled) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiStyle& style = g.Style; + ImVec2 pos = window->DC.CursorPos; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + // See BeginMenuEx() for comments about this. + const bool menuset_is_open = IsRootOfOpenMenuSet(); + if (menuset_is_open) + PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true); + + // We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73), + // but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only. + bool pressed; + PushID(label); + if (!enabled) + BeginDisabled(); + + // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. + const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover; + const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; + if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) + { + // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful + // Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark. + float w = label_size.x; + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); + ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); + pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); + PopStyleVar(); + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) + RenderText(text_pos, label); + window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). + } + else + { + // Menu item inside a vertical menu + // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. + // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system. + float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; + float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; + float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); + float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame + float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) + { + RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); + if (icon_w > 0.0f) + RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); + if (shortcut_w > 0.0f) + { + PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); + PopStyleColor(); + } + if (selected) + RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); + } + } + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); + if (!enabled) + EndDisabled(); + PopID(); + if (menuset_is_open) + PopItemFlag(); + + return pressed; +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled) +{ + return MenuItemEx(label, NULL, shortcut, selected, enabled); +} + +bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled) +{ + if (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled)) + { + if (p_selected) + *p_selected = !*p_selected; + return true; + } + return false; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabBar, EndTabBar, etc. +//------------------------------------------------------------------------- +// - BeginTabBar() +// - BeginTabBarEx() [Internal] +// - EndTabBar() +// - TabBarLayout() [Internal] +// - TabBarCalcTabID() [Internal] +// - TabBarCalcMaxTabWidth() [Internal] +// - TabBarFindTabById() [Internal] +// - TabBarFindTabByOrder() [Internal] +// - TabBarGetCurrentTab() [Internal] +// - TabBarGetTabName() [Internal] +// - TabBarRemoveTab() [Internal] +// - TabBarCloseTab() [Internal] +// - TabBarScrollClamp() [Internal] +// - TabBarScrollToTab() [Internal] +// - TabBarQueueFocus() [Internal] +// - TabBarQueueReorder() [Internal] +// - TabBarProcessReorderFromMousePos() [Internal] +// - TabBarProcessReorder() [Internal] +// - TabBarScrollingButtons() [Internal] +// - TabBarTabListPopupButton() [Internal] +//------------------------------------------------------------------------- + +struct ImGuiTabBarSection +{ + int TabCount; // Number of tabs in this section. + float Width; // Sum of width of tabs in this section (after shrinking down) + float Spacing; // Horizontal spacing at the end of the section. + + ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); } +}; + +namespace ImGui +{ + static void TabBarLayout(ImGuiTabBar* tab_bar); + static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window); + static float TabBarCalcMaxTabWidth(); + static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling); + static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections); + static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar); + static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar); +} + +ImGuiTabBar::ImGuiTabBar() +{ + memset(this, 0, sizeof(*this)); + CurrFrameVisible = PrevFrameVisible = -1; + LastTabItemIdx = -1; +} + +static inline int TabItemGetSectionIdx(const ImGuiTabItem* tab) +{ + return (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1; +} + +static int IMGUI_CDECL TabItemComparerBySection(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + const int a_section = TabItemGetSectionIdx(a); + const int b_section = TabItemGetSectionIdx(b); + if (a_section != b_section) + return a_section - b_section; + return (int)(a->IndexDuringLayout - b->IndexDuringLayout); +} + +static int IMGUI_CDECL TabItemComparerByBeginOrder(const void* lhs, const void* rhs) +{ + const ImGuiTabItem* a = (const ImGuiTabItem*)lhs; + const ImGuiTabItem* b = (const ImGuiTabItem*)rhs; + return (int)(a->BeginOrder - b->BeginOrder); +} + +static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref) +{ + ImGuiContext& g = *GImGui; + return ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index); +} + +static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + if (g.TabBars.Contains(tab_bar)) + return ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar)); + return ImGuiPtrOrIndex(tab_bar); +} + +bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiID id = window->GetID(str_id); + ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + tab_bar->ID = id; + return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused); +} + +bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + if ((flags & ImGuiTabBarFlags_DockNode) == 0) + PushOverrideID(tab_bar->ID); + + // Add to stack + g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); + g.CurrentTabBar = tab_bar; + + // Append with multiple BeginTabBar()/EndTabBar() pairs. + tab_bar->BackupCursorPos = window->DC.CursorPos; + if (tab_bar->CurrFrameVisible == g.FrameCount) + { + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); + tab_bar->BeginCount++; + return true; + } + + // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable + if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); + tab_bar->TabsAddedNew = false; + + // Flags + if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + + tab_bar->Flags = flags; + tab_bar->BarRect = tab_bar_bb; + tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() + tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; + tab_bar->CurrFrameVisible = g.FrameCount; + tab_bar->PrevTabsContentsHeight = tab_bar->CurrTabsContentsHeight; + tab_bar->CurrTabsContentsHeight = 0.0f; + tab_bar->ItemSpacingY = g.Style.ItemSpacing.y; + tab_bar->FramePadding = g.Style.FramePadding; + tab_bar->TabsActiveCount = 0; + tab_bar->LastTabItemIdx = -1; + tab_bar->BeginCount = 1; + + // Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY); + + // Draw separator + const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive); + const float y = tab_bar->BarRect.Max.y - 1.0f; + { + const float separator_min_x = tab_bar->BarRect.Min.x - IM_FLOOR(window->WindowPadding.x * 0.5f); + const float separator_max_x = tab_bar->BarRect.Max.x + IM_FLOOR(window->WindowPadding.x * 0.5f); + window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); + } + return true; +} + +void ImGui::EndTabBar() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); + return; + } + + // Fallback in case no TabItem have been submitted + if (tab_bar->WantLayout) + TabBarLayout(tab_bar); + + // Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed(). + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing) + { + tab_bar->CurrTabsContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight); + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->CurrTabsContentsHeight; + } + else + { + window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->PrevTabsContentsHeight; + } + if (tab_bar->BeginCount > 1) + window->DC.CursorPos = tab_bar->BackupCursorPos; + + tab_bar->LastTabItemIdx = -1; + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + PopID(); + + g.CurrentTabBarStack.pop_back(); + g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back()); +} + +// Scrolling happens only in the central section (leading/trailing sections are not scrolling) +static float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar, ImGuiTabBarSection* sections) +{ + return tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing; +} + +// This is called only once a frame before by the first call to ItemTab() +// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions. +static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + tab_bar->WantLayout = false; + + // Garbage collect by compacting list + // Detect if we need to sort out tab list (e.g. in rare case where a tab changed section) + int tab_dst_n = 0; + bool need_sort_by_section = false; + ImGuiTabBarSection sections[3]; // Layout sections: Leading, Central, Trailing + for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n]; + if (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose) + { + // Remove tab + if (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; } + continue; + } + if (tab_dst_n != tab_src_n) + tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n]; + + tab = &tab_bar->Tabs[tab_dst_n]; + tab->IndexDuringLayout = (ImS16)tab_dst_n; + + // We will need sorting if tabs have changed section (e.g. moved from one of Leading/Central/Trailing to another) + int curr_tab_section_n = TabItemGetSectionIdx(tab); + if (tab_dst_n > 0) + { + ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1]; + int prev_tab_section_n = TabItemGetSectionIdx(prev_tab); + if (curr_tab_section_n == 0 && prev_tab_section_n != 0) + need_sort_by_section = true; + if (prev_tab_section_n == 2 && curr_tab_section_n != 2) + need_sort_by_section = true; + } + + sections[curr_tab_section_n].TabCount++; + tab_dst_n++; + } + if (tab_bar->Tabs.Size != tab_dst_n) + tab_bar->Tabs.resize(tab_dst_n); + + if (need_sort_by_section) + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerBySection); + + // Calculate spacing between sections + sections[0].Spacing = sections[0].TabCount > 0 && (sections[1].TabCount + sections[2].TabCount) > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + sections[1].Spacing = sections[1].TabCount > 0 && sections[2].TabCount > 0 ? g.Style.ItemInnerSpacing.x : 0.0f; + + // Setup next selected tab + ImGuiID scroll_to_tab_id = 0; + if (tab_bar->NextSelectedTabId) + { + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId; + tab_bar->NextSelectedTabId = 0; + scroll_to_tab_id = tab_bar->SelectedTabId; + } + + // Process order change request (we could probably process it when requested but it's just saner to do it in a single spot). + if (tab_bar->ReorderRequestTabId != 0) + { + if (TabBarProcessReorder(tab_bar)) + if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId) + scroll_to_tab_id = tab_bar->ReorderRequestTabId; + tab_bar->ReorderRequestTabId = 0; + } + + // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) + const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; + if (tab_list_popup_button) + if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Min.x! + scroll_to_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + + // Leading/Trailing tabs will be shrink only if central one aren't visible anymore, so layout the shrink data as: leading, trailing, central + // (whereas our tabs are stored as: leading, central, trailing) + int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount }; + g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size); + + // Compute ideal tabs widths + store them into shrink buffer + ImGuiTabItem* most_recently_selected_tab = NULL; + int curr_section_n = -1; + bool found_selected_tab_id = false; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible); + + if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button)) + most_recently_selected_tab = tab; + if (tab->ID == tab_bar->SelectedTabId) + found_selected_tab_id = true; + if (scroll_to_tab_id == 0 && g.NavJustMovedToId == tab->ID) + scroll_to_tab_id = tab->ID; + + // Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar. + // Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet, + // and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window. + const char* tab_name = TabBarGetTabName(tab_bar, tab); + const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument); + tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x; + + int section_n = TabItemGetSectionIdx(tab); + ImGuiTabBarSection* section = §ions[section_n]; + section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f); + curr_section_n = section_n; + + // Store data so we can build an array sorted by width if we need to shrink tabs down + IM_MSVC_WARNING_SUPPRESS(6385); + ImGuiShrinkWidthItem* shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++]; + shrink_width_item->Index = tab_n; + shrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth; + tab->Width = ImMax(tab->ContentWidth, 1.0f); + } + + // Compute total ideal width (used for e.g. auto-resizing a window) + tab_bar->WidthAllTabsIdeal = 0.0f; + for (int section_n = 0; section_n < 3; section_n++) + tab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing; + + // Horizontal scrolling buttons + // (note that TabBarScrollButtons() will alter BarRect.Max.x) + if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll)) + if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar)) + { + scroll_to_tab_id = scroll_and_select_tab->ID; + if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0) + tab_bar->SelectedTabId = scroll_to_tab_id; + } + + // Shrink widths if full tabs don't fit in their allocated space + float section_0_w = sections[0].Width + sections[0].Spacing; + float section_1_w = sections[1].Width + sections[1].Spacing; + float section_2_w = sections[2].Width + sections[2].Spacing; + bool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth(); + float width_excess; + if (central_section_is_visible) + width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f); // Excess used to shrink central section + else + width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section + + // With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore + if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible)) + { + int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount); + int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0); + ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess); + + // Apply shrunk values into tabs and sections + for (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index]; + float shrinked_width = IM_FLOOR(g.ShrinkWidthBuffer[tab_n].Width); + if (shrinked_width < 0.0f) + continue; + + shrinked_width = ImMax(1.0f, shrinked_width); + int section_n = TabItemGetSectionIdx(tab); + sections[section_n].Width -= (tab->Width - shrinked_width); + tab->Width = shrinked_width; + } + } + + // Layout all active tabs + int section_tab_index = 0; + float tab_offset = 0.0f; + tab_bar->WidthAllTabs = 0.0f; + for (int section_n = 0; section_n < 3; section_n++) + { + ImGuiTabBarSection* section = §ions[section_n]; + if (section_n == 2) + tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->Width), tab_offset); + + for (int tab_n = 0; tab_n < section->TabCount; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n]; + tab->Offset = tab_offset; + tab->NameOffset = -1; + tab_offset += tab->Width + (tab_n < section->TabCount - 1 ? g.Style.ItemInnerSpacing.x : 0.0f); + } + tab_bar->WidthAllTabs += ImMax(section->Width + section->Spacing, 0.0f); + tab_offset += section->Spacing; + section_tab_index += section->TabCount; + } + + // Clear name buffers + tab_bar->TabsNames.Buf.resize(0); + + // If we have lost the selected tab, select the next most recently active one + if (found_selected_tab_id == false) + tab_bar->SelectedTabId = 0; + if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL) + scroll_to_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID; + + // Lock in visible tab + tab_bar->VisibleTabId = tab_bar->SelectedTabId; + tab_bar->VisibleTabWasSubmitted = false; + + // Apply request requests + if (scroll_to_tab_id != 0) + TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); + else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow)) + { + const float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH; + const ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX; + if (TestKeyOwner(wheel_key, tab_bar->ID) && wheel != 0.0f) + { + const float scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0f; + tab_bar->ScrollingTargetDistToVisibility = 0.0f; + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget - scroll_step); + } + SetKeyOwner(wheel_key, tab_bar->ID); + } + + // Update scrolling + tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim); + tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget); + if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) + { + // Scrolling speed adjust itself so we can always reach our target in 1/3 seconds. + // Teleport if we are aiming far off the visible line + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f * g.FontSize); + tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f); + const bool teleport = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f * g.FontSize); + tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, g.IO.DeltaTime * tab_bar->ScrollingSpeed); + } + else + { + tab_bar->ScrollingSpeed = 0.0f; + } + tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].Width + sections[0].Spacing; + tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].Width - sections[1].Spacing; + + // Actual layout in host window (we don't do it in BeginTabBar() so as not to waste an extra frame) + ImGuiWindow* window = g.CurrentWindow; + window->DC.CursorPos = tab_bar->BarRect.Min; + ItemSize(ImVec2(tab_bar->WidthAllTabs, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y); + window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal); +} + +// Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack. +static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window) +{ + IM_ASSERT(docked_window == NULL); // master branch only + IM_UNUSED(docked_window); + if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) + { + ImGuiID id = ImHashStr(label); + KeepAliveID(id); + return id; + } + else + { + ImGuiWindow* window = GImGui->CurrentWindow; + return window->GetID(label); + } +} + +static float ImGui::TabBarCalcMaxTabWidth() +{ + ImGuiContext& g = *GImGui; + return g.FontSize * 20.0f; +} + +ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (tab_id != 0) + for (int n = 0; n < tab_bar->Tabs.Size; n++) + if (tab_bar->Tabs[n].ID == tab_id) + return &tab_bar->Tabs[n]; + return NULL; +} + +// Order = visible order, not submission order! (which is tab->BeginOrder) +ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order) +{ + if (order < 0 || order >= tab_bar->Tabs.Size) + return NULL; + return &tab_bar->Tabs[order]; +} + +ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar) +{ + if (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size) + return NULL; + return &tab_bar->Tabs[tab_bar->LastTabItemIdx]; +} + +const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if (tab->NameOffset == -1) + return "N/A"; + IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size); + return tab_bar->TabsNames.Buf.Data + tab->NameOffset; +} + +// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. +void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) +{ + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab_bar->Tabs.erase(tab); + if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; } + if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; } + if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; } +} + +// Called on manual closure attempt +void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + if (tab->Flags & ImGuiTabItemFlags_Button) + return; // A button appended with TabItemButton(). + + if (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument)) + { + // This will remove a frame of lag for selecting another tab on closure. + // However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure + tab->WantClose = true; + if (tab_bar->VisibleTabId == tab->ID) + { + tab->LastFrameVisible = -1; + tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0; + } + } + else + { + // Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup) + if (tab_bar->VisibleTabId != tab->ID) + TabBarQueueFocus(tab_bar, tab); + } +} + +static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling) +{ + scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth()); + return ImMax(scrolling, 0.0f); +} + +// Note: we may scroll to tab that are not selected! e.g. using keyboard arrow keys +static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGuiTabBarSection* sections) +{ + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id); + if (tab == NULL) + return; + if (tab->Flags & ImGuiTabItemFlags_SectionMask_) + return; + + ImGuiContext& g = *GImGui; + float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar) + int order = TabBarGetTabOrder(tab_bar, tab); + + // Scrolling happens only in the central section (leading/trailing sections are not scrolling) + float scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections); + + // We make all tabs positions all relative Sections[0].Width to make code simpler + float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f); + float tab_x2 = tab->Offset - sections[0].Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].TabCount ? margin : 1.0f); + tab_bar->ScrollingTargetDistToVisibility = 0.0f; + if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width)) + { + // Scroll to the left + tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f); + tab_bar->ScrollingTarget = tab_x1; + } + else if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width) + { + // Scroll to the right + tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f); + tab_bar->ScrollingTarget = tab_x2 - scrollable_width; + } +} + +void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) +{ + tab_bar->NextSelectedTabId = tab->ID; +} + +void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset) +{ + IM_ASSERT(offset != 0); + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + tab_bar->ReorderRequestTabId = tab->ID; + tab_bar->ReorderRequestOffset = (ImS16)offset; +} + +void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(tab_bar->ReorderRequestTabId == 0); + if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0) + return; + + const bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; + const float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0); + + // Count number of contiguous tabs we are crossing over + const int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1; + const int src_idx = tab_bar->Tabs.index_from_ptr(src_tab); + int dst_idx = src_idx; + for (int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir) + { + // Reordered tabs must share the same section + const ImGuiTabItem* dst_tab = &tab_bar->Tabs[i]; + if (dst_tab->Flags & ImGuiTabItemFlags_NoReorder) + break; + if ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_)) + break; + dst_idx = i; + + // Include spacing after tab, so when mouse cursor is between tabs we would not continue checking further tabs that are not hovered. + const float x1 = bar_offset + dst_tab->Offset - g.Style.ItemInnerSpacing.x; + const float x2 = bar_offset + dst_tab->Offset + dst_tab->Width + g.Style.ItemInnerSpacing.x; + //GetForegroundDrawList()->AddRect(ImVec2(x1, tab_bar->BarRect.Min.y), ImVec2(x2, tab_bar->BarRect.Max.y), IM_COL32(255, 0, 0, 255)); + if ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2)) + break; + } + + if (dst_idx != src_idx) + TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx); +} + +bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar) +{ + ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId); + if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder)) + return false; + + //IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools + int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset; + if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size) + return false; + + // Reordered tabs must share the same section + // (Note: TabBarQueueReorderFromMousePos() also has a similar test but since we allow direct calls to TabBarQueueReorder() we do it here too) + ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order]; + if (tab2->Flags & ImGuiTabItemFlags_NoReorder) + return false; + if ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_)) + return false; + + ImGuiTabItem item_tmp = *tab1; + ImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2; + ImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1; + const int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset; + memmove(dst_tab, src_tab, move_count * sizeof(ImGuiTabItem)); + *tab2 = item_tmp; + + if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings) + MarkIniSettingsDirty(); + return true; +} + +static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); + const float scrolling_buttons_width = arrow_button_size.x * 2.0f; + + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + //window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255)); + + int select_dir = 0; + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + const float backup_repeat_delay = g.IO.KeyRepeatDelay; + const float backup_repeat_rate = g.IO.KeyRepeatRate; + g.IO.KeyRepeatDelay = 0.250f; + g.IO.KeyRepeatRate = 0.200f; + float x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width); + window->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = -1; + window->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y); + if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) + select_dir = +1; + PopStyleColor(2); + g.IO.KeyRepeatRate = backup_repeat_rate; + g.IO.KeyRepeatDelay = backup_repeat_delay; + + ImGuiTabItem* tab_to_scroll_to = NULL; + if (select_dir != 0) + if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + { + int selected_order = TabBarGetTabOrder(tab_bar, tab_item); + int target_order = selected_order + select_dir; + + // Skip tab item buttons until another tab item is found or end is reached + while (tab_to_scroll_to == NULL) + { + // If we are at the end of the list, still scroll to make our tab visible + tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; + + // Cross through buttons + // (even if first/last item is a button, return it so we can update the scroll) + if (tab_to_scroll_to->Flags & ImGuiTabItemFlags_Button) + { + target_order += select_dir; + selected_order += select_dir; + tab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; + } + } + } + window->DC.CursorPos = backup_cursor_pos; + tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f; + + return tab_to_scroll_to; +} + +static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + // We use g.Style.FramePadding.y to match the square ArrowButton size + const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; + const ImVec2 backup_cursor_pos = window->DC.CursorPos; + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y); + tab_bar->BarRect.Min.x += tab_list_popup_button_width; + + ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; + arrow_col.w *= 0.5f; + PushStyleColor(ImGuiCol_Text, arrow_col); + PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest); + PopStyleColor(2); + + ImGuiTabItem* tab_to_select = NULL; + if (open) + { + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + if (tab->Flags & ImGuiTabItemFlags_Button) + continue; + + const char* tab_name = TabBarGetTabName(tab_bar, tab); + if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) + tab_to_select = tab; + } + EndCombo(); + } + + window->DC.CursorPos = backup_cursor_pos; + return tab_to_select; +} + +//------------------------------------------------------------------------- +// [SECTION] Widgets: BeginTabItem, EndTabItem, etc. +//------------------------------------------------------------------------- +// - BeginTabItem() +// - EndTabItem() +// - TabItemButton() +// - TabItemEx() [Internal] +// - SetTabItemClosed() +// - TabItemCalcSize() [Internal] +// - TabItemBackground() [Internal] +// - TabItemLabelAndCloseButton() [Internal] +//------------------------------------------------------------------------- + +bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; + } + IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! + + bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); + if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + PushOverrideID(tab->ID); // We already hashed 'label' so push into the ID stack directly instead of doing another hash through PushID(label) + } + return ret; +} + +void ImGui::EndTabItem() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return; + } + IM_ASSERT(tab_bar->LastTabItemIdx >= 0); + ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; + if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) + PopID(); +} + +bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return false; + } + return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); +} + +bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) +{ + // Layout whole tab bar if not already done + ImGuiContext& g = *GImGui; + if (tab_bar->WantLayout) + { + ImGuiNextItemData backup_next_item_data = g.NextItemData; + TabBarLayout(tab_bar); + g.NextItemData = backup_next_item_data; + } + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImGuiID id = TabBarCalcTabID(tab_bar, label, docked_window); + + // If the user called us with *p_open == false, we early out and don't render. + // We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID. + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags); + if (p_open && !*p_open) + { + ItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav); + return false; + } + + IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button)); + IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)); // Can't use both Leading and Trailing + + // Store into ImGuiTabItemFlags_NoCloseButton, also honor ImGuiTabItemFlags_NoCloseButton passed by user (although not documented) + if (flags & ImGuiTabItemFlags_NoCloseButton) + p_open = NULL; + else if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; + + // Acquire tab data + ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id); + bool tab_is_new = false; + if (tab == NULL) + { + tab_bar->Tabs.push_back(ImGuiTabItem()); + tab = &tab_bar->Tabs.back(); + tab->ID = id; + tab_bar->TabsAddedNew = tab_is_new = true; + } + tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab); + + // Calculate tab contents size + ImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument)); + tab->RequestedWidth = -1.0f; + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) + size.x = tab->RequestedWidth = g.NextItemData.Width; + if (tab_is_new) + tab->Width = ImMax(1.0f, size.x); + tab->ContentWidth = size.x; + tab->BeginOrder = tab_bar->TabsActiveCount++; + + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); + const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; + const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); + const bool tab_just_unsaved = (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument); + const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0; + tab->LastFrameVisible = g.FrameCount; + tab->Flags = flags; + + // Append name _WITH_ the zero-terminator + if (docked_window != NULL) + { + IM_ASSERT(docked_window == NULL); // master branch only + } + else + { + tab->NameOffset = (ImS32)tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); + } + + // Update selected tab + if (!is_tab_button) + { + if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0) + if (!tab_bar_appearing || tab_bar->SelectedTabId == 0) + TabBarQueueFocus(tab_bar, tab); // New tabs gets activated + if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar + TabBarQueueFocus(tab_bar, tab); + } + + // Lock visibility + // (Note: tab_contents_visible != tab_selected... because CTRL+TAB operations may preview some tabs without selecting them!) + bool tab_contents_visible = (tab_bar->VisibleTabId == id); + if (tab_contents_visible) + tab_bar->VisibleTabWasSubmitted = true; + + // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches + if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing) + if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) + tab_contents_visible = true; + + // Note that tab_is_new is not necessarily the same as tab_appearing! When a tab bar stops being submitted + // and then gets submitted again, the tabs will have 'tab_appearing=true' but 'tab_is_new=false'. + if (tab_appearing && (!tab_bar_appearing || tab_is_new)) + { + ItemAdd(ImRect(), id, NULL, ImGuiItemFlags_NoNav); + if (is_tab_button) + return false; + return tab_contents_visible; + } + + if (tab_bar->SelectedTabId == id) + tab->LastFrameSelected = g.FrameCount; + + // Backup current layout position + const ImVec2 backup_main_cursor_pos = window->DC.CursorPos; + + // Layout + const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0; + size.x = tab->Width; + if (is_central_section) + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_FLOOR(tab->Offset - tab_bar->ScrollingAnim), 0.0f); + else + window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f); + ImVec2 pos = window->DC.CursorPos; + ImRect bb(pos, pos + size); + + // We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation) + const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX); + if (want_clip_rect) + PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y), true); + + ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos; + ItemSize(bb.GetSize(), style.FramePadding.y); + window->DC.CursorMaxPos = backup_cursor_max_pos; + + if (!ItemAdd(bb, id)) + { + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + return tab_contents_visible; + } + + // Click to Select a tab + // Allow the close button to overlap + ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); + if (g.DragDropActive) + button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + if (pressed && !is_tab_button) + TabBarQueueFocus(tab_bar, tab); + + // Drag and drop: re-order tabs + if (held && !tab_appearing && IsMouseDragging(0)) + { + if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) + { + // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x + if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) + { + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); + } + else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) + { + TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); + } + } + } + +#if 0 + if (hovered && g.HoveredIdNotActiveTimer > TOOLTIP_DELAY && bb.GetWidth() < tab->ContentWidth) + { + // Enlarge tab display when hovering + bb.Max.x = bb.Min.x + IM_FLOOR(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((g.HoveredIdNotActiveTimer - 0.40f) * 6.0f))); + display_draw_list = GetForegroundDrawList(window); + TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive)); + } +#endif + + // Render tab shape + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + RenderNavHighlight(bb, id); + + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) + TabBarQueueFocus(tab_bar, tab); + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; + bool just_closed; + bool text_clipped; + TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); + if (just_closed && p_open != NULL) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Restore main window position so user can draw there + if (want_clip_rect) + PopClipRect(); + window->DC.CursorPos = backup_main_cursor_pos; + + // Tooltip + // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) + // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) + // FIXME: This is a mess. + // FIXME: We may want disabled tab to still display the tooltip? + if (text_clipped && g.HoveredId == id && !held) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) + SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + + IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected + if (is_tab_button) + return pressed; + return tab_contents_visible; +} + +// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed. +// To use it to need to call the function SetTabItemClosed() between BeginTabBar() and EndTabBar(). +// Tabs closed by the close button will automatically be flagged to avoid this issue. +void ImGui::SetTabItemClosed(const char* label) +{ + ImGuiContext& g = *GImGui; + bool is_within_manual_tab_bar = g.CurrentTabBar && !(g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode); + if (is_within_manual_tab_bar) + { + ImGuiTabBar* tab_bar = g.CurrentTabBar; + ImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL); + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) + tab->WantClose = true; // Will be processed by next call to TabBarLayout() + } +} + +ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f); + if (has_close_button_or_unsaved_marker) + size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle. + else + size.x += g.Style.FramePadding.x + 1.0f; + return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); +} + +ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*) +{ + IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch. + return ImVec2(0.0f, 0.0f); +} + +void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) +{ + // While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it. + ImGuiContext& g = *GImGui; + const float width = bb.GetWidth(); + IM_UNUSED(flags); + IM_ASSERT(width > 0.0f); + const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); + const float y1 = bb.Min.y + 1.0f; + const float y2 = bb.Max.y - 1.0f; + draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); + draw_list->PathFillConvex(col); + if (g.Style.TabBorderSize > 0.0f) + { + draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); + draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9); + draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12); + draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2)); + draw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0, g.Style.TabBorderSize); + } +} + +// Render text label (with custom clipping) + Unsaved Document marker + Close Button logic +// We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. +void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped) +{ + ImGuiContext& g = *GImGui; + ImVec2 label_size = CalcTextSize(label, NULL, true); + + if (out_just_closed) + *out_just_closed = false; + if (out_text_clipped) + *out_text_clipped = false; + + if (bb.GetWidth() <= 1.0f) + return; + + // In Style V2 we'll have full override of all colors per state (e.g. focused, selected) + // But right now if you want to alter text color of tabs this is what you need to do. +#if 0 + const float backup_alpha = g.Style.Alpha; + if (!is_contents_visible) + g.Style.Alpha *= 0.7f; +#endif + + // Render text label (with clipping + alpha gradient) + unsaved marker + ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); + ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + + // Return clipped state ignoring the close button + if (out_text_clipped) + { + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x; + //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); + } + + const float button_sz = g.FontSize; + const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x * 2.0f - button_sz), bb.Min.y); + + // Close Button & Unsaved Marker + // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() + // 'hovered' will be true when hovering the Tab but NOT when hovering the close button + // 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button + // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false + bool close_button_pressed = false; + bool close_button_visible = false; + if (close_button_id != 0) + if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton)) + if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id) + close_button_visible = true; + bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x); + + if (close_button_visible) + { + ImGuiLastItemData last_item_backup = g.LastItemData; + PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); + if (CloseButton(close_button_id, button_pos)) + close_button_pressed = true; + PopStyleVar(); + g.LastItemData = last_item_backup; + + // Close with middle mouse button + if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + close_button_pressed = true; + } + else if (unsaved_marker_visible) + { + const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz) + g.Style.FramePadding * 2.0f); + RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); + } + + // This is all rather complicated + // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) + // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. + float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + if (close_button_visible || unsaved_marker_visible) + { + text_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); + text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; + ellipsis_max_x = text_pixel_clip_bb.Max.x; + } + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); + +#if 0 + if (!is_contents_visible) + g.Style.Alpha = backup_alpha; +#endif + + if (out_just_closed) + *out_just_closed = close_button_pressed; +} + + +#endif // #ifndef IMGUI_DISABLE diff --git a/Amalgam/include/ImGui/imstb_rectpack.h b/Amalgam/include/ImGui/imstb_rectpack.h new file mode 100644 index 0000000..f6917e7 --- /dev/null +++ b/Amalgam/include/ImGui/imstb_rectpack.h @@ -0,0 +1,627 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_rect_pack.h 1.01. +// Grep for [DEAR IMGUI] to find the changes. +// +// stb_rect_pack.h - v1.01 - public domain - rectangle packing +// Sean Barrett 2014 +// +// Useful for e.g. packing rectangular textures into an atlas. +// Does not do rotation. +// +// Before #including, +// +// #define STB_RECT_PACK_IMPLEMENTATION +// +// in the file that you want to have the implementation. +// +// Not necessarily the awesomest packing method, but better than +// the totally naive one in stb_truetype (which is primarily what +// this is meant to replace). +// +// Has only had a few tests run, may have issues. +// +// More docs to come. +// +// No memory allocations; uses qsort() and assert() from stdlib. +// Can override those by defining STBRP_SORT and STBRP_ASSERT. +// +// This library currently uses the Skyline Bottom-Left algorithm. +// +// Please note: better rectangle packers are welcome! Please +// implement them to the same API, but with a different init +// function. +// +// Credits +// +// Library +// Sean Barrett +// Minor features +// Martins Mozeiko +// github:IntellectualKitty +// +// Bugfixes / warning fixes +// Jeremy Jaussaud +// Fabian Giesen +// +// Version history: +// +// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section +// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles +// 0.99 (2019-02-07) warning fixes +// 0.11 (2017-03-03) return packing success/fail result +// 0.10 (2016-10-25) remove cast-away-const to avoid warnings +// 0.09 (2016-08-27) fix compiler warnings +// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) +// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) +// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort +// 0.05: added STBRP_ASSERT to allow replacing assert +// 0.04: fixed minor bug in STBRP_LARGE_RECTS support +// 0.01: initial release +// +// LICENSE +// +// See end of file for license information. + +////////////////////////////////////////////////////////////////////////////// +// +// INCLUDE SECTION +// + +#ifndef STB_INCLUDE_STB_RECT_PACK_H +#define STB_INCLUDE_STB_RECT_PACK_H + +#define STB_RECT_PACK_VERSION 1 + +#ifdef STBRP_STATIC +#define STBRP_DEF static +#else +#define STBRP_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct stbrp_context stbrp_context; +typedef struct stbrp_node stbrp_node; +typedef struct stbrp_rect stbrp_rect; + +typedef int stbrp_coord; + +#define STBRP__MAXVAL 0x7fffffff +// Mostly for internal use, but this is the maximum supported coordinate value. + +STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); +// Assign packed locations to rectangles. The rectangles are of type +// 'stbrp_rect' defined below, stored in the array 'rects', and there +// are 'num_rects' many of them. +// +// Rectangles which are successfully packed have the 'was_packed' flag +// set to a non-zero value and 'x' and 'y' store the minimum location +// on each axis (i.e. bottom-left in cartesian coordinates, top-left +// if you imagine y increasing downwards). Rectangles which do not fit +// have the 'was_packed' flag set to 0. +// +// You should not try to access the 'rects' array from another thread +// while this function is running, as the function temporarily reorders +// the array while it executes. +// +// To pack into another rectangle, you need to call stbrp_init_target +// again. To continue packing into the same rectangle, you can call +// this function again. Calling this multiple times with multiple rect +// arrays will probably produce worse packing results than calling it +// a single time with the full rectangle array, but the option is +// available. +// +// The function returns 1 if all of the rectangles were successfully +// packed and 0 otherwise. + +struct stbrp_rect +{ + // reserved for your use: + int id; + + // input: + stbrp_coord w, h; + + // output: + stbrp_coord x, y; + int was_packed; // non-zero if valid packing + +}; // 16 bytes, nominally + + +STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); +// Initialize a rectangle packer to: +// pack a rectangle that is 'width' by 'height' in dimensions +// using temporary storage provided by the array 'nodes', which is 'num_nodes' long +// +// You must call this function every time you start packing into a new target. +// +// There is no "shutdown" function. The 'nodes' memory must stay valid for +// the following stbrp_pack_rects() call (or calls), but can be freed after +// the call (or calls) finish. +// +// Note: to guarantee best results, either: +// 1. make sure 'num_nodes' >= 'width' +// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' +// +// If you don't do either of the above things, widths will be quantized to multiples +// of small integers to guarantee the algorithm doesn't run out of temporary storage. +// +// If you do #2, then the non-quantized algorithm will be used, but the algorithm +// may run out of temporary storage and be unable to pack some rectangles. + +STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); +// Optionally call this function after init but before doing any packing to +// change the handling of the out-of-temp-memory scenario, described above. +// If you call init again, this will be reset to the default (false). + + +STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); +// Optionally select which packing heuristic the library should use. Different +// heuristics will produce better/worse results for different data sets. +// If you call init again, this will be reset to the default. + +enum +{ + STBRP_HEURISTIC_Skyline_default=0, + STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, + STBRP_HEURISTIC_Skyline_BF_sortHeight +}; + + +////////////////////////////////////////////////////////////////////////////// +// +// the details of the following structures don't matter to you, but they must +// be visible so you can handle the memory allocations for them + +struct stbrp_node +{ + stbrp_coord x,y; + stbrp_node *next; +}; + +struct stbrp_context +{ + int width; + int height; + int align; + int init_mode; + int heuristic; + int num_nodes; + stbrp_node *active_head; + stbrp_node *free_head; + stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' +}; + +#ifdef __cplusplus +} +#endif + +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// IMPLEMENTATION SECTION +// + +#ifdef STB_RECT_PACK_IMPLEMENTATION +#ifndef STBRP_SORT +#include +#define STBRP_SORT qsort +#endif + +#ifndef STBRP_ASSERT +#include +#define STBRP_ASSERT assert +#endif + +#ifdef _MSC_VER +#define STBRP__NOTUSED(v) (void)(v) +#define STBRP__CDECL __cdecl +#else +#define STBRP__NOTUSED(v) (void)sizeof(v) +#define STBRP__CDECL +#endif + +enum +{ + STBRP__INIT_skyline = 1 +}; + +STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) +{ + switch (context->init_mode) { + case STBRP__INIT_skyline: + STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); + context->heuristic = heuristic; + break; + default: + STBRP_ASSERT(0); + } +} + +STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) +{ + if (allow_out_of_mem) + // if it's ok to run out of memory, then don't bother aligning them; + // this gives better packing, but may fail due to OOM (even though + // the rectangles easily fit). @TODO a smarter approach would be to only + // quantize once we've hit OOM, then we could get rid of this parameter. + context->align = 1; + else { + // if it's not ok to run out of memory, then quantize the widths + // so that num_nodes is always enough nodes. + // + // I.e. num_nodes * align >= width + // align >= width / num_nodes + // align = ceil(width/num_nodes) + + context->align = (context->width + context->num_nodes-1) / context->num_nodes; + } +} + +STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) +{ + int i; + + for (i=0; i < num_nodes-1; ++i) + nodes[i].next = &nodes[i+1]; + nodes[i].next = NULL; + context->init_mode = STBRP__INIT_skyline; + context->heuristic = STBRP_HEURISTIC_Skyline_default; + context->free_head = &nodes[0]; + context->active_head = &context->extra[0]; + context->width = width; + context->height = height; + context->num_nodes = num_nodes; + stbrp_setup_allow_out_of_mem(context, 0); + + // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) + context->extra[0].x = 0; + context->extra[0].y = 0; + context->extra[0].next = &context->extra[1]; + context->extra[1].x = (stbrp_coord) width; + context->extra[1].y = (1<<30); + context->extra[1].next = NULL; +} + +// find minimum y position if it starts at x1 +static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) +{ + stbrp_node *node = first; + int x1 = x0 + width; + int min_y, visited_width, waste_area; + + STBRP__NOTUSED(c); + + STBRP_ASSERT(first->x <= x0); + + #if 0 + // skip in case we're past the node + while (node->next->x <= x0) + ++node; + #else + STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency + #endif + + STBRP_ASSERT(node->x <= x0); + + min_y = 0; + waste_area = 0; + visited_width = 0; + while (node->x < x1) { + if (node->y > min_y) { + // raise min_y higher. + // we've accounted for all waste up to min_y, + // but we'll now add more waste for everything we've visted + waste_area += visited_width * (node->y - min_y); + min_y = node->y; + // the first time through, visited_width might be reduced + if (node->x < x0) + visited_width += node->next->x - x0; + else + visited_width += node->next->x - node->x; + } else { + // add waste area + int under_width = node->next->x - node->x; + if (under_width + visited_width > width) + under_width = width - visited_width; + waste_area += under_width * (min_y - node->y); + visited_width += under_width; + } + node = node->next; + } + + *pwaste = waste_area; + return min_y; +} + +typedef struct +{ + int x,y; + stbrp_node **prev_link; +} stbrp__findresult; + +static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) +{ + int best_waste = (1<<30), best_x, best_y = (1 << 30); + stbrp__findresult fr; + stbrp_node **prev, *node, *tail, **best = NULL; + + // align to multiple of c->align + width = (width + c->align - 1); + width -= width % c->align; + STBRP_ASSERT(width % c->align == 0); + + // if it can't possibly fit, bail immediately + if (width > c->width || height > c->height) { + fr.prev_link = NULL; + fr.x = fr.y = 0; + return fr; + } + + node = c->active_head; + prev = &c->active_head; + while (node->x + width <= c->width) { + int y,waste; + y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); + if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL + // bottom left + if (y < best_y) { + best_y = y; + best = prev; + } + } else { + // best-fit + if (y + height <= c->height) { + // can only use it if it first vertically + if (y < best_y || (y == best_y && waste < best_waste)) { + best_y = y; + best_waste = waste; + best = prev; + } + } + } + prev = &node->next; + node = node->next; + } + + best_x = (best == NULL) ? 0 : (*best)->x; + + // if doing best-fit (BF), we also have to try aligning right edge to each node position + // + // e.g, if fitting + // + // ____________________ + // |____________________| + // + // into + // + // | | + // | ____________| + // |____________| + // + // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned + // + // This makes BF take about 2x the time + + if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { + tail = c->active_head; + node = c->active_head; + prev = &c->active_head; + // find first node that's admissible + while (tail->x < width) + tail = tail->next; + while (tail) { + int xpos = tail->x - width; + int y,waste; + STBRP_ASSERT(xpos >= 0); + // find the left position that matches this + while (node->next->x <= xpos) { + prev = &node->next; + node = node->next; + } + STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); + y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); + if (y + height <= c->height) { + if (y <= best_y) { + if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { + best_x = xpos; + //STBRP_ASSERT(y <= best_y); [DEAR IMGUI] + best_y = y; + best_waste = waste; + best = prev; + } + } + } + tail = tail->next; + } + } + + fr.prev_link = best; + fr.x = best_x; + fr.y = best_y; + return fr; +} + +static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) +{ + // find best position according to heuristic + stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); + stbrp_node *node, *cur; + + // bail if: + // 1. it failed + // 2. the best node doesn't fit (we don't always check this) + // 3. we're out of memory + if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { + res.prev_link = NULL; + return res; + } + + // on success, create new node + node = context->free_head; + node->x = (stbrp_coord) res.x; + node->y = (stbrp_coord) (res.y + height); + + context->free_head = node->next; + + // insert the new node into the right starting point, and + // let 'cur' point to the remaining nodes needing to be + // stiched back in + + cur = *res.prev_link; + if (cur->x < res.x) { + // preserve the existing one, so start testing with the next one + stbrp_node *next = cur->next; + cur->next = node; + cur = next; + } else { + *res.prev_link = node; + } + + // from here, traverse cur and free the nodes, until we get to one + // that shouldn't be freed + while (cur->next && cur->next->x <= res.x + width) { + stbrp_node *next = cur->next; + // move the current node to the free list + cur->next = context->free_head; + context->free_head = cur; + cur = next; + } + + // stitch the list back in + node->next = cur; + + if (cur->x < res.x + width) + cur->x = (stbrp_coord) (res.x + width); + +#ifdef _DEBUG + cur = context->active_head; + while (cur->x < context->width) { + STBRP_ASSERT(cur->x < cur->next->x); + cur = cur->next; + } + STBRP_ASSERT(cur->next == NULL); + + { + int count=0; + cur = context->active_head; + while (cur) { + cur = cur->next; + ++count; + } + cur = context->free_head; + while (cur) { + cur = cur->next; + ++count; + } + STBRP_ASSERT(count == context->num_nodes+2); + } +#endif + + return res; +} + +static int STBRP__CDECL rect_height_compare(const void *a, const void *b) +{ + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; + if (p->h > q->h) + return -1; + if (p->h < q->h) + return 1; + return (p->w > q->w) ? -1 : (p->w < q->w); +} + +static int STBRP__CDECL rect_original_order(const void *a, const void *b) +{ + const stbrp_rect *p = (const stbrp_rect *) a; + const stbrp_rect *q = (const stbrp_rect *) b; + return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); +} + +STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) +{ + int i, all_rects_packed = 1; + + // we use the 'was_packed' field internally to allow sorting/unsorting + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = i; + } + + // sort according to heuristic + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); + + for (i=0; i < num_rects; ++i) { + if (rects[i].w == 0 || rects[i].h == 0) { + rects[i].x = rects[i].y = 0; // empty rect needs no space + } else { + stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); + if (fr.prev_link) { + rects[i].x = (stbrp_coord) fr.x; + rects[i].y = (stbrp_coord) fr.y; + } else { + rects[i].x = rects[i].y = STBRP__MAXVAL; + } + } + } + + // unsort + STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); + + // set was_packed flags and all_rects_packed status + for (i=0; i < num_rects; ++i) { + rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); + if (!rects[i].was_packed) + all_rects_packed = 0; + } + + // return the all_rects_packed status + return all_rects_packed; +} +#endif + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/Amalgam/include/ImGui/imstb_textedit.h b/Amalgam/include/ImGui/imstb_textedit.h new file mode 100644 index 0000000..a8a8231 --- /dev/null +++ b/Amalgam/include/ImGui/imstb_textedit.h @@ -0,0 +1,1437 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_textedit.h 1.14. +// Those changes would need to be pushed into nothings/stb: +// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) +// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000) +// Grep for [DEAR IMGUI] to find the changes. + +// stb_textedit.h - v1.14 - public domain - Sean Barrett +// Development of this library was sponsored by RAD Game Tools +// +// This C header file implements the guts of a multi-line text-editing +// widget; you implement display, word-wrapping, and low-level string +// insertion/deletion, and stb_textedit will map user inputs into +// insertions & deletions, plus updates to the cursor position, +// selection state, and undo state. +// +// It is intended for use in games and other systems that need to build +// their own custom widgets and which do not have heavy text-editing +// requirements (this library is not recommended for use for editing large +// texts, as its performance does not scale and it has limited undo). +// +// Non-trivial behaviors are modelled after Windows text controls. +// +// +// LICENSE +// +// See end of file for license information. +// +// +// DEPENDENCIES +// +// Uses the C runtime function 'memmove', which you can override +// by defining STB_TEXTEDIT_memmove before the implementation. +// Uses no other functions. Performs no runtime allocations. +// +// +// VERSION HISTORY +// +// 1.14 (2021-07-11) page up/down, various fixes +// 1.13 (2019-02-07) fix bug in undo size management +// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash +// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield +// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual +// 1.9 (2016-08-27) customizable move-by-word +// 1.8 (2016-04-02) better keyboard handling when mouse button is down +// 1.7 (2015-09-13) change y range handling in case baseline is non-0 +// 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove +// 1.5 (2014-09-10) add support for secondary keys for OS X +// 1.4 (2014-08-17) fix signed/unsigned warnings +// 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary +// 1.2 (2014-05-27) fix some RAD types that had crept into the new code +// 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) +// 1.0 (2012-07-26) improve documentation, initial public release +// 0.3 (2012-02-24) bugfixes, single-line mode; insert mode +// 0.2 (2011-11-28) fixes to undo/redo +// 0.1 (2010-07-08) initial version +// +// ADDITIONAL CONTRIBUTORS +// +// Ulf Winklemann: move-by-word in 1.1 +// Fabian Giesen: secondary key inputs in 1.5 +// Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 +// Louis Schnellbach: page up/down in 1.14 +// +// Bugfixes: +// Scott Graham +// Daniel Keller +// Omar Cornut +// Dan Thompson +// +// USAGE +// +// This file behaves differently depending on what symbols you define +// before including it. +// +// +// Header-file mode: +// +// If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, +// it will operate in "header file" mode. In this mode, it declares a +// single public symbol, STB_TexteditState, which encapsulates the current +// state of a text widget (except for the string, which you will store +// separately). +// +// To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a +// primitive type that defines a single character (e.g. char, wchar_t, etc). +// +// To save space or increase undo-ability, you can optionally define the +// following things that are used by the undo system: +// +// STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position +// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow +// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer +// +// If you don't define these, they are set to permissive types and +// moderate sizes. The undo system does no memory allocations, so +// it grows STB_TexteditState by the worst-case storage which is (in bytes): +// +// [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATECOUNT +// + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHARCOUNT +// +// +// Implementation mode: +// +// If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it +// will compile the implementation of the text edit widget, depending +// on a large number of symbols which must be defined before the include. +// +// The implementation is defined only as static functions. You will then +// need to provide your own APIs in the same file which will access the +// static functions. +// +// The basic concept is that you provide a "string" object which +// behaves like an array of characters. stb_textedit uses indices to +// refer to positions in the string, implicitly representing positions +// in the displayed textedit. This is true for both plain text and +// rich text; even with rich text stb_truetype interacts with your +// code as if there was an array of all the displayed characters. +// +// Symbols that must be the same in header-file and implementation mode: +// +// STB_TEXTEDIT_CHARTYPE the character type +// STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position +// STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow +// STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer +// +// Symbols you must define for implementation mode: +// +// STB_TEXTEDIT_STRING the type of object representing a string being edited, +// typically this is a wrapper object with other data you need +// +// STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) +// STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters +// starting from character #n (see discussion below) +// STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character +// to the xpos of the i+1'th char for a line of characters +// starting at character #n (i.e. accounts for kerning +// with previous char) +// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character +// (return type is int, -1 means not valid to insert) +// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based +// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize +// as manually wordwrapping for end-of-line positioning +// +// STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i +// STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) +// +// STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key +// +// STB_TEXTEDIT_K_LEFT keyboard input to move cursor left +// STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right +// STB_TEXTEDIT_K_UP keyboard input to move cursor up +// STB_TEXTEDIT_K_DOWN keyboard input to move cursor down +// STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page +// STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page +// STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME +// STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END +// STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME +// STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END +// STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor +// STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor +// STB_TEXTEDIT_K_UNDO keyboard input to perform undo +// STB_TEXTEDIT_K_REDO keyboard input to perform redo +// +// Optional: +// STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode +// STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), +// required for default WORDLEFT/WORDRIGHT handlers +// STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to +// STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to +// STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT +// STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT +// STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line +// STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line +// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text +// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text +// +// Keyboard input must be encoded as a single integer value; e.g. a character code +// and some bitflags that represent shift states. to simplify the interface, SHIFT must +// be a bitflag, so we can test the shifted state of cursor movements to allow selection, +// i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. +// +// You can encode other things, such as CONTROL or ALT, in additional bits, and +// then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, +// my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN +// bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, +// and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the +// API below. The control keys will only match WM_KEYDOWN events because of the +// keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN +// bit so it only decodes WM_CHAR events. +// +// STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed +// row of characters assuming they start on the i'th character--the width and +// the height and the number of characters consumed. This allows this library +// to traverse the entire layout incrementally. You need to compute word-wrapping +// here. +// +// Each textfield keeps its own insert mode state, which is not how normal +// applications work. To keep an app-wide insert mode, update/copy the +// "insert_mode" field of STB_TexteditState before/after calling API functions. +// +// API +// +// void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) +// +// void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +// void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) +// +// Each of these functions potentially updates the string and updates the +// state. +// +// initialize_state: +// set the textedit state to a known good default state when initially +// constructing the textedit. +// +// click: +// call this with the mouse x,y on a mouse down; it will update the cursor +// and reset the selection start/end to the cursor point. the x,y must +// be relative to the text widget, with (0,0) being the top left. +// +// drag: +// call this with the mouse x,y on a mouse drag/up; it will update the +// cursor and the selection end point +// +// cut: +// call this to delete the current selection; returns true if there was +// one. you should FIRST copy the current selection to the system paste buffer. +// (To copy, just copy the current selection out of the string yourself.) +// +// paste: +// call this to paste text at the current cursor point or over the current +// selection if there is one. +// +// key: +// call this for keyboard inputs sent to the textfield. you can use it +// for "key down" events or for "translated" key events. if you need to +// do both (as in Win32), or distinguish Unicode characters from control +// inputs, set a high bit to distinguish the two; then you can define the +// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit +// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is +// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to +// anything other type you wante before including. +// +// +// When rendering, you can read the cursor position and selection state from +// the STB_TexteditState. +// +// +// Notes: +// +// This is designed to be usable in IMGUI, so it allows for the possibility of +// running in an IMGUI that has NOT cached the multi-line layout. For this +// reason, it provides an interface that is compatible with computing the +// layout incrementally--we try to make sure we make as few passes through +// as possible. (For example, to locate the mouse pointer in the text, we +// could define functions that return the X and Y positions of characters +// and binary search Y and then X, but if we're doing dynamic layout this +// will run the layout algorithm many times, so instead we manually search +// forward in one pass. Similar logic applies to e.g. up-arrow and +// down-arrow movement.) +// +// If it's run in a widget that *has* cached the layout, then this is less +// efficient, but it's not horrible on modern computers. But you wouldn't +// want to edit million-line files with it. + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//// +//// Header-file mode +//// +//// + +#ifndef INCLUDE_STB_TEXTEDIT_H +#define INCLUDE_STB_TEXTEDIT_H + +//////////////////////////////////////////////////////////////////////// +// +// STB_TexteditState +// +// Definition of STB_TexteditState which you should store +// per-textfield; it includes cursor position, selection state, +// and undo state. +// + +#ifndef STB_TEXTEDIT_UNDOSTATECOUNT +#define STB_TEXTEDIT_UNDOSTATECOUNT 99 +#endif +#ifndef STB_TEXTEDIT_UNDOCHARCOUNT +#define STB_TEXTEDIT_UNDOCHARCOUNT 999 +#endif +#ifndef STB_TEXTEDIT_CHARTYPE +#define STB_TEXTEDIT_CHARTYPE int +#endif +#ifndef STB_TEXTEDIT_POSITIONTYPE +#define STB_TEXTEDIT_POSITIONTYPE int +#endif + +typedef struct +{ + // private data + STB_TEXTEDIT_POSITIONTYPE where; + STB_TEXTEDIT_POSITIONTYPE insert_length; + STB_TEXTEDIT_POSITIONTYPE delete_length; + int char_storage; +} StbUndoRecord; + +typedef struct +{ + // private data + StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; + STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; + short undo_point, redo_point; + int undo_char_point, redo_char_point; +} StbUndoState; + +typedef struct +{ + ///////////////////// + // + // public data + // + + int cursor; + // position of the text cursor within the string + + int select_start; // selection start point + int select_end; + // selection start and end point in characters; if equal, no selection. + // note that start may be less than or greater than end (e.g. when + // dragging the mouse, start is where the initial click was, and you + // can drag in either direction) + + unsigned char insert_mode; + // each textfield keeps its own insert mode state. to keep an app-wide + // insert mode, copy this value in/out of the app state + + int row_count_per_page; + // page size in number of row. + // this value MUST be set to >0 for pageup or pagedown in multilines documents. + + ///////////////////// + // + // private data + // + unsigned char cursor_at_end_of_line; // not implemented yet + unsigned char initialized; + unsigned char has_preferred_x; + unsigned char single_line; + unsigned char padding1, padding2, padding3; + float preferred_x; // this determines where the cursor up/down tries to seek to along x + StbUndoState undostate; +} STB_TexteditState; + + +//////////////////////////////////////////////////////////////////////// +// +// StbTexteditRow +// +// Result of layout query, used by stb_textedit to determine where +// the text in each row is. + +// result of layout query +typedef struct +{ + float x0,x1; // starting x location, end x location (allows for align=right, etc) + float baseline_y_delta; // position of baseline relative to previous row's baseline + float ymin,ymax; // height of row above and below baseline + int num_chars; +} StbTexteditRow; +#endif //INCLUDE_STB_TEXTEDIT_H + + +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// +//// +//// Implementation mode +//// +//// + + +// implementation isn't include-guarded, since it might have indirectly +// included just the "header" portion +#ifdef STB_TEXTEDIT_IMPLEMENTATION + +#ifndef STB_TEXTEDIT_memmove +#include +#define STB_TEXTEDIT_memmove memmove +#endif + + +///////////////////////////////////////////////////////////////////////////// +// +// Mouse input handling +// + +// traverse the layout to locate the nearest character to a display position +static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) +{ + StbTexteditRow r; + int n = STB_TEXTEDIT_STRINGLEN(str); + float base_y = 0, prev_x; + int i=0, k; + + r.x0 = r.x1 = 0; + r.ymin = r.ymax = 0; + r.num_chars = 0; + + // search rows to find one that straddles 'y' + while (i < n) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (r.num_chars <= 0) + return n; + + if (i==0 && y < base_y + r.ymin) + return 0; + + if (y < base_y + r.ymax) + break; + + i += r.num_chars; + base_y += r.baseline_y_delta; + } + + // below all text, return 'after' last character + if (i >= n) + return n; + + // check if it's before the beginning of the line + if (x < r.x0) + return i; + + // check if it's before the end of the line + if (x < r.x1) { + // search characters in row for one that straddles 'x' + prev_x = r.x0; + for (k=0; k < r.num_chars; ++k) { + float w = STB_TEXTEDIT_GETWIDTH(str, i, k); + if (x < prev_x+w) { + if (x < prev_x+w/2) + return k+i; + else + return k+i+1; + } + prev_x += w; + } + // shouldn't happen, but if it does, fall through to end-of-line case + } + + // if the last character is a newline, return that. otherwise return 'after' the last character + if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) + return i+r.num_chars-1; + else + return i+r.num_chars; +} + +// API click: on mouse down, move the cursor to the clicked location, and reset the selection +static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse + // goes off the top or bottom of the text + if( state->single_line ) + { + StbTexteditRow r; + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + y = r.ymin; + } + + state->cursor = stb_text_locate_coord(str, x, y); + state->select_start = state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; +} + +// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location +static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) +{ + int p = 0; + + // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse + // goes off the top or bottom of the text + if( state->single_line ) + { + StbTexteditRow r; + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + y = r.ymin; + } + + if (state->select_start == state->select_end) + state->select_start = state->cursor; + + p = stb_text_locate_coord(str, x, y); + state->cursor = state->select_end = p; +} + +///////////////////////////////////////////////////////////////////////////// +// +// Keyboard input handling +// + +// forward declarations +static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); +static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); +static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); +static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); +static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); + +typedef struct +{ + float x,y; // position of n'th character + float height; // height of line + int first_char, length; // first char of row, and length + int prev_first; // first char of previous row +} StbFindState; + +// find the x/y location of a character, and remember info about the previous row in +// case we get a move-up event (for page up, we'll have to rescan) +static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) +{ + StbTexteditRow r; + int prev_start = 0; + int z = STB_TEXTEDIT_STRINGLEN(str); + int i=0, first; + + if (n == z && single_line) { + // special case if it's at the end (may not be needed?) + STB_TEXTEDIT_LAYOUTROW(&r, str, 0); + find->y = 0; + find->first_char = 0; + find->length = z; + find->height = r.ymax - r.ymin; + find->x = r.x1; + return; + } + + // search rows to find the one that straddles character n + find->y = 0; + + for(;;) { + STB_TEXTEDIT_LAYOUTROW(&r, str, i); + if (n < i + r.num_chars) + break; + if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] special handling for last line + break; // [DEAR IMGUI] + prev_start = i; + i += r.num_chars; + find->y += r.baseline_y_delta; + if (i == z) // [DEAR IMGUI] + break; // [DEAR IMGUI] + } + + find->first_char = first = i; + find->length = r.num_chars; + find->height = r.ymax - r.ymin; + find->prev_first = prev_start; + + // now scan to find xpos + find->x = r.x0; + for (i=0; first+i < n; ++i) + find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); +} + +#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) + +// make the selection/cursor state valid if client altered the string +static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + int n = STB_TEXTEDIT_STRINGLEN(str); + if (STB_TEXT_HAS_SELECTION(state)) { + if (state->select_start > n) state->select_start = n; + if (state->select_end > n) state->select_end = n; + // if clamping forced them to be equal, move the cursor to match + if (state->select_start == state->select_end) + state->cursor = state->select_start; + } + if (state->cursor > n) state->cursor = n; +} + +// delete characters while updating undo +static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) +{ + stb_text_makeundo_delete(str, state, where, len); + STB_TEXTEDIT_DELETECHARS(str, where, len); + state->has_preferred_x = 0; +} + +// delete the section +static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + stb_textedit_clamp(str, state); + if (STB_TEXT_HAS_SELECTION(state)) { + if (state->select_start < state->select_end) { + stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); + state->select_end = state->cursor = state->select_start; + } else { + stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); + state->select_start = state->cursor = state->select_end; + } + state->has_preferred_x = 0; + } +} + +// canoncialize the selection so start <= end +static void stb_textedit_sortselection(STB_TexteditState *state) +{ + if (state->select_end < state->select_start) { + int temp = state->select_end; + state->select_end = state->select_start; + state->select_start = temp; + } +} + +// move cursor to first character of selection +static void stb_textedit_move_to_first(STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_sortselection(state); + state->cursor = state->select_start; + state->select_end = state->select_start; + state->has_preferred_x = 0; + } +} + +// move cursor to last character of selection +static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_sortselection(state); + stb_textedit_clamp(str, state); + state->cursor = state->select_end; + state->select_start = state->select_end; + state->has_preferred_x = 0; + } +} + +#ifdef STB_TEXTEDIT_IS_SPACE +static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) +{ + return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; +} + +#ifndef STB_TEXTEDIT_MOVEWORDLEFT +static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) +{ + --c; // always move at least one character + while( c >= 0 && !is_word_boundary( str, c ) ) + --c; + + if( c < 0 ) + c = 0; + + return c; +} +#define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous +#endif + +#ifndef STB_TEXTEDIT_MOVEWORDRIGHT +static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) +{ + const int len = STB_TEXTEDIT_STRINGLEN(str); + ++c; // always move at least one character + while( c < len && !is_word_boundary( str, c ) ) + ++c; + + if( c > len ) + c = len; + + return c; +} +#define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next +#endif + +#endif + +// update selection and cursor to match each other +static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) +{ + if (!STB_TEXT_HAS_SELECTION(state)) + state->select_start = state->select_end = state->cursor; + else + state->cursor = state->select_end; +} + +// API cut: delete selection +static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + if (STB_TEXT_HAS_SELECTION(state)) { + stb_textedit_delete_selection(str,state); // implicitly clamps + state->has_preferred_x = 0; + return 1; + } + return 0; +} + +// API paste: replace existing selection with passed-in text +static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) +{ + // if there's a selection, the paste should delete it + stb_textedit_clamp(str, state); + stb_textedit_delete_selection(str,state); + // try to insert the characters + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { + stb_text_makeundo_insert(state, state->cursor, len); + state->cursor += len; + state->has_preferred_x = 0; + return 1; + } + // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) + return 0; +} + +#ifndef STB_TEXTEDIT_KEYTYPE +#define STB_TEXTEDIT_KEYTYPE int +#endif + +// API key: process a keyboard input +static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) +{ +retry: + switch (key) { + default: { + int c = STB_TEXTEDIT_KEYTOTEXT(key); + if (c > 0) { + STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; + + // can't add newline in single-line mode + if (c == '\n' && state->single_line) + break; + + if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { + stb_text_makeundo_replace(str, state, state->cursor, 1, 1); + STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + ++state->cursor; + state->has_preferred_x = 0; + } + } else { + stb_textedit_delete_selection(str,state); // implicitly clamps + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + stb_text_makeundo_insert(state, state->cursor, 1); + ++state->cursor; + state->has_preferred_x = 0; + } + } + } + break; + } + +#ifdef STB_TEXTEDIT_K_INSERT + case STB_TEXTEDIT_K_INSERT: + state->insert_mode = !state->insert_mode; + break; +#endif + + case STB_TEXTEDIT_K_UNDO: + stb_text_undo(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_REDO: + stb_text_redo(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_LEFT: + // if currently there's a selection, move cursor to start of selection + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else + if (state->cursor > 0) + --state->cursor; + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_RIGHT: + // if currently there's a selection, move cursor to end of selection + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else + ++state->cursor; + stb_textedit_clamp(str, state); + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + // move selection left + if (state->select_end > 0) + --state->select_end; + state->cursor = state->select_end; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_MOVEWORDLEFT + case STB_TEXTEDIT_K_WORDLEFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); + stb_textedit_clamp( str, state ); + } + break; + + case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: + if( !STB_TEXT_HAS_SELECTION( state ) ) + stb_textedit_prep_selection_at_cursor(state); + + state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); + state->select_end = state->cursor; + + stb_textedit_clamp( str, state ); + break; +#endif + +#ifdef STB_TEXTEDIT_MOVEWORDRIGHT + case STB_TEXTEDIT_K_WORDRIGHT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + else { + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); + stb_textedit_clamp( str, state ); + } + break; + + case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: + if( !STB_TEXT_HAS_SELECTION( state ) ) + stb_textedit_prep_selection_at_cursor(state); + + state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); + state->select_end = state->cursor; + + stb_textedit_clamp( str, state ); + break; +#endif + + case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + // move selection right + ++state->select_end; + stb_textedit_clamp(str, state); + state->cursor = state->select_end; + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_DOWN: + case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: + case STB_TEXTEDIT_K_PGDOWN: + case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { + StbFindState find; + StbTexteditRow row; + int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; + int row_count = is_page ? state->row_count_per_page : 1; + + if (!is_page && state->single_line) { + // on windows, up&down in single-line behave like left&right + key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); + goto retry; + } + + if (sel) + stb_textedit_prep_selection_at_cursor(state); + else if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_last(str, state); + + // compute current position of cursor point + stb_textedit_clamp(str, state); + stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + for (j = 0; j < row_count; ++j) { + float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; + int start = find.first_char + find.length; + + if (find.length == 0) + break; + + // [DEAR IMGUI] + // going down while being on the last line shouldn't bring us to that line end + if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) + break; + + // now find character position down a row + state->cursor = start; + STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); + x = row.x0; + for (i=0; i < row.num_chars; ++i) { + float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); + #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE + if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) + break; + #endif + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + stb_textedit_clamp(str, state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + + if (sel) + state->select_end = state->cursor; + + // go to next line + find.first_char = find.first_char + find.length; + find.length = row.num_chars; + } + break; + } + + case STB_TEXTEDIT_K_UP: + case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: + case STB_TEXTEDIT_K_PGUP: + case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { + StbFindState find; + StbTexteditRow row; + int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; + int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; + int row_count = is_page ? state->row_count_per_page : 1; + + if (!is_page && state->single_line) { + // on windows, up&down become left&right + key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); + goto retry; + } + + if (sel) + stb_textedit_prep_selection_at_cursor(state); + else if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_move_to_first(state); + + // compute current position of cursor point + stb_textedit_clamp(str, state); + stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); + + for (j = 0; j < row_count; ++j) { + float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; + + // can only go up if there's a previous row + if (find.prev_first == find.first_char) + break; + + // now find character position up a row + state->cursor = find.prev_first; + STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); + x = row.x0; + for (i=0; i < row.num_chars; ++i) { + float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); + #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE + if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) + break; + #endif + x += dx; + if (x > goal_x) + break; + ++state->cursor; + } + stb_textedit_clamp(str, state); + + state->has_preferred_x = 1; + state->preferred_x = goal_x; + + if (sel) + state->select_end = state->cursor; + + // go to previous line + // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) + prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; + while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) + --prev_scan; + find.first_char = find.prev_first; + find.prev_first = prev_scan; + } + break; + } + + case STB_TEXTEDIT_K_DELETE: + case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_delete_selection(str, state); + else { + int n = STB_TEXTEDIT_STRINGLEN(str); + if (state->cursor < n) + stb_textedit_delete(str, state, state->cursor, 1); + } + state->has_preferred_x = 0; + break; + + case STB_TEXTEDIT_K_BACKSPACE: + case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: + if (STB_TEXT_HAS_SELECTION(state)) + stb_textedit_delete_selection(str, state); + else { + stb_textedit_clamp(str, state); + if (state->cursor > 0) { + stb_textedit_delete(str, state, state->cursor-1, 1); + --state->cursor; + } + } + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2: +#endif + case STB_TEXTEDIT_K_TEXTSTART: + state->cursor = state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2: +#endif + case STB_TEXTEDIT_K_TEXTEND: + state->cursor = STB_TEXTEDIT_STRINGLEN(str); + state->select_start = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTSTART2 + case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = 0; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_TEXTEND2 + case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: + stb_textedit_prep_selection_at_cursor(state); + state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); + state->has_preferred_x = 0; + break; + + +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2: +#endif + case STB_TEXTEDIT_K_LINESTART: + stb_textedit_clamp(str, state); + stb_textedit_move_to_first(state); + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2: +#endif + case STB_TEXTEDIT_K_LINEEND: { + int n = STB_TEXTEDIT_STRINGLEN(str); + stb_textedit_clamp(str, state); + stb_textedit_move_to_first(state); + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; + state->has_preferred_x = 0; + break; + } + +#ifdef STB_TEXTEDIT_K_LINESTART2 + case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + if (state->single_line) + state->cursor = 0; + else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) + --state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + break; + +#ifdef STB_TEXTEDIT_K_LINEEND2 + case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: +#endif + case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { + int n = STB_TEXTEDIT_STRINGLEN(str); + stb_textedit_clamp(str, state); + stb_textedit_prep_selection_at_cursor(state); + if (state->single_line) + state->cursor = n; + else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) + ++state->cursor; + state->select_end = state->cursor; + state->has_preferred_x = 0; + break; + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// Undo processing +// +// @OPTIMIZE: the undo/redo buffer should be circular + +static void stb_textedit_flush_redo(StbUndoState *state) +{ + state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; +} + +// discard the oldest entry in the undo list +static void stb_textedit_discard_undo(StbUndoState *state) +{ + if (state->undo_point > 0) { + // if the 0th undo state has characters, clean those up + if (state->undo_rec[0].char_storage >= 0) { + int n = state->undo_rec[0].insert_length, i; + // delete n characters from all other records + state->undo_char_point -= n; + STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); + for (i=0; i < state->undo_point; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it + } + --state->undo_point; + STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); + } +} + +// discard the oldest entry in the redo list--it's bad if this +// ever happens, but because undo & redo have to store the actual +// characters in different cases, the redo character buffer can +// fill up even though the undo buffer didn't +static void stb_textedit_discard_redo(StbUndoState *state) +{ + int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; + + if (state->redo_point <= k) { + // if the k'th undo state has characters, clean those up + if (state->undo_rec[k].char_storage >= 0) { + int n = state->undo_rec[k].insert_length, i; + // move the remaining redo character data to the end of the buffer + state->redo_char_point += n; + STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); + // adjust the position of all the other records to account for above memmove + for (i=state->redo_point; i < k; ++i) + if (state->undo_rec[i].char_storage >= 0) + state->undo_rec[i].char_storage += n; + } + // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' + // [DEAR IMGUI] + size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); + const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; + const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; + IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); + IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); + STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); + + // now move redo_point to point to the new one + ++state->redo_point; + } +} + +static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) +{ + // any time we create a new undo record, we discard redo + stb_textedit_flush_redo(state); + + // if we have no free records, we have to make room, by sliding the + // existing records down + if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + stb_textedit_discard_undo(state); + + // if the characters to store won't possibly fit in the buffer, we can't undo + if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { + state->undo_point = 0; + state->undo_char_point = 0; + return NULL; + } + + // if we don't have enough free characters in the buffer, we have to make room + while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) + stb_textedit_discard_undo(state); + + return &state->undo_rec[state->undo_point++]; +} + +static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) +{ + StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); + if (r == NULL) + return NULL; + + r->where = pos; + r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; + r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; + + if (insert_len == 0) { + r->char_storage = -1; + return NULL; + } else { + r->char_storage = state->undo_char_point; + state->undo_char_point += insert_len; + return &state->undo_char[r->char_storage]; + } +} + +static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + StbUndoState *s = &state->undostate; + StbUndoRecord u, *r; + if (s->undo_point == 0) + return; + + // we need to do two things: apply the undo record, and create a redo record + u = s->undo_rec[s->undo_point-1]; + r = &s->undo_rec[s->redo_point-1]; + r->char_storage = -1; + + r->insert_length = u.delete_length; + r->delete_length = u.insert_length; + r->where = u.where; + + if (u.delete_length) { + // if the undo record says to delete characters, then the redo record will + // need to re-insert the characters that get deleted, so we need to store + // them. + + // there are three cases: + // there's enough room to store the characters + // characters stored for *redoing* don't leave room for redo + // characters stored for *undoing* don't leave room for redo + // if the last is true, we have to bail + + if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { + // the undo records take up too much character space; there's no space to store the redo characters + r->insert_length = 0; + } else { + int i; + + // there's definitely room to store the characters eventually + while (s->undo_char_point + u.delete_length > s->redo_char_point) { + // should never happen: + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + // there's currently not enough room, so discard a redo record + stb_textedit_discard_redo(s); + } + r = &s->undo_rec[s->redo_point-1]; + + r->char_storage = s->redo_char_point - u.delete_length; + s->redo_char_point = s->redo_char_point - u.delete_length; + + // now save the characters + for (i=0; i < u.delete_length; ++i) + s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); + } + + // now we can carry out the deletion + STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); + } + + // check type of recorded action: + if (u.insert_length) { + // easy case: was a deletion, so we need to insert n characters + STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); + s->undo_char_point -= u.insert_length; + } + + state->cursor = u.where + u.insert_length; + + s->undo_point--; + s->redo_point--; +} + +static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) +{ + StbUndoState *s = &state->undostate; + StbUndoRecord *u, r; + if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) + return; + + // we need to do two things: apply the redo record, and create an undo record + u = &s->undo_rec[s->undo_point]; + r = s->undo_rec[s->redo_point]; + + // we KNOW there must be room for the undo record, because the redo record + // was derived from an undo record + + u->delete_length = r.insert_length; + u->insert_length = r.delete_length; + u->where = r.where; + u->char_storage = -1; + + if (r.delete_length) { + // the redo record requires us to delete characters, so the undo record + // needs to store the characters + + if (s->undo_char_point + u->insert_length > s->redo_char_point) { + u->insert_length = 0; + u->delete_length = 0; + } else { + int i; + u->char_storage = s->undo_char_point; + s->undo_char_point = s->undo_char_point + u->insert_length; + + // now save the characters + for (i=0; i < u->insert_length; ++i) + s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); + } + + STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); + } + + if (r.insert_length) { + // easy case: need to insert n characters + STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); + s->redo_char_point += r.insert_length; + } + + state->cursor = r.where + r.insert_length; + + s->undo_point++; + s->redo_point++; +} + +static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) +{ + stb_text_createundo(&state->undostate, where, 0, length); +} + +static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) +{ + int i; + STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); + if (p) { + for (i=0; i < length; ++i) + p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); + } +} + +static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) +{ + int i; + STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); + if (p) { + for (i=0; i < old_length; ++i) + p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); + } +} + +// reset the state to default +static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) +{ + state->undostate.undo_point = 0; + state->undostate.undo_char_point = 0; + state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; + state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; + state->select_end = state->select_start = 0; + state->cursor = 0; + state->has_preferred_x = 0; + state->preferred_x = 0; + state->cursor_at_end_of_line = 0; + state->initialized = 1; + state->single_line = (unsigned char) is_single_line; + state->insert_mode = 0; + state->row_count_per_page = 0; +} + +// API initialize +static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) +{ + stb_textedit_clear_state(state, is_single_line); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) +{ + return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif//STB_TEXTEDIT_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/Amalgam/include/ImGui/imstb_truetype.h b/Amalgam/include/ImGui/imstb_truetype.h new file mode 100644 index 0000000..35c827e --- /dev/null +++ b/Amalgam/include/ImGui/imstb_truetype.h @@ -0,0 +1,5085 @@ +// [DEAR IMGUI] +// This is a slightly modified version of stb_truetype.h 1.26. +// Mostly fixing for compiler and static analyzer warnings. +// Grep for [DEAR IMGUI] to find the changes. + +// stb_truetype.h - v1.26 - public domain +// authored from 2009-2021 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning +// +// Misc other: +// Ryan Gordon +// Simon Glass +// github:IntellectualKitty +// Imanol Celaya +// Daniel Ribeiro Maciel +// +// Bug/warning reports/fixes: +// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe +// Cass Everitt Martins Mozeiko github:aloucks +// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam +// Brian Hook Omar Cornut github:vassvik +// Walter van Niftrik Ryan Griege +// David Gow Peter LaValle +// David Given Sergey Popov +// Ivan-Assen Ivanov Giumo X. Clanjor +// Anthony Pesch Higor Euripedes +// Johan Duparc Thomas Fields +// Hou Qiming Derek Vinyard +// Rob Loach Cort Stratton +// Kenney Phillis Jr. Brian Costabile +// Ken Voskuil (kaesve) +// +// VERSION HISTORY +// +// 1.26 (2021-08-28) fix broken rasterizer +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// variant PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// +// Full history can be found at the end of this file. +// +// LICENSE +// +// See end of file for license information. +// +// USAGE +// +// Include this file in whatever places need to refer to it. In ONE C/C++ +// file, write: +// #define STB_TRUETYPE_IMPLEMENTATION +// before the #include of this file. This expands out the actual +// implementation into that C/C++ file. +// +// To make the implementation private to the file that generates the implementation, +// #define STBTT_STATIC +// +// Simple 3D API (don't ship this, but it's fine for tools and quick start) +// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture +// stbtt_GetBakedQuad() -- compute quad to draw for a given char +// +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversampling() -- for improved quality on small fonts +// stbtt_PackFontRanges() -- pack and renders +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// +// "Load" a font file from a memory buffer (you have to keep the buffer loaded) +// stbtt_InitFont() +// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections +// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections +// +// Render a unicode codepoint to a bitmap +// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap +// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide +// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be +// +// Character advance/positioning +// stbtt_GetCodepointHMetrics() +// stbtt_GetFontVMetrics() +// stbtt_GetFontVMetricsOS2() +// stbtt_GetCodepointKernAdvance() +// +// Starting with version 1.06, the rasterizer was replaced with a new, +// faster and generally-more-precise rasterizer. The new rasterizer more +// accurately measures pixel coverage for anti-aliasing, except in the case +// where multiple shapes overlap, in which case it overestimates the AA pixel +// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If +// this turns out to be a problem, you can re-enable the old rasterizer with +// #define STBTT_RASTERIZER_VERSION 1 +// which will incur about a 15% speed hit. +// +// ADDITIONAL DOCUMENTATION +// +// Immediately after this block comment are a series of sample programs. +// +// After the sample programs is the "header file" section. This section +// includes documentation for each API function. +// +// Some important concepts to understand to use this library: +// +// Codepoint +// Characters are defined by unicode codepoints, e.g. 65 is +// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is +// the hiragana for "ma". +// +// Glyph +// A visual character shape (every codepoint is rendered as +// some glyph) +// +// Glyph index +// A font-specific integer ID representing a glyph +// +// Baseline +// Glyph shapes are defined relative to a baseline, which is the +// bottom of uppercase characters. Characters extend both above +// and below the baseline. +// +// Current Point +// As you draw text to the screen, you keep track of a "current point" +// which is the origin of each character. The current point's vertical +// position is the baseline. Even "baked fonts" use this model. +// +// Vertical Font Metrics +// The vertical qualities of the font, used to vertically position +// and space the characters. See docs for stbtt_GetFontVMetrics. +// +// Font Size in Pixels or Points +// The preferred interface for specifying font sizes in stb_truetype +// is to specify how tall the font's vertical extent should be in pixels. +// If that sounds good enough, skip the next paragraph. +// +// Most font APIs instead use "points", which are a common typographic +// measurement for describing font size, defined as 72 points per inch. +// stb_truetype provides a point API for compatibility. However, true +// "per inch" conventions don't make much sense on computer displays +// since different monitors have different number of pixels per +// inch. For example, Windows traditionally uses a convention that +// there are 96 pixels per inch, thus making 'inch' measurements have +// nothing to do with inches, and thus effectively defining a point to +// be 1.333 pixels. Additionally, the TrueType font data provides +// an explicit scale factor to scale a given font's glyphs to points, +// but the author has observed that this scale factor is often wrong +// for non-commercial fonts, thus making fonts scaled in points +// according to the TrueType spec incoherently sized in practice. +// +// DETAILED USAGE: +// +// Scale: +// Select how high you want the font to be, in points or pixels. +// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute +// a scale factor SF that will be used by all other functions. +// +// Baseline: +// You need to select a y-coordinate that is the baseline of where +// your text will appear. Call GetFontBoundingBox to get the baseline-relative +// bounding box for all characters. SF*-y0 will be the distance in pixels +// that the worst-case character could extend above the baseline, so if +// you want the top edge of characters to appear at the top of the +// screen where y=0, then you would set the baseline to SF*-y0. +// +// Current point: +// Set the current point where the first character will appear. The +// first character could extend left of the current point; this is font +// dependent. You can either choose a current point that is the leftmost +// point and hope, or add some padding, or check the bounding box or +// left-side-bearing of the first character to be displayed and set +// the current point based on that. +// +// Displaying a character: +// Compute the bounding box of the character. It will contain signed values +// relative to . I.e. if it returns x0,y0,x1,y1, +// then the character should be displayed in the rectangle from +// to = 32 && *text < 128) { + stbtt_aligned_quad q; + stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 + glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); + glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); + glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); + glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); + } + ++text; + } + glEnd(); +} +#endif +// +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program (this compiles): get a single bitmap, print as ASCII art +// +#if 0 +#include +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#include "stb_truetype.h" + +char ttf_buffer[1<<25]; + +int main(int argc, char **argv) +{ + stbtt_fontinfo font; + unsigned char *bitmap; + int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); + + fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); + + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); + bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); + + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) + putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); + putchar('\n'); + } + return 0; +} +#endif +// +// Output: +// +// .ii. +// @@@@@@. +// V@Mio@@o +// :i. V@V +// :oM@@M +// :@@@MM@M +// @@o o@M +// :@@. M@M +// @@@o@@@@ +// :M@@V:@@. +// +////////////////////////////////////////////////////////////////////////////// +// +// Complete program: print "Hello World!" banner, with bugs +// +#if 0 +char buffer[24<<20]; +unsigned char screen[20][79]; + +int main(int arg, char **argv) +{ + stbtt_fontinfo font; + int i,j,ascent,baseline,ch=0; + float scale, xpos=2; // leave a little padding in case the character extends left + char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness + + fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); + stbtt_InitFont(&font, buffer, 0); + + scale = stbtt_ScaleForPixelHeight(&font, 15); + stbtt_GetFontVMetrics(&font, &ascent,0,0); + baseline = (int) (ascent*scale); + + while (text[ch]) { + int advance,lsb,x0,y0,x1,y1; + float x_shift = xpos - (float) floor(xpos); + stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); + stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); + stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); + // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong + // because this API is really for baking character bitmaps into textures. if you want to render + // a sequence of characters, you really need to render each bitmap to a temp buffer, then + // "alpha blend" that into the working buffer + xpos += (advance * scale); + if (text[ch+1]) + xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); + ++ch; + } + + for (j=0; j < 20; ++j) { + for (i=0; i < 78; ++i) + putchar(" .:ioVM@"[screen[j][i]>>5]); + putchar('\n'); + } + + return 0; +} +#endif + + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +//// +//// INTEGRATION WITH YOUR CODEBASE +//// +//// The following sections allow you to supply alternate definitions +//// of C library functions used by stb_truetype, e.g. if you don't +//// link with the C runtime library. + +#ifdef STB_TRUETYPE_IMPLEMENTATION + // #define your own (u)stbtt_int8/16/32 before including to override this + #ifndef stbtt_uint8 + typedef unsigned char stbtt_uint8; + typedef signed char stbtt_int8; + typedef unsigned short stbtt_uint16; + typedef signed short stbtt_int16; + typedef unsigned int stbtt_uint32; + typedef signed int stbtt_int32; + #endif + + typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; + typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; + + // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h + #ifndef STBTT_ifloor + #include + #define STBTT_ifloor(x) ((int) floor(x)) + #define STBTT_iceil(x) ((int) ceil(x)) + #endif + + #ifndef STBTT_sqrt + #include + #define STBTT_sqrt(x) sqrt(x) + #define STBTT_pow(x,y) pow(x,y) + #endif + + #ifndef STBTT_fmod + #include + #define STBTT_fmod(x,y) fmod(x,y) + #endif + + #ifndef STBTT_cos + #include + #define STBTT_cos(x) cos(x) + #define STBTT_acos(x) acos(x) + #endif + + #ifndef STBTT_fabs + #include + #define STBTT_fabs(x) fabs(x) + #endif + + // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h + #ifndef STBTT_malloc + #include + #define STBTT_malloc(x,u) ((void)(u),malloc(x)) + #define STBTT_free(x,u) ((void)(u),free(x)) + #endif + + #ifndef STBTT_assert + #include + #define STBTT_assert(x) assert(x) + #endif + + #ifndef STBTT_strlen + #include + #define STBTT_strlen(x) strlen(x) + #endif + + #ifndef STBTT_memcpy + #include + #define STBTT_memcpy memcpy + #define STBTT_memset memset + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// INTERFACE +//// +//// + +#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ +#define __STB_INCLUDE_STB_TRUETYPE_H__ + +#ifdef STBTT_STATIC +#define STBTT_DEF static +#else +#define STBTT_DEF extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// private structure +typedef struct +{ + unsigned char *data; + int cursor; + int size; +} stbtt__buf; + +////////////////////////////////////////////////////////////////////////////// +// +// TEXTURE BAKING API +// +// If you use this API, you only have to call two functions ever. +// + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; +} stbtt_bakedchar; + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata); // you allocate this, it's num_chars long +// if return is positive, the first unused row of the bitmap +// if return is negative, returns the negative of the number of characters that fit +// if return is 0, no characters fit and no rows were used +// This uses a very crappy packing. + +typedef struct +{ + float x0,y0,s0,t0; // top-left + float x1,y1,s1,t1; // bottom-right +} stbtt_aligned_quad; + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier +// Call GetBakedQuad with char_index = 'character - first_char', and it +// creates the quad you need to draw and advances the current position. +// +// The coordinate system used assumes y increases downwards. +// +// Characters will extend both above and below the current position; +// see discussion of "BASELINE" above. +// +// It's inefficient; you might want to c&p it and optimize it. + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); +// Query the font vertical metrics without having to create a font first. + + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct stbtt_fontinfo stbtt_fontinfo; +#ifndef STB_RECT_PACK_VERSION +typedef struct stbrp_rect stbrp_rect; +#endif + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is width * height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +#define STBTT_POINT_SIZE(x) (-(x)) + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint + int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints + int num_chars; + stbtt_packedchar *chardata_for_range; // output + unsigned char h_oversample, v_oversample; // don't set these, they're used internally +} stbtt_pack_range; + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. Note that you can call this multiple +// times within a single PackBegin/PackEnd. + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given +// pack context. The default (no oversampling) is achieved by h_oversample=1 +// and v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts +// +// To use with PackFontRangesGather etc., you must set it before calls +// call to PackFontRangesGatherRects. + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); +// If skip != 0, this tells stb_truetype to skip any codepoints for which +// there is no corresponding glyph. If skip=0, which is the default, then +// codepoints without a glyph recived the font's "missing character" glyph, +// typically an empty box by convention. + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); +// Calling these functions in sequence is roughly equivalent to calling +// stbtt_PackFontRanges(). If you more control over the packing of multiple +// fonts, or if you want to pack custom data into a font texture, take a look +// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times, +// building up a single array of rects, then call PackRects once, +// then call RenderIntoRects repeatedly. This may result in a +// better packing than calling PackFontRanges multiple times +// (or it may not). + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + int padding; + int skip_missing; + unsigned int h_oversample, v_oversample; + unsigned char *pixels; + void *nodes; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// FONT LOADING +// +// + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); +// This function will determine the number of fonts in a font file. TrueType +// collection (.ttc) files may contain multiple fonts, while TrueType font +// (.ttf) files only contain one font. The number of fonts can be used for +// indexing with the previous function where the index is between zero and one +// less than the total fonts. If an error occurs, -1 is returned. + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); +// Each .ttf/.ttc file may have more than one font. Each font has a sequential +// index number starting from 0. Call this function to get the font offset for +// a given index; it returns -1 if the index is out of range. A regular .ttf +// file will only define one font and it always be at offset 0, so it will +// return '0' for index 0, and -1 for all other indices. + +// The following structure is defined publicly so you can declare one on +// the stack or as a global or etc, but you should treat it as opaque. +struct stbtt_fontinfo +{ + void * userdata; + unsigned char * data; // pointer to .ttf file + int fontstart; // offset of start of font + + int numGlyphs; // number of glyphs, needed for range checking + + int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf + int index_map; // a cmap mapping for our chosen character encoding + int indexToLocFormat; // format needed to map from glyph index to glyph + + stbtt__buf cff; // cff font data + stbtt__buf charstrings; // the charstring index + stbtt__buf gsubrs; // global charstring subroutines index + stbtt__buf subrs; // private charstring subroutines index + stbtt__buf fontdicts; // array of font dicts + stbtt__buf fdselect; // map from glyph to fontdict +}; + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); +// Given an offset into the file that defines a font, this function builds +// the necessary cached info for the rest of the system. You must allocate +// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't +// need to do anything special to free it, because the contents are pure +// value data with no additional data structures. Returns 0 on failure. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER TO GLYPH-INDEX CONVERSIOn + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); +// If you're going to perform multiple operations on the same character +// and you want a speed-up, call this function with the character you're +// going to process, then use glyph-based functions instead of the +// codepoint-based functions. +// Returns 0 if the character codepoint is not defined in the font. + + +////////////////////////////////////////////////////////////////////////////// +// +// CHARACTER PROPERTIES +// + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose "height" is 'pixels' tall. +// Height is measured as the distance from the highest ascender to the lowest +// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics +// and computing: +// scale = pixels / (ascent - descent) +// so if you prefer to measure height by the ascent only, use a similar calculation. + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); +// computes a scale factor to produce a font whose EM size is mapped to +// 'pixels' tall. This is probably what traditional APIs compute, but +// I'm not positive. + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); +// ascent is the coordinate above the baseline the font extends; descent +// is the coordinate below the baseline the font extends (i.e. it is typically negative) +// lineGap is the spacing between one row's descent and the next row's ascent... +// so you should advance the vertical position by "*ascent - *descent + *lineGap" +// these are expressed in unscaled coordinates, so you must multiply by +// the scale factor for a given size + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); +// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 +// table (specific to MS/Windows TTF files). +// +// Returns 1 on success (table present), 0 on failure. + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); +// the bounding box around all possible characters + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); +// leftSideBearing is the offset from the current horizontal position to the left edge of the character +// advanceWidth is the offset from the current horizontal position to the next horizontal position +// these are expressed in unscaled coordinates + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); +// an additional amount to add to the 'advance' value between ch1 and ch2 + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); +// Gets the bounding box of the visible part of the glyph, in unscaled coordinates + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); +// as above, but takes one or more glyph indices for greater efficiency + +typedef struct stbtt_kerningentry +{ + int glyph1; // use stbtt_FindGlyphIndex + int glyph2; + int advance; +} stbtt_kerningentry; + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); +// Retrieves a complete list of all of the kerning pairs provided by the font +// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. +// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) + +////////////////////////////////////////////////////////////////////////////// +// +// GLYPH SHAPES (you probably don't need these, but they have to go before +// the bitmaps for C declaration-order reasons) +// + +#ifndef STBTT_vmove // you can predefine these to use different values (but why?) + enum { + STBTT_vmove=1, + STBTT_vline, + STBTT_vcurve, + STBTT_vcubic + }; +#endif + +#ifndef stbtt_vertex // you can predefine this to use different values + // (we share this with other code at RAD) + #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file + typedef struct + { + stbtt_vertex_type x,y,cx,cy,cx1,cy1; + unsigned char type,padding; + } stbtt_vertex; +#endif + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); +// returns non-zero if nothing is drawn for this glyph + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); +// returns # of vertices and fills *vertices with the pointer to them +// these are expressed in "unscaled" coordinates +// +// The shape is a series of contours. Each one starts with +// a STBTT_moveto, then consists of a series of mixed +// STBTT_lineto and STBTT_curveto segments. A lineto +// draws a line from previous endpoint to its x,y; a curveto +// draws a quadratic bezier from previous endpoint to +// its x,y, using cx,cy as the bezier control point. + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); +// frees the data allocated above + +STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); +// fills svg with the character's SVG data. +// returns data size or 0 if SVG not found. + +////////////////////////////////////////////////////////////////////////////// +// +// BITMAP RENDERING +// + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); +// frees the bitmap allocated below + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// allocates a large-enough single-channel 8bpp bitmap and renders the +// specified character/glyph at the specified scale into it, with +// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). +// *width & *height are filled out with the width & height of the bitmap, +// which is stored left-to-right, top-to-bottom. +// +// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); +// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); +// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap +// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap +// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the +// width and height and positioning info for it first. + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); +// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel +// shift for the character + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); +// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering +// is performed (see stbtt_PackSetOversampling) + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +// get the bbox of the bitmap centered around the glyph origin; so the +// bitmap width is ix1-ix0, height is iy1-iy0, and location to place +// the bitmap top left is (leftSideBearing*scale,iy0). +// (Note that the bitmap uses y-increases-down, but the shape uses +// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); +// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel +// shift for the character + +// the following functions are equivalent to the above functions, but operate +// on glyph indices instead of Unicode codepoints (for efficiency) +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); + + +// @TODO: don't expose this structure +typedef struct +{ + int w,h,stride; + unsigned char *pixels; +} stbtt__bitmap; + +// rasterize a shape with quadratic beziers into a bitmap +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into + float flatness_in_pixels, // allowable error of curve in pixels + stbtt_vertex *vertices, // array of vertices defining shape + int num_verts, // number of vertices in above array + float scale_x, float scale_y, // scale applied to input vertices + float shift_x, float shift_y, // translation applied to input vertices + int x_off, int y_off, // another translation applied to input + int invert, // if non-zero, vertically flip shape + void *userdata); // context for to STBTT_MALLOC + +////////////////////////////////////////////////////////////////////////////// +// +// Signed Distance Function (or Field) rendering + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); +// frees the SDF bitmap allocated below + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); +// These functions compute a discretized SDF field for a single character, suitable for storing +// in a single-channel texture, sampling with bilinear filtering, and testing against +// larger than some threshold to produce scalable fonts. +// info -- the font +// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap +// glyph/codepoint -- the character to generate the SDF for +// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), +// which allows effects like bit outlines +// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) +// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) +// if positive, > onedge_value is inside; if negative, < onedge_value is inside +// width,height -- output height & width of the SDF bitmap (including padding) +// xoff,yoff -- output origin of the character +// return value -- a 2D array of bytes 0..255, width*height in size +// +// pixel_dist_scale & onedge_value are a scale & bias that allows you to make +// optimal use of the limited 0..255 for your application, trading off precision +// and special effects. SDF values outside the range 0..255 are clamped to 0..255. +// +// Example: +// scale = stbtt_ScaleForPixelHeight(22) +// padding = 5 +// onedge_value = 180 +// pixel_dist_scale = 180/5.0 = 36.0 +// +// This will create an SDF bitmap in which the character is about 22 pixels +// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled +// shape, sample the SDF at each pixel and fill the pixel if the SDF value +// is greater than or equal to 180/255. (You'll actually want to antialias, +// which is beyond the scope of this example.) Additionally, you can compute +// offset outlines (e.g. to stroke the character border inside & outside, +// or only outside). For example, to fill outside the character up to 3 SDF +// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above +// choice of variables maps a range from 5 pixels outside the shape to +// 2 pixels inside the shape to 0..255; this is intended primarily for apply +// outside effects only (the interior range is needed to allow proper +// antialiasing of the font at *smaller* sizes) +// +// The function computes the SDF analytically at each SDF pixel, not by e.g. +// building a higher-res bitmap and approximating it. In theory the quality +// should be as high as possible for an SDF of this size & representation, but +// unclear if this is true in practice (perhaps building a higher-res bitmap +// and computing from that can allow drop-out prevention). +// +// The algorithm has not been optimized at all, so expect it to be slow +// if computing lots of characters or very large sizes. + + + +////////////////////////////////////////////////////////////////////////////// +// +// Finding the right font... +// +// You should really just solve this offline, keep your own tables +// of what font is what, and don't try to get it out of the .ttf file. +// That's because getting it out of the .ttf file is really hard, because +// the names in the file can appear in many possible encodings, in many +// possible languages, and e.g. if you need a case-insensitive comparison, +// the details of that depend on the encoding & language in a complex way +// (actually underspecified in truetype, but also gigantic). +// +// But you can use the provided functions in two possible ways: +// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on +// unicode-encoded names to try to find the font you want; +// you can run this before calling stbtt_InitFont() +// +// stbtt_GetFontNameString() lets you get any of the various strings +// from the file yourself and do your own comparisons on them. +// You have to have called stbtt_InitFont() first. + + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); +// returns the offset (not index) of the font that matches, or -1 if none +// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". +// if you use any other flag, use a font name like "Arial"; this checks +// the 'macStyle' header field; i don't know if fonts set this consistently +#define STBTT_MACSTYLE_DONTCARE 0 +#define STBTT_MACSTYLE_BOLD 1 +#define STBTT_MACSTYLE_ITALIC 2 +#define STBTT_MACSTYLE_UNDERSCORE 4 +#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); +// returns 1/0 whether the first string interpreted as utf8 is identical to +// the second string interpreted as big-endian utf16... useful for strings from next func + +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); +// returns the string (which may be big-endian double byte, e.g. for unicode) +// and puts the length in bytes in *length. +// +// some of the values for the IDs are below; for more see the truetype spec: +// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html +// http://www.microsoft.com/typography/otspec/name.htm + +enum { // platformID + STBTT_PLATFORM_ID_UNICODE =0, + STBTT_PLATFORM_ID_MAC =1, + STBTT_PLATFORM_ID_ISO =2, + STBTT_PLATFORM_ID_MICROSOFT =3 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_UNICODE + STBTT_UNICODE_EID_UNICODE_1_0 =0, + STBTT_UNICODE_EID_UNICODE_1_1 =1, + STBTT_UNICODE_EID_ISO_10646 =2, + STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, + STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT + STBTT_MS_EID_SYMBOL =0, + STBTT_MS_EID_UNICODE_BMP =1, + STBTT_MS_EID_SHIFTJIS =2, + STBTT_MS_EID_UNICODE_FULL =10 +}; + +enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes + STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, + STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, + STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, + STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 +}; + +enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... + // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs + STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, + STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, + STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, + STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, + STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, + STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D +}; + +enum { // languageID for STBTT_PLATFORM_ID_MAC + STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, + STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, + STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, + STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , + STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , + STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, + STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 +}; + +#ifdef __cplusplus +} +#endif + +#endif // __STB_INCLUDE_STB_TRUETYPE_H__ + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +//// +//// IMPLEMENTATION +//// +//// + +#ifdef STB_TRUETYPE_IMPLEMENTATION + +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +#if STBTT_MAX_OVERSAMPLE > 255 +#error "STBTT_MAX_OVERSAMPLE cannot be > 255" +#endif + +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + +#ifndef STBTT_RASTERIZER_VERSION +#define STBTT_RASTERIZER_VERSION 2 +#endif + +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +////////////////////////////////////////////////////////////////////////// +// +// stbtt__buf helpers to parse data from file +// + +static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor++]; +} + +static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) +{ + if (b->cursor >= b->size) + return 0; + return b->data[b->cursor]; +} + +static void stbtt__buf_seek(stbtt__buf *b, int o) +{ + STBTT_assert(!(o > b->size || o < 0)); + b->cursor = (o > b->size || o < 0) ? b->size : o; +} + +static void stbtt__buf_skip(stbtt__buf *b, int o) +{ + stbtt__buf_seek(b, b->cursor + o); +} + +static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) +{ + stbtt_uint32 v = 0; + int i; + STBTT_assert(n >= 1 && n <= 4); + for (i = 0; i < n; i++) + v = (v << 8) | stbtt__buf_get8(b); + return v; +} + +static stbtt__buf stbtt__new_buf(const void *p, size_t size) +{ + stbtt__buf r; + STBTT_assert(size < 0x40000000); + r.data = (stbtt_uint8*) p; + r.size = (int) size; + r.cursor = 0; + return r; +} + +#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) +#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) + +static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) +{ + stbtt__buf r = stbtt__new_buf(NULL, 0); + if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; + r.data = b->data + o; + r.size = s; + return r; +} + +static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) +{ + int count, start, offsize; + start = b->cursor; + count = stbtt__buf_get16(b); + if (count) { + offsize = stbtt__buf_get8(b); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(b, offsize * count); + stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); + } + return stbtt__buf_range(b, start, b->cursor - start); +} + +static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) +{ + int b0 = stbtt__buf_get8(b); + if (b0 >= 32 && b0 <= 246) return b0 - 139; + else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; + else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; + else if (b0 == 28) return stbtt__buf_get16(b); + else if (b0 == 29) return stbtt__buf_get32(b); + STBTT_assert(0); + return 0; +} + +static void stbtt__cff_skip_operand(stbtt__buf *b) { + int v, b0 = stbtt__buf_peek8(b); + STBTT_assert(b0 >= 28); + if (b0 == 30) { + stbtt__buf_skip(b, 1); + while (b->cursor < b->size) { + v = stbtt__buf_get8(b); + if ((v & 0xF) == 0xF || (v >> 4) == 0xF) + break; + } + } else { + stbtt__cff_int(b); + } +} + +static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) +{ + stbtt__buf_seek(b, 0); + while (b->cursor < b->size) { + int start = b->cursor, end, op; + while (stbtt__buf_peek8(b) >= 28) + stbtt__cff_skip_operand(b); + end = b->cursor; + op = stbtt__buf_get8(b); + if (op == 12) op = stbtt__buf_get8(b) | 0x100; + if (op == key) return stbtt__buf_range(b, start, end-start); + } + return stbtt__buf_range(b, 0, 0); +} + +static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) +{ + int i; + stbtt__buf operands = stbtt__dict_get(b, key); + for (i = 0; i < outcount && operands.cursor < operands.size; i++) + out[i] = stbtt__cff_int(&operands); +} + +static int stbtt__cff_index_count(stbtt__buf *b) +{ + stbtt__buf_seek(b, 0); + return stbtt__buf_get16(b); +} + +static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) +{ + int count, offsize, start, end; + stbtt__buf_seek(&b, 0); + count = stbtt__buf_get16(&b); + offsize = stbtt__buf_get8(&b); + STBTT_assert(i >= 0 && i < count); + STBTT_assert(offsize >= 1 && offsize <= 4); + stbtt__buf_skip(&b, i*offsize); + start = stbtt__buf_get(&b, offsize); + end = stbtt__buf_get(&b, offsize); + return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); +} + +////////////////////////////////////////////////////////////////////////// +// +// accessors to parse data from file +// + +// on platforms that don't allow misaligned reads, if we want to allow +// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE + +#define ttBYTE(p) (* (stbtt_uint8 *) (p)) +#define ttCHAR(p) (* (stbtt_int8 *) (p)) +#define ttFixed(p) ttLONG(p) + +static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } +static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } +static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } + +#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) +#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) + +static int stbtt__isfont(stbtt_uint8 *font) +{ + // check the version number + if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 + if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! + if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF + if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 + if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts + return 0; +} + +// @OPTIMIZE: binary search +static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) +{ + stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); + stbtt_uint32 tabledir = fontstart + 12; + stbtt_int32 i; + for (i=0; i < num_tables; ++i) { + stbtt_uint32 loc = tabledir + 16*i; + if (stbtt_tag(data+loc+0, tag)) + return ttULONG(data+loc+8); + } + return 0; +} + +static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) +{ + // if it's just a font, there's only one valid index + if (stbtt__isfont(font_collection)) + return index == 0 ? 0 : -1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + stbtt_int32 n = ttLONG(font_collection+8); + if (index >= n) + return -1; + return ttULONG(font_collection+12+index*4); + } + } + return -1; +} + +static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) +{ + // if it's just a font, there's only one valid font + if (stbtt__isfont(font_collection)) + return 1; + + // check if it's a TTC + if (stbtt_tag(font_collection, "ttcf")) { + // version 1? + if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { + return ttLONG(font_collection+8); + } + } + return 0; +} + +static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) +{ + stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; + stbtt__buf pdict; + stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); + if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); + pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); + stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); + if (!subrsoff) return stbtt__new_buf(NULL, 0); + stbtt__buf_seek(&cff, private_loc[1]+subrsoff); + return stbtt__cff_get_index(&cff); +} + +// since most people won't use this, find this table the first time it's needed +static int stbtt__get_svg(stbtt_fontinfo *info) +{ + stbtt_uint32 t; + if (info->svg < 0) { + t = stbtt__find_table(info->data, info->fontstart, "SVG "); + if (t) { + stbtt_uint32 offset = ttULONG(info->data + t + 2); + info->svg = t + offset; + } else { + info->svg = 0; + } + } + return info->svg; +} + +static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) +{ + stbtt_uint32 cmap, t; + stbtt_int32 i,numTables; + + info->data = data; + info->fontstart = fontstart; + info->cff = stbtt__new_buf(NULL, 0); + + cmap = stbtt__find_table(data, fontstart, "cmap"); // required + info->loca = stbtt__find_table(data, fontstart, "loca"); // required + info->head = stbtt__find_table(data, fontstart, "head"); // required + info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required + info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required + info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required + info->kern = stbtt__find_table(data, fontstart, "kern"); // not required + info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required + + if (!cmap || !info->head || !info->hhea || !info->hmtx) + return 0; + if (info->glyf) { + // required for truetype + if (!info->loca) return 0; + } else { + // initialization for CFF / Type2 fonts (OTF) + stbtt__buf b, topdict, topdictidx; + stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; + stbtt_uint32 cff; + + cff = stbtt__find_table(data, fontstart, "CFF "); + if (!cff) return 0; + + info->fontdicts = stbtt__new_buf(NULL, 0); + info->fdselect = stbtt__new_buf(NULL, 0); + + // @TODO this should use size from table (not 512MB) + info->cff = stbtt__new_buf(data+cff, 512*1024*1024); + b = info->cff; + + // read the header + stbtt__buf_skip(&b, 2); + stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize + + // @TODO the name INDEX could list multiple fonts, + // but we just use the first one. + stbtt__cff_get_index(&b); // name INDEX + topdictidx = stbtt__cff_get_index(&b); + topdict = stbtt__cff_index_get(topdictidx, 0); + stbtt__cff_get_index(&b); // string INDEX + info->gsubrs = stbtt__cff_get_index(&b); + + stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); + stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); + stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); + stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); + info->subrs = stbtt__get_subrs(b, topdict); + + // we only support Type 2 charstrings + if (cstype != 2) return 0; + if (charstrings == 0) return 0; + + if (fdarrayoff) { + // looks like a CID font + if (!fdselectoff) return 0; + stbtt__buf_seek(&b, fdarrayoff); + info->fontdicts = stbtt__cff_get_index(&b); + info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); + } + + stbtt__buf_seek(&b, charstrings); + info->charstrings = stbtt__cff_get_index(&b); + } + + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data+t+4); + else + info->numGlyphs = 0xffff; + + info->svg = -1; + + // find a cmap encoding table we understand *now* to avoid searching + // later. (todo: could make this installable) + // the same regardless of glyph. + numTables = ttUSHORT(data + cmap + 2); + info->index_map = 0; + for (i=0; i < numTables; ++i) { + stbtt_uint32 encoding_record = cmap + 4 + 8 * i; + // find an encoding we understand: + switch(ttUSHORT(data+encoding_record)) { + case STBTT_PLATFORM_ID_MICROSOFT: + switch (ttUSHORT(data+encoding_record+2)) { + case STBTT_MS_EID_UNICODE_BMP: + case STBTT_MS_EID_UNICODE_FULL: + // MS/Unicode + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + break; + case STBTT_PLATFORM_ID_UNICODE: + // Mac/iOS has these + // all the encodingIDs are unicode, so we don't bother to check it + info->index_map = cmap + ttULONG(data+encoding_record+4); + break; + } + } + if (info->index_map == 0) + return 0; + + info->indexToLocFormat = ttUSHORT(data+info->head + 50); + return 1; +} + +STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) +{ + stbtt_uint8 *data = info->data; + stbtt_uint32 index_map = info->index_map; + + stbtt_uint16 format = ttUSHORT(data + index_map + 0); + if (format == 0) { // apple byte encoding + stbtt_int32 bytes = ttUSHORT(data + index_map + 2); + if (unicode_codepoint < bytes-6) + return ttBYTE(data + index_map + 6 + unicode_codepoint); + return 0; + } else if (format == 6) { + stbtt_uint32 first = ttUSHORT(data + index_map + 6); + stbtt_uint32 count = ttUSHORT(data + index_map + 8); + if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) + return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); + return 0; + } else if (format == 2) { + STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean + return 0; + } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges + stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; + stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; + stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); + stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; + + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; + + if (unicode_codepoint > 0xffff) + return 0; + + // they lie from endCount .. endCount + segCount + // but searchRange is the nearest power of two, so... + if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) + search += rangeShift*2; + + // now decrement to bias correctly to find smallest + search -= 2; + while (entrySelector) { + stbtt_uint16 end; + searchRange >>= 1; + end = ttUSHORT(data + search + searchRange*2); + if (unicode_codepoint > end) + search += searchRange*2; + --entrySelector; + } + search += 2; + + { + stbtt_uint16 offset, start, last; + stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); + + start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); + last = ttUSHORT(data + endCount + 2*item); + if (unicode_codepoint < start || unicode_codepoint > last) + return 0; + + offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); + if (offset == 0) + return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); + + return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); + } + } else if (format == 12 || format == 13) { + stbtt_uint32 ngroups = ttULONG(data+index_map+12); + stbtt_int32 low,high; + low = 0; high = (stbtt_int32)ngroups; + // Binary search the right group. + while (low < high) { + stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high + stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); + stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); + if ((stbtt_uint32) unicode_codepoint < start_char) + high = mid; + else if ((stbtt_uint32) unicode_codepoint > end_char) + low = mid+1; + else { + stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); + if (format == 12) + return start_glyph + unicode_codepoint-start_char; + else // format == 13 + return start_glyph; + } + } + return 0; // not found + } + // @TODO + STBTT_assert(0); + return 0; +} + +STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) +{ + return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); +} + +static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) +{ + v->type = type; + v->x = (stbtt_int16) x; + v->y = (stbtt_int16) y; + v->cx = (stbtt_int16) cx; + v->cy = (stbtt_int16) cy; +} + +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) +{ + int g1,g2; + + STBTT_assert(!info->cff.size); + + if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range + if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format + + if (info->indexToLocFormat == 0) { + g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; + g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; + } else { + g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); + g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); + } + + return g1==g2 ? -1 : g1; // if length is 0, return -1 +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); + +STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + if (info->cff.size) { + stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); + } else { + int g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 0; + + if (x0) *x0 = ttSHORT(info->data + g + 2); + if (y0) *y0 = ttSHORT(info->data + g + 4); + if (x1) *x1 = ttSHORT(info->data + g + 6); + if (y1) *y1 = ttSHORT(info->data + g + 8); + } + return 1; +} + +STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) +{ + return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); +} + +STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt_int16 numberOfContours; + int g; + if (info->cff.size) + return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; + g = stbtt__GetGlyfOffset(info, glyph_index); + if (g < 0) return 1; + numberOfContours = ttSHORT(info->data + g); + return numberOfContours == 0; +} + +static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, + stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) +{ + if (start_off) { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); + } + return num_vertices; +} + +static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + stbtt_int16 numberOfContours; + stbtt_uint8 *endPtsOfContours; + stbtt_uint8 *data = info->data; + stbtt_vertex *vertices=0; + int num_vertices=0; + int g = stbtt__GetGlyfOffset(info, glyph_index); + + *pvertices = NULL; + + if (g < 0) return 0; + + numberOfContours = ttSHORT(data + g); + + if (numberOfContours > 0) { + stbtt_uint8 flags=0,flagcount; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; + stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; + stbtt_uint8 *points; + endPtsOfContours = (data + g + 10); + ins = ttUSHORT(data + g + 10 + numberOfContours * 2); + points = data + g + 10 + numberOfContours * 2 + 2 + ins; + + n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); + + m = n + 2*numberOfContours; // a loose bound on how many vertices we might need + vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); + if (vertices == 0) + return 0; + + next_move = 0; + flagcount=0; + + // in first pass, we load uninterpreted data into the allocated array + // above, shifted to the end of the array so we won't overwrite it when + // we create our final data starting from the front + + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated + + // first load flags + + for (i=0; i < n; ++i) { + if (flagcount == 0) { + flags = *points++; + if (flags & 8) + flagcount = *points++; + } else + --flagcount; + vertices[off+i].type = flags; + } + + // now load x coordinates + x=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 2) { + stbtt_int16 dx = *points++; + x += (flags & 16) ? dx : -dx; // ??? + } else { + if (!(flags & 16)) { + x = x + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].x = (stbtt_int16) x; + } + + // now load y coordinates + y=0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + if (flags & 4) { + stbtt_int16 dy = *points++; + y += (flags & 32) ? dy : -dy; // ??? + } else { + if (!(flags & 32)) { + y = y + (stbtt_int16) (points[0]*256 + points[1]); + points += 2; + } + } + vertices[off+i].y = (stbtt_int16) y; + } + + // now convert them to our format + num_vertices=0; + sx = sy = cx = cy = scx = scy = 0; + for (i=0; i < n; ++i) { + flags = vertices[off+i].type; + x = (stbtt_int16) vertices[off+i].x; + y = (stbtt_int16) vertices[off+i].y; + + if (next_move == i) { + if (i != 0) + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + + // now start the new one + start_off = !(flags & 1); + if (start_off) { + // if we start off with an off-curve point, then when we need to find a point on the curve + // where we can start, and we need to save some state for when we wraparound. + scx = x; + scy = y; + if (!(vertices[off+i+1].type & 1)) { + // next point is also a curve point, so interpolate an on-point curve + sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; + sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; + } else { + // otherwise just use the next point as our start point + sx = (stbtt_int32) vertices[off+i+1].x; + sy = (stbtt_int32) vertices[off+i+1].y; + ++i; // we're using point i+1 as the starting point, so skip it + } + } else { + sx = x; + sy = y; + } + stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); + was_off = 0; + next_move = 1 + ttUSHORT(endPtsOfContours+j*2); + ++j; + } else { + if (!(flags & 1)) { // if it's a curve + if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); + cx = x; + cy = y; + was_off = 1; + } else { + if (was_off) + stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); + else + stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); + was_off = 0; + } + } + } + num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); + } else if (numberOfContours < 0) { + // Compound shapes. + int more = 1; + stbtt_uint8 *comp = data + g + 10; + num_vertices = 0; + vertices = 0; + while (more) { + stbtt_uint16 flags, gidx; + int comp_num_verts = 0, i; + stbtt_vertex *comp_verts = 0, *tmp = 0; + float mtx[6] = {1,0,0,1,0,0}, m, n; + + flags = ttSHORT(comp); comp+=2; + gidx = ttSHORT(comp); comp+=2; + + if (flags & 2) { // XY values + if (flags & 1) { // shorts + mtx[4] = ttSHORT(comp); comp+=2; + mtx[5] = ttSHORT(comp); comp+=2; + } else { + mtx[4] = ttCHAR(comp); comp+=1; + mtx[5] = ttCHAR(comp); comp+=1; + } + } + else { + // @TODO handle matching point + STBTT_assert(0); + } + if (flags & (1<<3)) { // WE_HAVE_A_SCALE + mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = mtx[2] = 0; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO + mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; + mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; + } + + // Find transformation scales. + m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); + n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); + + // Get indexed glyph. + comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); + if (comp_num_verts > 0) { + // Transform vertices. + for (i = 0; i < comp_num_verts; ++i) { + stbtt_vertex* v = &comp_verts[i]; + stbtt_vertex_type x,y; + x=v->x; y=v->y; + v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + x=v->cx; y=v->cy; + v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); + v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); + } + // Append vertices. + tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); + if (!tmp) { + if (vertices) STBTT_free(vertices, info->userdata); + if (comp_verts) STBTT_free(comp_verts, info->userdata); + return 0; + } + if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); + STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); + if (vertices) STBTT_free(vertices, info->userdata); + vertices = tmp; + STBTT_free(comp_verts, info->userdata); + num_vertices += comp_num_verts; + } + // More components ? + more = flags & (1<<5); + } + } else { + // numberOfCounters == 0, do nothing + } + + *pvertices = vertices; + return num_vertices; +} + +typedef struct +{ + int bounds; + int started; + float first_x, first_y; + float x, y; + stbtt_int32 min_x, max_x, min_y, max_y; + + stbtt_vertex *pvertices; + int num_vertices; +} stbtt__csctx; + +#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} + +static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) +{ + if (x > c->max_x || !c->started) c->max_x = x; + if (y > c->max_y || !c->started) c->max_y = y; + if (x < c->min_x || !c->started) c->min_x = x; + if (y < c->min_y || !c->started) c->min_y = y; + c->started = 1; +} + +static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) +{ + if (c->bounds) { + stbtt__track_vertex(c, x, y); + if (type == STBTT_vcubic) { + stbtt__track_vertex(c, cx, cy); + stbtt__track_vertex(c, cx1, cy1); + } + } else { + stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); + c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; + c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; + } + c->num_vertices++; +} + +static void stbtt__csctx_close_shape(stbtt__csctx *ctx) +{ + if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) +{ + stbtt__csctx_close_shape(ctx); + ctx->first_x = ctx->x = ctx->x + dx; + ctx->first_y = ctx->y = ctx->y + dy; + stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) +{ + ctx->x += dx; + ctx->y += dy; + stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); +} + +static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) +{ + float cx1 = ctx->x + dx1; + float cy1 = ctx->y + dy1; + float cx2 = cx1 + dx2; + float cy2 = cy1 + dy2; + ctx->x = cx2 + dx3; + ctx->y = cy2 + dy3; + stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); +} + +static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) +{ + int count = stbtt__cff_index_count(&idx); + int bias = 107; + if (count >= 33900) + bias = 32768; + else if (count >= 1240) + bias = 1131; + n += bias; + if (n < 0 || n >= count) + return stbtt__new_buf(NULL, 0); + return stbtt__cff_index_get(idx, n); +} + +static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) +{ + stbtt__buf fdselect = info->fdselect; + int nranges, start, end, v, fmt, fdselector = -1, i; + + stbtt__buf_seek(&fdselect, 0); + fmt = stbtt__buf_get8(&fdselect); + if (fmt == 0) { + // untested + stbtt__buf_skip(&fdselect, glyph_index); + fdselector = stbtt__buf_get8(&fdselect); + } else if (fmt == 3) { + nranges = stbtt__buf_get16(&fdselect); + start = stbtt__buf_get16(&fdselect); + for (i = 0; i < nranges; i++) { + v = stbtt__buf_get8(&fdselect); + end = stbtt__buf_get16(&fdselect); + if (glyph_index >= start && glyph_index < end) { + fdselector = v; + break; + } + start = end; + } + } + if (fdselector == -1) return stbtt__new_buf(NULL, 0); // [DEAR IMGUI] fixed, see #6007 and nothings/stb#1422 + return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); +} + +static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) +{ + int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; + int has_subrs = 0, clear_stack; + float s[48]; + stbtt__buf subr_stack[10], subrs = info->subrs, b; + float f; + +#define STBTT__CSERR(s) (0) + + // this currently ignores the initial width value, which isn't needed if we have hmtx + b = stbtt__cff_index_get(info->charstrings, glyph_index); + while (b.cursor < b.size) { + i = 0; + clear_stack = 1; + b0 = stbtt__buf_get8(&b); + switch (b0) { + // @TODO implement hinting + case 0x13: // hintmask + case 0x14: // cntrmask + if (in_header) + maskbits += (sp / 2); // implicit "vstem" + in_header = 0; + stbtt__buf_skip(&b, (maskbits + 7) / 8); + break; + + case 0x01: // hstem + case 0x03: // vstem + case 0x12: // hstemhm + case 0x17: // vstemhm + maskbits += (sp / 2); + break; + + case 0x15: // rmoveto + in_header = 0; + if (sp < 2) return STBTT__CSERR("rmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); + break; + case 0x04: // vmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("vmoveto stack"); + stbtt__csctx_rmove_to(c, 0, s[sp-1]); + break; + case 0x16: // hmoveto + in_header = 0; + if (sp < 1) return STBTT__CSERR("hmoveto stack"); + stbtt__csctx_rmove_to(c, s[sp-1], 0); + break; + + case 0x05: // rlineto + if (sp < 2) return STBTT__CSERR("rlineto stack"); + for (; i + 1 < sp; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical + // starting from a different place. + + case 0x07: // vlineto + if (sp < 1) return STBTT__CSERR("vlineto stack"); + goto vlineto; + case 0x06: // hlineto + if (sp < 1) return STBTT__CSERR("hlineto stack"); + for (;;) { + if (i >= sp) break; + stbtt__csctx_rline_to(c, s[i], 0); + i++; + vlineto: + if (i >= sp) break; + stbtt__csctx_rline_to(c, 0, s[i]); + i++; + } + break; + + case 0x1F: // hvcurveto + if (sp < 4) return STBTT__CSERR("hvcurveto stack"); + goto hvcurveto; + case 0x1E: // vhcurveto + if (sp < 4) return STBTT__CSERR("vhcurveto stack"); + for (;;) { + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); + i += 4; + hvcurveto: + if (i + 3 >= sp) break; + stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); + i += 4; + } + break; + + case 0x08: // rrcurveto + if (sp < 6) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x18: // rcurveline + if (sp < 8) return STBTT__CSERR("rcurveline stack"); + for (; i + 5 < sp - 2; i += 6) + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); + stbtt__csctx_rline_to(c, s[i], s[i+1]); + break; + + case 0x19: // rlinecurve + if (sp < 8) return STBTT__CSERR("rlinecurve stack"); + for (; i + 1 < sp - 6; i += 2) + stbtt__csctx_rline_to(c, s[i], s[i+1]); + if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); + stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); + break; + + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); + f = 0.0; + if (sp & 1) { f = s[i]; i++; } + for (; i + 3 < sp; i += 4) { + if (b0 == 0x1B) + stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); + else + stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); + f = 0.0; + } + break; + + case 0x0A: // callsubr + if (!has_subrs) { + if (info->fdselect.size) + subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); + has_subrs = 1; + } + // FALLTHROUGH + case 0x1D: // callgsubr + if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); + v = (int) s[--sp]; + if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); + subr_stack[subr_stack_height++] = b; + b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); + if (b.size == 0) return STBTT__CSERR("subr not found"); + b.cursor = 0; + clear_stack = 0; + break; + + case 0x0B: // return + if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); + b = subr_stack[--subr_stack_height]; + clear_stack = 0; + break; + + case 0x0E: // endchar + stbtt__csctx_close_shape(c); + return 1; + + case 0x0C: { // two-byte escape + float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; + float dx, dy; + int b1 = stbtt__buf_get8(&b); + switch (b1) { + // @TODO These "flex" implementations ignore the flex-depth and resolution, + // and always draw beziers. + case 0x22: // hflex + if (sp < 7) return STBTT__CSERR("hflex stack"); + dx1 = s[0]; + dx2 = s[1]; + dy2 = s[2]; + dx3 = s[3]; + dx4 = s[4]; + dx5 = s[5]; + dx6 = s[6]; + stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); + break; + + case 0x23: // flex + if (sp < 13) return STBTT__CSERR("flex stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = s[10]; + dy6 = s[11]; + //fd is s[12] + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + case 0x24: // hflex1 + if (sp < 9) return STBTT__CSERR("hflex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dx4 = s[5]; + dx5 = s[6]; + dy5 = s[7]; + dx6 = s[8]; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); + stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); + break; + + case 0x25: // flex1 + if (sp < 11) return STBTT__CSERR("flex1 stack"); + dx1 = s[0]; + dy1 = s[1]; + dx2 = s[2]; + dy2 = s[3]; + dx3 = s[4]; + dy3 = s[5]; + dx4 = s[6]; + dy4 = s[7]; + dx5 = s[8]; + dy5 = s[9]; + dx6 = dy6 = s[10]; + dx = dx1+dx2+dx3+dx4+dx5; + dy = dy1+dy2+dy3+dy4+dy5; + if (STBTT_fabs(dx) > STBTT_fabs(dy)) + dy6 = -dy; + else + dx6 = -dx; + stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); + stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); + break; + + default: + return STBTT__CSERR("unimplemented"); + } + } break; + + default: + if (b0 != 255 && b0 != 28 && b0 < 32) + return STBTT__CSERR("reserved operator"); + + // push immediate + if (b0 == 255) { + f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; + } else { + stbtt__buf_skip(&b, -1); + f = (float)(stbtt_int16)stbtt__cff_int(&b); + } + if (sp >= 48) return STBTT__CSERR("push stack overflow"); + s[sp++] = f; + clear_stack = 0; + break; + } + if (clear_stack) sp = 0; + } + return STBTT__CSERR("no endchar"); + +#undef STBTT__CSERR +} + +static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + // runs the charstring twice, once to count and once to output (to avoid realloc) + stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); + stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); + if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { + *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); + output_ctx.pvertices = *pvertices; + if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { + STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); + return output_ctx.num_vertices; + } + } + *pvertices = NULL; + return 0; +} + +static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) +{ + stbtt__csctx c = STBTT__CSCTX_INIT(1); + int r = stbtt__run_charstring(info, glyph_index, &c); + if (x0) *x0 = r ? c.min_x : 0; + if (y0) *y0 = r ? c.min_y : 0; + if (x1) *x1 = r ? c.max_x : 0; + if (y1) *y1 = r ? c.max_y : 0; + return r ? c.num_vertices : 0; +} + +STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) +{ + if (!info->cff.size) + return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); + else + return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); +} + +STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) +{ + stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); + if (glyph_index < numOfLongHorMetrics) { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); + } else { + if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); + if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); + } +} + +STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) +{ + stbtt_uint8 *data = info->data + info->kern; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + return ttUSHORT(data+10); +} + +STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) +{ + stbtt_uint8 *data = info->data + info->kern; + int k, length; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + length = ttUSHORT(data+10); + if (table_length < length) + length = table_length; + + for (k = 0; k < length; k++) + { + table[k].glyph1 = ttUSHORT(data+18+(k*6)); + table[k].glyph2 = ttUSHORT(data+20+(k*6)); + table[k].advance = ttSHORT(data+22+(k*6)); + } + + return length; +} + +static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint8 *data = info->data + info->kern; + stbtt_uint32 needle, straw; + int l, r, m; + + // we only look at the first table. it must be 'horizontal' and format 0. + if (!info->kern) + return 0; + if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 + return 0; + if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format + return 0; + + l = 0; + r = ttUSHORT(data+10) - 1; + needle = glyph1 << 16 | glyph2; + while (l <= r) { + m = (l + r) >> 1; + straw = ttULONG(data+18+(m*6)); // note: unaligned read + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else + return ttSHORT(data+22+(m*6)); + } + return 0; +} + +static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) +{ + stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); + switch (coverageFormat) { + case 1: { + stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); + + // Binary search. + stbtt_int32 l=0, r=glyphCount-1, m; + int straw, needle=glyph; + while (l <= r) { + stbtt_uint8 *glyphArray = coverageTable + 4; + stbtt_uint16 glyphID; + m = (l + r) >> 1; + glyphID = ttUSHORT(glyphArray + 2 * m); + straw = glyphID; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + return m; + } + } + break; + } + + case 2: { + stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); + stbtt_uint8 *rangeArray = coverageTable + 4; + + // Binary search. + stbtt_int32 l=0, r=rangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *rangeRecord; + m = (l + r) >> 1; + rangeRecord = rangeArray + 6 * m; + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else { + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; + } + } + break; + } + + default: return -1; // unsupported + } + + return -1; +} + +static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) +{ + stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); + switch (classDefFormat) + { + case 1: { + stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); + stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); + stbtt_uint8 *classDef1ValueArray = classDefTable + 6; + + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) + return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); + break; + } + + case 2: { + stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); + stbtt_uint8 *classRangeRecords = classDefTable + 4; + + // Binary search. + stbtt_int32 l=0, r=classRangeCount-1, m; + int strawStart, strawEnd, needle=glyph; + while (l <= r) { + stbtt_uint8 *classRangeRecord; + m = (l + r) >> 1; + classRangeRecord = classRangeRecords + 6 * m; + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); + if (needle < strawStart) + r = m - 1; + else if (needle > strawEnd) + l = m + 1; + else + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } + + default: + return -1; // Unsupported definition type, return an error. + } + + // "All glyphs not assigned to a class fall into class 0". (OpenType spec) + return 0; +} + +// Define to STBTT_assert(x) if you want to break on unimplemented formats. +#define STBTT_GPOS_TODO_assert(x) + +static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) +{ + stbtt_uint16 lookupListOffset; + stbtt_uint8 *lookupList; + stbtt_uint16 lookupCount; + stbtt_uint8 *data; + stbtt_int32 i, sti; + + if (!info->gpos) return 0; + + data = info->data + info->gpos; + + if (ttUSHORT(data+0) != 1) return 0; // Major version 1 + if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 + + lookupListOffset = ttUSHORT(data+8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); + + for (i=0; i= pairSetCount) return 0; + + needle=glyph2; + r=pairValueCount-1; + l=0; + + // Binary search. + while (l <= r) { + stbtt_uint16 secondGlyph; + stbtt_uint8 *pairValue; + m = (l + r) >> 1; + pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; + secondGlyph = ttUSHORT(pairValue); + straw = secondGlyph; + if (needle < straw) + r = m - 1; + else if (needle > straw) + l = m + 1; + else { + stbtt_int16 xAdvance = ttSHORT(pairValue + 2); + return xAdvance; + } + } + } else + return 0; + break; + } + + case 2: { + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); + stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); + int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); + int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); + + stbtt_uint16 class1Count = ttUSHORT(table + 12); + stbtt_uint16 class2Count = ttUSHORT(table + 14); + stbtt_uint8 *class1Records, *class2Records; + stbtt_int16 xAdvance; + + if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed + if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed + + class1Records = table + 16; + class2Records = class1Records + 2 * (glyph1class * class2Count); + xAdvance = ttSHORT(class2Records + 2 * glyph2class); + return xAdvance; + } else + return 0; + break; + } + + default: + return 0; // Unsupported position format + } + } + } + + return 0; +} + +STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) +{ + int xAdvance = 0; + + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); + + return xAdvance; +} + +STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) +{ + if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs + return 0; + return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); +} + +STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) +{ + stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); +} + +STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) +{ + if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); + if (descent) *descent = ttSHORT(info->data+info->hhea + 6); + if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); +} + +STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) +{ + int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); + if (!tab) + return 0; + if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); + if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); + if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); + return 1; +} + +STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) +{ + *x0 = ttSHORT(info->data + info->head + 36); + *y0 = ttSHORT(info->data + info->head + 38); + *x1 = ttSHORT(info->data + info->head + 40); + *y1 = ttSHORT(info->data + info->head + 42); +} + +STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) +{ + int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); + return (float) height / fheight; +} + +STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) +{ + int unitsPerEm = ttUSHORT(info->data + info->head + 18); + return pixels / unitsPerEm; +} + +STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) +{ + STBTT_free(v, info->userdata); +} + +STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) +{ + int i; + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); + + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; + + for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) + return svg_doc; + } + return 0; +} + +STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) +{ + stbtt_uint8 *data = info->data; + stbtt_uint8 *svg_doc; + + if (info->svg == 0) + return 0; + + svg_doc = stbtt_FindSVGDoc(info, gl); + if (svg_doc != NULL) { + *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); + return ttULONG(svg_doc + 8); + } else { + return 0; + } +} + +STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) +{ + return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); +} + +////////////////////////////////////////////////////////////////////////////// +// +// antialiasing software rasterizer +// + +STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning + if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { + // e.g. space character + if (ix0) *ix0 = 0; + if (iy0) *iy0 = 0; + if (ix1) *ix1 = 0; + if (iy1) *iy1 = 0; + } else { + // move to integral bboxes (treating pixels as little squares, what pixels get touched)? + if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); + if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); + if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); + if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); + } +} + +STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); +} + +STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) +{ + stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Rasterizer + +typedef struct stbtt__hheap_chunk +{ + struct stbtt__hheap_chunk *next; +} stbtt__hheap_chunk; + +typedef struct stbtt__hheap +{ + struct stbtt__hheap_chunk *head; + void *first_free; + int num_remaining_in_head_chunk; +} stbtt__hheap; + +static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) +{ + if (hh->first_free) { + void *p = hh->first_free; + hh->first_free = * (void **) p; + return p; + } else { + if (hh->num_remaining_in_head_chunk == 0) { + int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); + stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); + if (c == NULL) + return NULL; + c->next = hh->head; + hh->head = c; + hh->num_remaining_in_head_chunk = count; + } + --hh->num_remaining_in_head_chunk; + return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; + } +} + +static void stbtt__hheap_free(stbtt__hheap *hh, void *p) +{ + *(void **) p = hh->first_free; + hh->first_free = p; +} + +static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) +{ + stbtt__hheap_chunk *c = hh->head; + while (c) { + stbtt__hheap_chunk *n = c->next; + STBTT_free(c, userdata); + c = n; + } +} + +typedef struct stbtt__edge { + float x0,y0, x1,y1; + int invert; +} stbtt__edge; + + +typedef struct stbtt__active_edge +{ + struct stbtt__active_edge *next; + #if STBTT_RASTERIZER_VERSION==1 + int x,dx; + float ey; + int direction; + #elif STBTT_RASTERIZER_VERSION==2 + float fx,fdx,fdy; + float direction; + float sy; + float ey; + #else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" + #endif +} stbtt__active_edge; + +#if STBTT_RASTERIZER_VERSION == 1 +#define STBTT_FIXSHIFT 10 +#define STBTT_FIX (1 << STBTT_FIXSHIFT) +#define STBTT_FIXMASK (STBTT_FIX-1) + +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + if (!z) return z; + + // round dx down to avoid overshooting + if (dxdy < 0) + z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); + else + z->dx = STBTT_ifloor(STBTT_FIX * dxdy); + + z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount + z->x -= off_x * STBTT_FIX; + + z->ey = e->y1; + z->next = 0; + z->direction = e->invert ? 1 : -1; + return z; +} +#elif STBTT_RASTERIZER_VERSION == 2 +static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) +{ + stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); + STBTT_assert(z != NULL); + //STBTT_assert(e->y0 <= start_point); + if (!z) return z; + z->fdx = dxdy; + z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; + z->fx = e->x0 + dxdy * (start_point - e->y0); + z->fx -= off_x; + z->direction = e->invert ? 1.0f : -1.0f; + z->sy = e->y0; + z->ey = e->y1; + z->next = 0; + return z; +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#if STBTT_RASTERIZER_VERSION == 1 +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) +{ + // non-zero winding fill + int x0=0, w=0; + + while (e) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->direction; + } else { + int x1 = e->x; w += e->direction; + // if we went to zero, we need to draw + if (w == 0) { + int i = x0 >> STBTT_FIXSHIFT; + int j = x1 >> STBTT_FIXSHIFT; + + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8) max_weight; + } + } + } + } + + e = e->next; + } +} + +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0; + int max_weight = (255 / vsubsample); // weight per vertical scanline + int s; // vertical subsample index + unsigned char scanline_data[512], *scanline; + + if (result->w > 512) + scanline = (unsigned char *) STBTT_malloc(result->w, userdata); + else + scanline = scanline_data; + + y = off_y * vsubsample; + e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; + + while (j < result->h) { + STBTT_memset(scanline, 0, result->w); + for (s=0; s < vsubsample; ++s) { + // find center of pixel for this scanline + float scan_y = y + 0.5f; + stbtt__active_edge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for(;;) { + int changed=0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + stbtt__active_edge *t = *step; + stbtt__active_edge *q = t->next; + + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e->y0 <= scan_y) { + if (e->y1 > scan_y) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); + if (z != NULL) { + // find insertion point + if (active == NULL) + active = z; + else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + stbtt__active_edge *p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + } + ++e; + } + + // now process all active edges in XOR fashion + if (active) + stbtt__fill_active_edges(scanline, result->w, active, max_weight); + + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} + +#elif STBTT_RASTERIZER_VERSION == 2 + +// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 +// (i.e. it has already been clipped to those) +static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) +{ + if (y0 == y1) return; + STBTT_assert(y0 < y1); + STBTT_assert(e->sy <= e->ey); + if (y0 > e->ey) return; + if (y1 < e->sy) return; + if (y0 < e->sy) { + x0 += (x1-x0) * (e->sy - y0) / (y1-y0); + y0 = e->sy; + } + if (y1 > e->ey) { + x1 += (x1-x0) * (e->ey - y1) / (y1-y0); + y1 = e->ey; + } + + if (x0 == x) + STBTT_assert(x1 <= x+1); + else if (x0 == x+1) + STBTT_assert(x1 >= x); + else if (x0 <= x) + STBTT_assert(x1 <= x); + else if (x0 >= x+1) + STBTT_assert(x1 >= x+1); + else + STBTT_assert(x1 >= x && x1 <= x+1); + + if (x0 <= x && x1 <= x) + scanline[x] += e->direction * (y1-y0); + else if (x0 >= x+1 && x1 >= x+1) + ; + else { + STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); + scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position + } +} + +static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) +{ + STBTT_assert(top_width >= 0); + STBTT_assert(bottom_width >= 0); + return (top_width + bottom_width) / 2.0f * height; +} + +static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) +{ + return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); +} + +static float stbtt__sized_triangle_area(float height, float width) +{ + return height * width / 2; +} + +static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) +{ + float y_bottom = y_top+1; + + while (e) { + // brute force every pixel + + // compute intersection points with top & bottom + STBTT_assert(e->ey >= y_top); + + if (e->fdx == 0) { + float x0 = e->fx; + if (x0 < len) { + if (x0 >= 0) { + stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); + stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); + } else { + stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); + } + } + } else { + float x0 = e->fx; + float dx = e->fdx; + float xb = x0 + dx; + float x_top, x_bottom; + float sy0,sy1; + float dy = e->fdy; + STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); + + // compute endpoints of line segment clipped to this scanline (if the + // line segment starts on this scanline. x0 is the intersection of the + // line with y_top, but that may be off the line segment. + if (e->sy > y_top) { + x_top = x0 + dx * (e->sy - y_top); + sy0 = e->sy; + } else { + x_top = x0; + sy0 = y_top; + } + if (e->ey < y_bottom) { + x_bottom = x0 + dx * (e->ey - y_top); + sy1 = e->ey; + } else { + x_bottom = xb; + sy1 = y_bottom; + } + + if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { + // from here on, we don't have to range check x values + + if ((int) x_top == (int) x_bottom) { + float height; + // simple case, only spans one pixel + int x = (int) x_top; + height = (sy1 - sy0) * e->direction; + STBTT_assert(x >= 0 && x < len); + scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); + scanline_fill[x] += height; // everything right of this pixel is filled + } else { + int x,x1,x2; + float y_crossing, y_final, step, sign, area; + // covers 2+ pixels + if (x_top > x_bottom) { + // flip scanline vertically; signed area is the same + float t; + sy0 = y_bottom - (sy0 - y_top); + sy1 = y_bottom - (sy1 - y_top); + t = sy0, sy0 = sy1, sy1 = t; + t = x_bottom, x_bottom = x_top, x_top = t; + dx = -dx; + dy = -dy; + t = x0, x0 = xb, xb = t; + } + STBTT_assert(dy >= 0); + STBTT_assert(dx >= 0); + + x1 = (int) x_top; + x2 = (int) x_bottom; + // compute intersection with y axis at x1+1 + y_crossing = y_top + dy * (x1+1 - x0); + + // compute intersection with y axis at x2 + y_final = y_top + dy * (x2 - x0); + + // x1 x_top x2 x_bottom + // y_top +------|-----+------------+------------+--------|---+------------+ + // | | | | | | + // | | | | | | + // sy0 | Txxxxx|............|............|............|............| + // y_crossing | *xxxxx.......|............|............|............| + // | | xxxxx..|............|............|............| + // | | /- xx*xxxx........|............|............| + // | | dy < | xxxxxx..|............|............| + // y_final | | \- | xx*xxx.........|............| + // sy1 | | | | xxxxxB...|............| + // | | | | | | + // | | | | | | + // y_bottom +------------+------------+------------+------------+------------+ + // + // goal is to measure the area covered by '.' in each pixel + + // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 + // @TODO: maybe test against sy1 rather than y_bottom? + if (y_crossing > y_bottom) + y_crossing = y_bottom; + + sign = e->direction; + + // area of the rectangle covered from sy0..y_crossing + area = sign * (y_crossing-sy0); + + // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) + scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); + + // check if final y_crossing is blown up; no test case for this + if (y_final > y_bottom) { + int denom = (x2 - (x1+1)); + y_final = y_bottom; + if (denom != 0) { // [DEAR IMGUI] Avoid div by zero (https://github.com/nothings/stb/issues/1316) + dy = (y_final - y_crossing ) / denom; // if denom=0, y_final = y_crossing, so y_final <= y_bottom + } + } + + // in second pixel, area covered by line segment found in first pixel + // is always a rectangle 1 wide * the height of that line segment; this + // is exactly what the variable 'area' stores. it also gets a contribution + // from the line segment within it. the THIRD pixel will get the first + // pixel's rectangle contribution, the second pixel's rectangle contribution, + // and its own contribution. the 'own contribution' is the same in every pixel except + // the leftmost and rightmost, a trapezoid that slides down in each pixel. + // the second pixel's contribution to the third pixel will be the + // rectangle 1 wide times the height change in the second pixel, which is dy. + + step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, + // which multiplied by 1-pixel-width is how much pixel area changes for each step in x + // so the area advances by 'step' every time + + for (x = x1+1; x < x2; ++x) { + scanline[x] += area + step/2; // area of trapezoid is 1*step/2 + area += step; + } + STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down + STBTT_assert(sy1 > y_final-0.01f); + + // area covered in the last pixel is the rectangle from all the pixels to the left, + // plus the trapezoid filled by the line segment in this pixel all the way to the right edge + scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); + + // the rest of the line is filled based on the total height of the line segment in this pixel + scanline_fill[x2] += sign * (sy1-sy0); + } + } else { + // if edge goes outside of box we're drawing, we require + // clipping logic. since this does not match the intended use + // of this library, we use a different, very slow brute + // force implementation + // note though that this does happen some of the time because + // x_top and x_bottom can be extrapolated at the top & bottom of + // the shape and actually lie outside the bounding box + int x; + for (x=0; x < len; ++x) { + // cases: + // + // there can be up to two intersections with the pixel. any intersection + // with left or right edges can be handled by splitting into two (or three) + // regions. intersections with top & bottom do not necessitate case-wise logic. + // + // the old way of doing this found the intersections with the left & right edges, + // then used some simple logic to produce up to three segments in sorted order + // from top-to-bottom. however, this had a problem: if an x edge was epsilon + // across the x border, then the corresponding y position might not be distinct + // from the other y segment, and it might ignored as an empty segment. to avoid + // that, we need to explicitly produce segments based on x positions. + + // rename variables to clearly-defined pairs + float y0 = y_top; + float x1 = (float) (x); + float x2 = (float) (x+1); + float x3 = xb; + float y3 = y_bottom; + + // x = e->x + e->dx * (y-y_top) + // (y-y_top) = (x - e->x) / e->dx + // y = (x - e->x) / e->dx + y_top + float y1 = (x - x0) / dx + y_top; + float y2 = (x+1 - x0) / dx + y_top; + + if (x0 < x1 && x3 > x2) { // three segments descending down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x1 && x0 > x2) { // three segments descending down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); + stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); + } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); + stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); + } else { // one segment + stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); + } + } + } + } + e = e->next; + } +} + +// directly AA rasterize edges w/o supersampling +static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) +{ + stbtt__hheap hh = { 0, 0, 0 }; + stbtt__active_edge *active = NULL; + int y,j=0, i; + float scanline_data[129], *scanline, *scanline2; + + STBTT__NOTUSED(vsubsample); + + if (result->w > 64) + scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); + else + scanline = scanline_data; + + scanline2 = scanline + result->w; + + y = off_y; + e[n].y0 = (float) (off_y + result->h) + 1; + + while (j < result->h) { + // find center of pixel for this scanline + float scan_y_top = y + 0.0f; + float scan_y_bottom = y + 1.0f; + stbtt__active_edge **step = &active; + + STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); + STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); + + // update all active edges; + // remove all active edges that terminate before the top of this scanline + while (*step) { + stbtt__active_edge * z = *step; + if (z->ey <= scan_y_top) { + *step = z->next; // delete from list + STBTT_assert(z->direction); + z->direction = 0; + stbtt__hheap_free(&hh, z); + } else { + step = &((*step)->next); // advance through list + } + } + + // insert all edges that start before the bottom of this scanline + while (e->y0 <= scan_y_bottom) { + if (e->y0 != e->y1) { + stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); + if (z != NULL) { + if (j == 0 && off_y != 0) { + if (z->ey < scan_y_top) { + // this can happen due to subpixel positioning and some kind of fp rounding error i think + z->ey = scan_y_top; + } + } + STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds + // insert at front + z->next = active; + active = z; + } + } + ++e; + } + + // now process all active edges + if (active) + stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + + { + float sum = 0; + for (i=0; i < result->w; ++i) { + float k; + int m; + sum += scanline2[i]; + k = scanline[i] + sum; + k = (float) STBTT_fabs(k)*255 + 0.5f; + m = (int) k; + if (m > 255) m = 255; + result->pixels[j*result->stride + i] = (unsigned char) m; + } + } + // advance all the edges + step = &active; + while (*step) { + stbtt__active_edge *z = *step; + z->fx += z->fdx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + + ++y; + ++j; + } + + stbtt__hheap_cleanup(&hh, userdata); + + if (scanline != scanline_data) + STBTT_free(scanline, userdata); +} +#else +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + +#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) + +static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) +{ + int i,j; + for (i=1; i < n; ++i) { + stbtt__edge t = p[i], *a = &t; + j = i; + while (j > 0) { + stbtt__edge *b = &p[j-1]; + int c = STBTT__COMPARE(a,b); + if (!c) break; + p[j] = p[j-1]; + --j; + } + if (i != j) + p[j] = t; + } +} + +static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) +{ + /* threshold for transitioning to insertion sort */ + while (n > 12) { + stbtt__edge t; + int c01,c12,c,m,i,j; + + /* compute median of three */ + m = n >> 1; + c01 = STBTT__COMPARE(&p[0],&p[m]); + c12 = STBTT__COMPARE(&p[m],&p[n-1]); + /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ + if (c01 != c12) { + /* otherwise, we'll need to swap something else to middle */ + int z; + c = STBTT__COMPARE(&p[0],&p[n-1]); + /* 0>mid && midn => n; 0 0 */ + /* 0n: 0>n => 0; 0 n */ + z = (c == c12) ? 0 : n-1; + t = p[z]; + p[z] = p[m]; + p[m] = t; + } + /* now p[m] is the median-of-three */ + /* swap it to the beginning so it won't move around */ + t = p[0]; + p[0] = p[m]; + p[m] = t; + + /* partition loop */ + i=1; + j=n-1; + for(;;) { + /* handling of equality is crucial here */ + /* for sentinels & efficiency with duplicates */ + for (;;++i) { + if (!STBTT__COMPARE(&p[i], &p[0])) break; + } + for (;;--j) { + if (!STBTT__COMPARE(&p[0], &p[j])) break; + } + /* make sure we haven't crossed */ + if (i >= j) break; + t = p[i]; + p[i] = p[j]; + p[j] = t; + + ++i; + --j; + } + /* recurse on smaller side, iterate on larger */ + if (j < (n-i)) { + stbtt__sort_edges_quicksort(p,j); + p = p+i; + n = n-i; + } else { + stbtt__sort_edges_quicksort(p+i, n-i); + n = j; + } + } +} + +static void stbtt__sort_edges(stbtt__edge *p, int n) +{ + stbtt__sort_edges_quicksort(p, n); + stbtt__sort_edges_ins_sort(p, n); +} + +typedef struct +{ + float x,y; +} stbtt__point; + +static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) +{ + float y_scale_inv = invert ? -scale_y : scale_y; + stbtt__edge *e; + int n,i,j,k,m; +#if STBTT_RASTERIZER_VERSION == 1 + int vsubsample = result->h < 8 ? 15 : 5; +#elif STBTT_RASTERIZER_VERSION == 2 + int vsubsample = 1; +#else + #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#endif + // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + + // now we have to blow out the windings into explicit edge lists + n = 0; + for (i=0; i < windings; ++i) + n += wcount[i]; + + e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel + if (e == 0) return; + n = 0; + + m=0; + for (i=0; i < windings; ++i) { + stbtt__point *p = pts + m; + m += wcount[i]; + j = wcount[i]-1; + for (k=0; k < wcount[i]; j=k++) { + int a=k,b=j; + // skip the edge if horizontal + if (p[j].y == p[k].y) + continue; + // add edge from j to k to the list + e[n].invert = 0; + if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { + e[n].invert = 1; + a=j,b=k; + } + e[n].x0 = p[a].x * scale_x + shift_x; + e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; + e[n].x1 = p[b].x * scale_x + shift_x; + e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; + ++n; + } + } + + // now sort the edges by their highest point (should snap to integer, and then by x) + //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); + stbtt__sort_edges(e, n); + + // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule + stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); + + STBTT_free(e, userdata); +} + +static void stbtt__add_point(stbtt__point *points, int n, float x, float y) +{ + if (!points) return; // during first pass, it's unallocated + points[n].x = x; + points[n].y = y; +} + +// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching +static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) +{ + // midpoint + float mx = (x0 + 2*x1 + x2)/4; + float my = (y0 + 2*y1 + y2)/4; + // versus directly drawn line + float dx = (x0+x2)/2 - mx; + float dy = (y0+y2)/2 - my; + if (n > 16) // 65536 segments on one curve better be enough! + return 1; + if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA + stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x2,y2); + *num_points = *num_points+1; + } + return 1; +} + +static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) +{ + // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough + float dx0 = x1-x0; + float dy0 = y1-y0; + float dx1 = x2-x1; + float dy1 = y2-y1; + float dx2 = x3-x2; + float dy2 = y3-y2; + float dx = x3-x0; + float dy = y3-y0; + float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); + float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); + float flatness_squared = longlen*longlen-shortlen*shortlen; + + if (n > 16) // 65536 segments on one curve better be enough! + return; + + if (flatness_squared > objspace_flatness_squared) { + float x01 = (x0+x1)/2; + float y01 = (y0+y1)/2; + float x12 = (x1+x2)/2; + float y12 = (y1+y2)/2; + float x23 = (x2+x3)/2; + float y23 = (y2+y3)/2; + + float xa = (x01+x12)/2; + float ya = (y01+y12)/2; + float xb = (x12+x23)/2; + float yb = (y12+y23)/2; + + float mx = (xa+xb)/2; + float my = (ya+yb)/2; + + stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); + stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); + } else { + stbtt__add_point(points, *num_points,x3,y3); + *num_points = *num_points+1; + } +} + +// returns number of contours +static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) +{ + stbtt__point *points=0; + int num_points=0; + + float objspace_flatness_squared = objspace_flatness * objspace_flatness; + int i,n=0,start=0, pass; + + // count how many "moves" there are to get the contour count + for (i=0; i < num_verts; ++i) + if (vertices[i].type == STBTT_vmove) + ++n; + + *num_contours = n; + if (n == 0) return 0; + + *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + + if (*contour_lengths == 0) { + *num_contours = 0; + return 0; + } + + // make two passes through the points so we don't need to realloc + for (pass=0; pass < 2; ++pass) { + float x=0,y=0; + if (pass == 1) { + points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); + if (points == NULL) goto error; + } + num_points = 0; + n= -1; + for (i=0; i < num_verts; ++i) { + switch (vertices[i].type) { + case STBTT_vmove: + // start the next contour + if (n >= 0) + (*contour_lengths)[n] = num_points - start; + ++n; + start = num_points; + + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x,y); + break; + case STBTT_vline: + x = vertices[i].x, y = vertices[i].y; + stbtt__add_point(points, num_points++, x, y); + break; + case STBTT_vcurve: + stbtt__tesselate_curve(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + case STBTT_vcubic: + stbtt__tesselate_cubic(points, &num_points, x,y, + vertices[i].cx, vertices[i].cy, + vertices[i].cx1, vertices[i].cy1, + vertices[i].x, vertices[i].y, + objspace_flatness_squared, 0); + x = vertices[i].x, y = vertices[i].y; + break; + } + } + (*contour_lengths)[n] = num_points - start; + } + + return points; +error: + STBTT_free(points, userdata); + STBTT_free(*contour_lengths, userdata); + *contour_lengths = 0; + *num_contours = 0; + return NULL; +} + +STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) +{ + float scale = scale_x > scale_y ? scale_y : scale_x; + int winding_count = 0; + int *winding_lengths = NULL; + stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); + if (windings) { + stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); + STBTT_free(winding_lengths, userdata); + STBTT_free(windings, userdata); + } +} + +STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + int ix0,iy0,ix1,iy1; + stbtt__bitmap gbm; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + + if (scale_x == 0) scale_x = scale_y; + if (scale_y == 0) { + if (scale_x == 0) { + STBTT_free(vertices, info->userdata); + return NULL; + } + scale_y = scale_x; + } + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); + + // now we get the size + gbm.w = (ix1 - ix0); + gbm.h = (iy1 - iy0); + gbm.pixels = NULL; // in case we error + + if (width ) *width = gbm.w; + if (height) *height = gbm.h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + if (gbm.w && gbm.h) { + gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); + if (gbm.pixels) { + gbm.stride = gbm.w; + + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); + } + } + STBTT_free(vertices, info->userdata); + return gbm.pixels; +} + +STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) +{ + int ix0,iy0; + stbtt_vertex *vertices; + int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); + stbtt__bitmap gbm; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); + gbm.pixels = output; + gbm.w = out_w; + gbm.h = out_h; + gbm.stride = out_stride; + + if (gbm.w && gbm.h) + stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); + + STBTT_free(vertices, info->userdata); +} + +STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) +{ + stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); +} + +STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); +} + +STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) +{ + stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); +} + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-CRAPPY packing to keep source code small + +static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) + float pixel_height, // height of font in pixels + unsigned char *pixels, int pw, int ph, // bitmap to be filled in + int first_char, int num_chars, // characters to bake + stbtt_bakedchar *chardata) +{ + float scale; + int x,y,bottom_y, i; + stbtt_fontinfo f; + f.userdata = NULL; + if (!stbtt_InitFont(&f, data, offset)) + return -1; + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + x=y=1; + bottom_y = 1; + + scale = stbtt_ScaleForPixelHeight(&f, pixel_height); + + for (i=0; i < num_chars; ++i) { + int advance, lsb, x0,y0,x1,y1,gw,gh; + int g = stbtt_FindGlyphIndex(&f, first_char + i); + stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); + gw = x1-x0; + gh = y1-y0; + if (x + gw + 1 >= pw) + y = bottom_y, x = 1; // advance to next row + if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row + return -i; + STBTT_assert(x+gw < pw); + STBTT_assert(y+gh < ph); + stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); + chardata[i].x0 = (stbtt_int16) x; + chardata[i].y0 = (stbtt_int16) y; + chardata[i].x1 = (stbtt_int16) (x + gw); + chardata[i].y1 = (stbtt_int16) (y + gh); + chardata[i].xadvance = scale * advance; + chardata[i].xoff = (float) x0; + chardata[i].yoff = (float) y0; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; + } + return bottom_y; +} + +STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) +{ + float d3d_bias = opengl_fillrule ? 0 : -0.5f; + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_bakedchar *b = chardata + char_index; + int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); + int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); + + q->x0 = round_x + d3d_bias; + q->y0 = round_y + d3d_bias; + q->x1 = round_x + b->x1 - b->x0 + d3d_bias; + q->y1 = round_y + b->y1 - b->y0 + d3d_bias; + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION + +typedef int stbrp_coord; + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +struct stbrp_rect +{ + stbrp_coord x,y; + int id,w,h,was_packed; +}; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw - padding; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->padding = padding; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; + spc->skip_missing = 0; + + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); + + if (pixels) + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) +{ + spc->skip_missing = skip; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < h; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < w; ++i) { + STBTT_assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = (unsigned char) (total / kernel_width); + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze + for (j=0; j < w; ++j) { + int i; + unsigned int total; + STBTT_memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); + } + break; + case 5: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / 5); + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + break; + } + + for (; i < h; ++i) { + STBTT_assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); + } + + pixels += 1; + } +} + +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k; + int missing_glyph_added = 0; + + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + ranges[i].h_oversample = (unsigned char) spc->h_oversample; + ranges[i].v_oversample = (unsigned char) spc->v_oversample; + for (j=0; j < ranges[i].num_chars; ++j) { + int x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { + rects[k].w = rects[k].h = 0; + } else { + stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); + if (glyph == 0) + missing_glyph_added = 1; + } + ++k; + } + } + + return k; +} + +STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) +{ + stbtt_MakeGlyphBitmapSubpixel(info, + output, + out_w - (prefilter_x - 1), + out_h - (prefilter_y - 1), + out_stride, + scale_x, + scale_y, + shift_x, + shift_y, + glyph); + + if (prefilter_x > 1) + stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); + + if (prefilter_y > 1) + stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); + + *sub_x = stbtt__oversample_shift(prefilter_x); + *sub_y = stbtt__oversample_shift(prefilter_y); +} + +// rects array must be big enough to accommodate all characters in the given ranges +STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) +{ + int i,j,k, missing_glyph = -1, return_value = 1; + + // save current values + int old_h_over = spc->h_oversample; + int old_v_over = spc->v_oversample; + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); + float recip_h,recip_v,sub_x,sub_y; + spc->h_oversample = ranges[i].h_oversample; + spc->v_oversample = ranges[i].v_oversample; + recip_h = 1.0f / spc->h_oversample; + recip_v = 1.0f / spc->v_oversample; + sub_x = stbtt__oversample_shift(spc->h_oversample); + sub_y = stbtt__oversample_shift(spc->v_oversample); + for (j=0; j < ranges[i].num_chars; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed && r->w != 0 && r->h != 0) { + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; + int glyph = stbtt_FindGlyphIndex(info, codepoint); + stbrp_coord pad = (stbrp_coord) spc->padding; + + // pad on left and top + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; + stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, + spc->stride_in_bytes, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); + bc->xadvance = scale * advance; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; + + if (glyph == 0) + missing_glyph = j; + } else if (spc->skip_missing) { + return_value = 0; + } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { + ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; + + return return_value; +} + +STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) +{ + stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); +} + +STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i, j, n, return_value; // [DEAR IMGUI] removed = 1; + //stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars; + + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + + stbtt_PackFontRangesPackRects(spc, rects, n); + + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + + STBTT_free(rects, spc->user_allocator_context); + return return_value; +} + +STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, + int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; + range.array_of_unicode_codepoints = NULL; + range.num_chars = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + +STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) +{ + int i_ascent, i_descent, i_lineGap; + float scale; + stbtt_fontinfo info; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); + scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); + stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); + *ascent = (float) i_ascent * scale; + *descent = (float) i_descent * scale; + *lineGap = (float) i_lineGap * scale; +} + +STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + const stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + +////////////////////////////////////////////////////////////////////////////// +// +// sdf computation +// + +#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) +#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) + +static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) +{ + float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; + float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; + float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; + float roperp = orig[1]*ray[0] - orig[0]*ray[1]; + + float a = q0perp - 2*q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; + + float s0 = 0., s1 = 0.; + int num_s = 0; + + if (a != 0.0) { + float discr = b*b - a*c; + if (discr > 0.0) { + float rcpna = -1 / a; + float d = (float) STBTT_sqrt(discr); + s0 = (b+d) * rcpna; + s1 = (b-d) * rcpna; + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { + if (num_s == 0) s0 = s1; + ++num_s; + } + } + } else { + // 2*b*s + c = 0 + // s = -c / (2*b) + s0 = c / (-2 * b); + if (s0 >= 0.0 && s0 <= 1.0) + num_s = 1; + } + + if (num_s == 0) + return 0; + else { + float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); + float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; + + float q0d = q0[0]*rayn_x + q0[1]*rayn_y; + float q1d = q1[0]*rayn_x + q1[1]*rayn_y; + float q2d = q2[0]*rayn_x + q2[1]*rayn_y; + float rod = orig[0]*rayn_x + orig[1]*rayn_y; + + float q10d = q1d - q0d; + float q20d = q2d - q0d; + float q0rd = q0d - rod; + + hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; + hits[0][1] = a*s0+b; + + if (num_s > 1) { + hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; + hits[1][1] = a*s1+b; + return 2; + } else { + return 1; + } + } +} + +static int equal(float *a, float *b) +{ + return (a[0] == b[0] && a[1] == b[1]); +} + +static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) +{ + int i; + float orig[2], ray[2] = { 1, 0 }; + float y_frac; + int winding = 0; + + // make sure y never passes through a vertex of the shape + y_frac = (float) STBTT_fmod(y, 1.0f); + if (y_frac < 0.01f) + y += 0.01f; + else if (y_frac > 0.99f) + y -= 0.01f; + + orig[0] = x; + orig[1] = y; + + // test a ray from (-infinity,y) to (x,y) + for (i=0; i < nverts; ++i) { + if (verts[i].type == STBTT_vline) { + int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; + int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } + if (verts[i].type == STBTT_vcurve) { + int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; + int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; + int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; + int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); + int by = STBTT_max(y0,STBTT_max(y1,y2)); + if (y > ay && y < by && x > ax) { + float q0[2],q1[2],q2[2]; + float hits[2][2]; + q0[0] = (float)x0; + q0[1] = (float)y0; + q1[0] = (float)x1; + q1[1] = (float)y1; + q2[0] = (float)x2; + q2[1] = (float)y2; + if (equal(q0,q1) || equal(q1,q2)) { + x0 = (int)verts[i-1].x; + y0 = (int)verts[i-1].y; + x1 = (int)verts[i ].x; + y1 = (int)verts[i ].y; + if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { + float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; + if (x_inter < x) + winding += (y0 < y1) ? 1 : -1; + } + } else { + int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); + if (num_hits >= 1) + if (hits[0][0] < 0) + winding += (hits[0][1] < 0 ? -1 : 1); + if (num_hits >= 2) + if (hits[1][0] < 0) + winding += (hits[1][1] < 0 ? -1 : 1); + } + } + } + } + return winding; +} + +static float stbtt__cuberoot( float x ) +{ + if (x<0) + return -(float) STBTT_pow(-x,1.0f/3.0f); + else + return (float) STBTT_pow( x,1.0f/3.0f); +} + +// x^3 + a*x^2 + b*x + c = 0 +static int stbtt__solve_cubic(float a, float b, float c, float* r) +{ + float s = -a / 3; + float p = b - a*a / 3; + float q = a * (2*a*a - 9*b) / 27 + c; + float p3 = p*p*p; + float d = q*q + 4*p3 / 27; + if (d >= 0) { + float z = (float) STBTT_sqrt(d); + float u = (-q + z) / 2; + float v = (-q - z) / 2; + u = stbtt__cuberoot(u); + v = stbtt__cuberoot(v); + r[0] = s + u + v; + return 1; + } else { + float u = (float) STBTT_sqrt(-p/3); + float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative + float m = (float) STBTT_cos(v); + float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; + r[0] = s + u * 2 * m; + r[1] = s - u * (m + n); + r[2] = s - u * (m - n); + + //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? + //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); + //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); + return 3; + } +} + +STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + float scale_x = scale, scale_y = scale; + int ix0,iy0,ix1,iy1; + int w,h; + unsigned char *data; + + if (scale == 0) return NULL; + + stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; + + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; + + w = (ix1 - ix0); + h = (iy1 - iy0); + + if (width ) *width = w; + if (height) *height = h; + if (xoff ) *xoff = ix0; + if (yoff ) *yoff = iy0; + + // invert for y-downwards bitmaps + scale_y = -scale_y; + + { + int x,y,i,j; + float *precompute; + stbtt_vertex *verts; + int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); + data = (unsigned char *) STBTT_malloc(w * h, info->userdata); + precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); + + for (i=0,j=num_verts-1; i < num_verts; j=i++) { + if (verts[i].type == STBTT_vline) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; + float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); + precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; + float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; + float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float len2 = bx*bx + by*by; + if (len2 != 0.0f) + precompute[i] = 1.0f / (bx*bx + by*by); + else + precompute[i] = 0.0f; + } else + precompute[i] = 0.0f; + } + + for (y=iy0; y < iy1; ++y) { + for (x=ix0; x < ix1; ++x) { + float val; + float min_dist = 999999.0f; + float sx = (float) x + 0.5f; + float sy = (float) y + 0.5f; + float x_gspace = (sx / scale_x); + float y_gspace = (sy / scale_y); + + int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path + + for (i=0; i < num_verts; ++i) { + float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; + + if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { + float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; + + float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + // coarse culling against bbox + //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && + // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) + dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; + STBTT_assert(i != 0); + if (dist < min_dist) { + // check position along line + // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) + // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) + float dx = x1-x0, dy = y1-y0; + float px = x0-sx, py = y0-sy; + // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy + // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve + float t = -(px*dx + py*dy) / (dx*dx + dy*dy); + if (t >= 0.0f && t <= 1.0f) + min_dist = dist; + } + } else if (verts[i].type == STBTT_vcurve) { + float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; + float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; + float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); + float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); + float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); + float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); + // coarse culling against bbox to avoid computing cubic unnecessarily + if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { + int num=0; + float ax = x1-x0, ay = y1-y0; + float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; + float mx = x0 - sx, my = y0 - sy; + float res[3] = {0.f,0.f,0.f}; + float px,py,t,it,dist2; + float a_inv = precompute[i]; + if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula + float a = 3*(ax*bx + ay*by); + float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); + float c = mx*ax+my*ay; + if (a == 0.0) { // if a is 0, it's linear + if (b != 0.0) { + res[num++] = -c/b; + } + } else { + float discriminant = b*b - 4*a*c; + if (discriminant < 0) + num = 0; + else { + float root = (float) STBTT_sqrt(discriminant); + res[0] = (-b - root)/(2*a); + res[1] = (-b + root)/(2*a); + num = 2; // don't bother distinguishing 1-solution case, as code below will still work + } + } + } else { + float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point + float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; + float d = (mx*ax+my*ay) * a_inv; + num = stbtt__solve_cubic(b, c, d, res); + } + dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); + if (dist2 < min_dist*min_dist) + min_dist = (float) STBTT_sqrt(dist2); + + if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { + t = res[0], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { + t = res[1], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { + t = res[2], it = 1.0f - t; + px = it*it*x0 + 2*t*it*x1 + t*t*x2; + py = it*it*y0 + 2*t*it*y1 + t*t*y2; + dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); + if (dist2 < min_dist * min_dist) + min_dist = (float) STBTT_sqrt(dist2); + } + } + } + } + if (winding == 0) + min_dist = -min_dist; // if outside the shape, value is negative + val = onedge_value + pixel_dist_scale * min_dist; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; + } + } + STBTT_free(precompute, info->userdata); + STBTT_free(verts, info->userdata); + } + return data; +} + +STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) +{ + return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); +} + +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) +{ + STBTT_free(bitmap, userdata); +} + +////////////////////////////////////////////////////////////////////////////// +// +// font name matching -- recommended not to use this +// + +// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string +static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{ + stbtt_int32 i=0; + + // convert utf16 to utf8 and compare the results while converting + while (len2) { + stbtt_uint16 ch = s2[0]*256 + s2[1]; + if (ch < 0x80) { + if (i >= len1) return -1; + if (s1[i++] != ch) return -1; + } else if (ch < 0x800) { + if (i+1 >= len1) return -1; + if (s1[i++] != 0xc0 + (ch >> 6)) return -1; + if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; + } else if (ch >= 0xd800 && ch < 0xdc00) { + stbtt_uint32 c; + stbtt_uint16 ch2 = s2[2]*256 + s2[3]; + if (i+3 >= len1) return -1; + c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; + if (s1[i++] != 0xf0 + (c >> 18)) return -1; + if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; + s2 += 2; // plus another 2 below + len2 -= 2; + } else if (ch >= 0xdc00 && ch < 0xe000) { + return -1; + } else { + if (i+2 >= len1) return -1; + if (s1[i++] != 0xe0 + (ch >> 12)) return -1; + if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; + if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; + } + s2 += 2; + len2 -= 2; + } + return i; +} + +static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{ + return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); +} + +// returns results in whatever encoding you request... but note that 2-byte encodings +// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare +STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) +{ + stbtt_int32 i,count,stringOffset; + stbtt_uint8 *fc = font->data; + stbtt_uint32 offset = font->fontstart; + stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return NULL; + + count = ttUSHORT(fc+nm+2); + stringOffset = nm + ttUSHORT(fc+nm+4); + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) + && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { + *length = ttUSHORT(fc+loc+8); + return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); + } + } + return NULL; +} + +static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) +{ + stbtt_int32 i; + stbtt_int32 count = ttUSHORT(fc+nm+2); + stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); + + for (i=0; i < count; ++i) { + stbtt_uint32 loc = nm + 6 + 12 * i; + stbtt_int32 id = ttUSHORT(fc+loc+6); + if (id == target_id) { + // find the encoding + stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); + + // is this a Unicode encoding? + if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { + stbtt_int32 slen = ttUSHORT(fc+loc+8); + stbtt_int32 off = ttUSHORT(fc+loc+10); + + // check if there's a prefix match + stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); + if (matchlen >= 0) { + // check for target_id+1 immediately following, with same encoding & language + if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { + slen = ttUSHORT(fc+loc+12+8); + off = ttUSHORT(fc+loc+12+10); + if (slen == 0) { + if (matchlen == nlen) + return 1; + } else if (matchlen < nlen && name[matchlen] == ' ') { + ++matchlen; + if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) + return 1; + } + } else { + // if nothing immediately following + if (matchlen == nlen) + return 1; + } + } + } + + // @TODO handle other encodings + } + } + return 0; +} + +static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) +{ + stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); + stbtt_uint32 nm,hd; + if (!stbtt__isfont(fc+offset)) return 0; + + // check italics/bold/underline flags in macStyle... + if (flags) { + hd = stbtt__find_table(fc, offset, "head"); + if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; + } + + nm = stbtt__find_table(fc, offset, "name"); + if (!nm) return 0; + + if (flags) { + // if we checked the macStyle flags, then just check the family and ignore the subfamily + if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } else { + if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; + if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; + } + + return 0; +} + +static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) +{ + stbtt_int32 i; + for (i=0;;++i) { + stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); + if (off < 0) return off; + if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) + return off; + } +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, + float pixel_height, unsigned char *pixels, int pw, int ph, + int first_char, int num_chars, stbtt_bakedchar *chardata) +{ + return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); +} + +STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) +{ + return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); +} + +STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) +{ + return stbtt_GetNumberOfFonts_internal((unsigned char *) data); +} + +STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) +{ + return stbtt_InitFont_internal(info, (unsigned char *) data, offset); +} + +STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) +{ + return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); +} + +STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) +{ + return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); +} + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif // STB_TRUETYPE_IMPLEMENTATION + + +// FULL VERSION HISTORY +// +// 1.25 (2021-07-11) many fixes +// 1.24 (2020-02-05) fix warning +// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) +// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined +// 1.21 (2019-02-25) fix warning +// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() +// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod +// 1.18 (2018-01-29) add missing function +// 1.17 (2017-07-23) make more arguments const; doc fix +// 1.16 (2017-07-12) SDF support +// 1.15 (2017-03-03) make more arguments const +// 1.14 (2017-01-16) num-fonts-in-TTC function +// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts +// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual +// 1.11 (2016-04-02) fix unused-variable warning +// 1.10 (2016-04-02) allow user-defined fabs() replacement +// fix memory leak if fontsize=0.0 +// fix warning from duplicate typedef +// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges +// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges +// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; +// allow PackFontRanges to pack and render in separate phases; +// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); +// fixed an assert() bug in the new rasterizer +// replace assert() with STBTT_assert() in new rasterizer +// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) +// also more precise AA rasterizer, except if shapes overlap +// remove need for STBTT_sort +// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC +// 1.04 (2015-04-15) typo in example +// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling +// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) +// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID +// 0.8b (2014-07-07) fix a warning +// 0.8 (2014-05-25) fix a few more warnings +// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back +// 0.6c (2012-07-24) improve documentation +// 0.6b (2012-07-20) fix a few more warnings +// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, +// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty +// 0.5 (2011-12-09) bugfixes: +// subpixel glyph renderer computed wrong bounding box +// first vertex of shape can be off-curve (FreeSans) +// 0.4b (2011-12-03) fixed an error in the font baking example +// 0.4 (2011-12-01) kerning, subpixel rendering (tor) +// bugfixes for: +// codepoint-to-glyph conversion using table fmt=12 +// codepoint-to-glyph conversion using table fmt=4 +// stbtt_GetBakedQuad with non-square texture (Zer) +// updated Hello World! sample to use kerning and subpixel +// fixed some warnings +// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) +// userdata, malloc-from-userdata, non-zero fill (stb) +// 0.2 (2009-03-11) Fix unsigned/signed char warnings +// 0.1 (2009-03-09) First public release +// + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +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 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. +------------------------------------------------------------------------------ +*/ diff --git a/Amalgam/include/MinHook/MinHook.h b/Amalgam/include/MinHook/MinHook.h new file mode 100644 index 0000000..492d83f --- /dev/null +++ b/Amalgam/include/MinHook/MinHook.h @@ -0,0 +1,185 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * 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. + * + * 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 HOLDER + * 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. + */ + +#pragma once + +#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__) + #error MinHook supports only x86 and x64 systems. +#endif + +#include + +// MinHook Error Codes. +typedef enum MH_STATUS +{ + // Unknown error. Should not be returned. + MH_UNKNOWN = -1, + + // Successful. + MH_OK = 0, + + // MinHook is already initialized. + MH_ERROR_ALREADY_INITIALIZED, + + // MinHook is not initialized yet, or already uninitialized. + MH_ERROR_NOT_INITIALIZED, + + // The hook for the specified target function is already created. + MH_ERROR_ALREADY_CREATED, + + // The hook for the specified target function is not created yet. + MH_ERROR_NOT_CREATED, + + // The hook for the specified target function is already enabled. + MH_ERROR_ENABLED, + + // The hook for the specified target function is not enabled yet, or already + // disabled. + MH_ERROR_DISABLED, + + // The specified pointer is invalid. It points the address of non-allocated + // and/or non-executable region. + MH_ERROR_NOT_EXECUTABLE, + + // The specified target function cannot be hooked. + MH_ERROR_UNSUPPORTED_FUNCTION, + + // Failed to allocate memory. + MH_ERROR_MEMORY_ALLOC, + + // Failed to change the memory protection. + MH_ERROR_MEMORY_PROTECT, + + // The specified module is not loaded. + MH_ERROR_MODULE_NOT_FOUND, + + // The specified function is not found. + MH_ERROR_FUNCTION_NOT_FOUND +} +MH_STATUS; + +// Can be passed as a parameter to MH_EnableHook, MH_DisableHook, +// MH_QueueEnableHook or MH_QueueDisableHook. +#define MH_ALL_HOOKS NULL + +#ifdef __cplusplus +extern "C" { +#endif + + // Initialize the MinHook library. You must call this function EXACTLY ONCE + // at the beginning of your program. + MH_STATUS WINAPI MH_Initialize(VOID); + + // Uninitialize the MinHook library. You must call this function EXACTLY + // ONCE at the end of your program. + MH_STATUS WINAPI MH_Uninitialize(VOID); + + // Creates a hook for the specified target function, in disabled state. + // Parameters: + // pTarget [in] A pointer to the target function, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszProcName [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal); + + // Creates a hook for the specified API function, in disabled state. + // Parameters: + // pszModule [in] A pointer to the loaded module name which contains the + // target function. + // pszProcName [in] A pointer to the target function name, which will be + // overridden by the detour function. + // pDetour [in] A pointer to the detour function, which will override + // the target function. + // ppOriginal [out] A pointer to the trampoline function, which will be + // used to call the original target function. + // This parameter can be NULL. + // ppTarget [out] A pointer to the target function, which will be used + // with other functions. + // This parameter can be NULL. + MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget); + + // Removes an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget); + + // Enables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // enabled in one go. + MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget); + + // Disables an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // disabled in one go. + MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget); + + // Queues to enable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be enabled. + MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget); + + // Queues to disable an already created hook. + // Parameters: + // pTarget [in] A pointer to the target function. + // If this parameter is MH_ALL_HOOKS, all created hooks are + // queued to be disabled. + MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget); + + // Applies all queued changes in one go. + MH_STATUS WINAPI MH_ApplyQueued(VOID); + + // Translates the MH_STATUS to its name as a string. + const char * WINAPI MH_StatusToString(MH_STATUS status); + +#ifdef __cplusplus +} +#endif diff --git a/Amalgam/include/MinHook/buffer.c b/Amalgam/include/MinHook/buffer.c new file mode 100644 index 0000000..55412b0 --- /dev/null +++ b/Amalgam/include/MinHook/buffer.c @@ -0,0 +1,312 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * 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. + * + * 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 HOLDER + * 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 "buffer.h" + +// Size of each memory block. (= page size of VirtualAlloc) +#define MEMORY_BLOCK_SIZE 0x1000 + +// Max range for seeking a memory block. (= 1024MB) +#define MAX_MEMORY_RANGE 0x40000000 + +// Memory protection flags to check the executable address. +#define PAGE_EXECUTE_FLAGS \ + (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) + +// Memory slot. +typedef struct _MEMORY_SLOT +{ + union + { + struct _MEMORY_SLOT *pNext; + UINT8 buffer[MEMORY_SLOT_SIZE]; + }; +} MEMORY_SLOT, *PMEMORY_SLOT; + +// Memory block info. Placed at the head of each block. +typedef struct _MEMORY_BLOCK +{ + struct _MEMORY_BLOCK *pNext; + PMEMORY_SLOT pFree; // First element of the free slot list. + UINT usedCount; +} MEMORY_BLOCK, *PMEMORY_BLOCK; + +//------------------------------------------------------------------------- +// Global Variables: +//------------------------------------------------------------------------- + +// First element of the memory block list. +PMEMORY_BLOCK g_pMemoryBlocks; + +//------------------------------------------------------------------------- +VOID InitializeBuffer(VOID) +{ + // Nothing to do for now. +} + +//------------------------------------------------------------------------- +VOID UninitializeBuffer(VOID) +{ + PMEMORY_BLOCK pBlock = g_pMemoryBlocks; + g_pMemoryBlocks = NULL; + + while (pBlock) + { + PMEMORY_BLOCK pNext = pBlock->pNext; + VirtualFree(pBlock, 0, MEM_RELEASE); + pBlock = pNext; + } +} + +//------------------------------------------------------------------------- +#if defined(_M_X64) || defined(__x86_64__) +static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity) +{ + ULONG_PTR tryAddr = (ULONG_PTR)pAddress; + + // Round down to the allocation granularity. + tryAddr -= tryAddr % dwAllocationGranularity; + + // Start from the previous allocation granularity multiply. + tryAddr -= dwAllocationGranularity; + + while (tryAddr >= (ULONG_PTR)pMinAddr) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) + break; + + if (mbi.State == MEM_FREE) + return (LPVOID)tryAddr; + + if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity) + break; + + tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity; + } + + return NULL; +} +#endif + +//------------------------------------------------------------------------- +#if defined(_M_X64) || defined(__x86_64__) +static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity) +{ + ULONG_PTR tryAddr = (ULONG_PTR)pAddress; + + // Round down to the allocation granularity. + tryAddr -= tryAddr % dwAllocationGranularity; + + // Start from the next allocation granularity multiply. + tryAddr += dwAllocationGranularity; + + while (tryAddr <= (ULONG_PTR)pMaxAddr) + { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0) + break; + + if (mbi.State == MEM_FREE) + return (LPVOID)tryAddr; + + tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; + + // Round up to the next allocation granularity. + tryAddr += dwAllocationGranularity - 1; + tryAddr -= tryAddr % dwAllocationGranularity; + } + + return NULL; +} +#endif + +//------------------------------------------------------------------------- +static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin) +{ + PMEMORY_BLOCK pBlock; +#if defined(_M_X64) || defined(__x86_64__) + ULONG_PTR minAddr; + ULONG_PTR maxAddr; + + SYSTEM_INFO si; + GetSystemInfo(&si); + minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress; + maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress; + + // pOrigin ± 512MB + if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE) + minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE; + + if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE) + maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE; + + // Make room for MEMORY_BLOCK_SIZE bytes. + maxAddr -= MEMORY_BLOCK_SIZE - 1; +#endif + + // Look the registered blocks for a reachable one. + for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext) + { +#if defined(_M_X64) || defined(__x86_64__) + // Ignore the blocks too far. + if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr) + continue; +#endif + // The block has at least one unused slot. + if (pBlock->pFree != NULL) + return pBlock; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Alloc a new block above if not found. + { + LPVOID pAlloc = pOrigin; + while ((ULONG_PTR)pAlloc >= minAddr) + { + pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity); + if (pAlloc == NULL) + break; + + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (pBlock != NULL) + break; + } + } + + // Alloc a new block below if not found. + if (pBlock == NULL) + { + LPVOID pAlloc = pOrigin; + while ((ULONG_PTR)pAlloc <= maxAddr) + { + pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); + if (pAlloc == NULL) + break; + + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (pBlock != NULL) + break; + } + } +#else + // In x86 mode, a memory block can be placed anywhere. + pBlock = (PMEMORY_BLOCK)VirtualAlloc( + NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); +#endif + + if (pBlock != NULL) + { + // Build a linked list of all the slots. + PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1; + pBlock->pFree = NULL; + pBlock->usedCount = 0; + do + { + pSlot->pNext = pBlock->pFree; + pBlock->pFree = pSlot; + pSlot++; + } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE); + + pBlock->pNext = g_pMemoryBlocks; + g_pMemoryBlocks = pBlock; + } + + return pBlock; +} + +//------------------------------------------------------------------------- +LPVOID AllocateBuffer(LPVOID pOrigin) +{ + PMEMORY_SLOT pSlot; + PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin); + if (pBlock == NULL) + return NULL; + + // Remove an unused slot from the list. + pSlot = pBlock->pFree; + pBlock->pFree = pSlot->pNext; + pBlock->usedCount++; +#ifdef _DEBUG + // Fill the slot with INT3 for debugging. + memset(pSlot, 0xCC, sizeof(MEMORY_SLOT)); +#endif + return pSlot; +} + +//------------------------------------------------------------------------- +VOID FreeBuffer(LPVOID pBuffer) +{ + PMEMORY_BLOCK pBlock = g_pMemoryBlocks; + PMEMORY_BLOCK pPrev = NULL; + ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE; + + while (pBlock != NULL) + { + if ((ULONG_PTR)pBlock == pTargetBlock) + { + PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer; +#ifdef _DEBUG + // Clear the released slot for debugging. + memset(pSlot, 0x00, sizeof(MEMORY_SLOT)); +#endif + // Restore the released slot to the list. + pSlot->pNext = pBlock->pFree; + pBlock->pFree = pSlot; + pBlock->usedCount--; + + // Free if unused. + if (pBlock->usedCount == 0) + { + if (pPrev) + pPrev->pNext = pBlock->pNext; + else + g_pMemoryBlocks = pBlock->pNext; + + VirtualFree(pBlock, 0, MEM_RELEASE); + } + + break; + } + + pPrev = pBlock; + pBlock = pBlock->pNext; + } +} + +//------------------------------------------------------------------------- +BOOL IsExecutableAddress(LPVOID pAddress) +{ + MEMORY_BASIC_INFORMATION mi; + VirtualQuery(pAddress, &mi, sizeof(mi)); + + return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS)); +} diff --git a/Amalgam/include/MinHook/buffer.h b/Amalgam/include/MinHook/buffer.h new file mode 100644 index 0000000..204d551 --- /dev/null +++ b/Amalgam/include/MinHook/buffer.h @@ -0,0 +1,42 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * 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. + * + * 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 HOLDER + * 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. + */ + +#pragma once + +// Size of each memory slot. +#if defined(_M_X64) || defined(__x86_64__) + #define MEMORY_SLOT_SIZE 64 +#else + #define MEMORY_SLOT_SIZE 32 +#endif + +VOID InitializeBuffer(VOID); +VOID UninitializeBuffer(VOID); +LPVOID AllocateBuffer(LPVOID pOrigin); +VOID FreeBuffer(LPVOID pBuffer); +BOOL IsExecutableAddress(LPVOID pAddress); diff --git a/Amalgam/include/MinHook/hde/hde32.c b/Amalgam/include/MinHook/hde/hde32.c new file mode 100644 index 0000000..eb6af9b --- /dev/null +++ b/Amalgam/include/MinHook/hde/hde32.c @@ -0,0 +1,324 @@ +/* + * Hacker Disassembler Engine 32 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#if defined(_M_IX86) || defined(__i386__) + +#include +#include "hde32.h" +#include "table32.h" + +unsigned int hde32_disasm(const void *code, hde32s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; + + memset(hs, 0, sizeof(hde32s)); + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde32_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde32_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde32_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde32_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde32_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + break; + } + + if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + break; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (pref & PRE_66) { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } else { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } + } + + if (cflags & C_IMM16) { + if (hs->flags & F_IMM32) { + hs->flags |= F_IMM16; + hs->disp.disp16 = *(uint16_t *)p; + } else if (hs->flags & F_IMM16) { + hs->flags |= F_2IMM16; + hs->disp.disp16 = *(uint16_t *)p; + } else { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + } + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} + +#endif // defined(_M_IX86) || defined(__i386__) diff --git a/Amalgam/include/MinHook/hde/hde32.h b/Amalgam/include/MinHook/hde/hde32.h new file mode 100644 index 0000000..1112450 --- /dev/null +++ b/Amalgam/include/MinHook/hde/hde32.h @@ -0,0 +1,105 @@ +/* + * Hacker Disassembler Engine 32 + * Copyright (c) 2006-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde32.h: C/C++ header file + * + */ + +#ifndef _HDE32_H_ +#define _HDE32_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include "pstdint.h" + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_DISP8 0x00000020 +#define F_DISP16 0x00000040 +#define F_DISP32 0x00000080 +#define F_RELATIVE 0x00000100 +#define F_2IMM16 0x00000800 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_ANY 0x3f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde32s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde32_disasm(const void *code, hde32s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE32_H_ */ diff --git a/Amalgam/include/MinHook/hde/hde64.c b/Amalgam/include/MinHook/hde/hde64.c new file mode 100644 index 0000000..55a702e --- /dev/null +++ b/Amalgam/include/MinHook/hde/hde64.c @@ -0,0 +1,333 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#if defined(_M_X64) || defined(__x86_64__) + +#include +#include "hde64.h" +#include "table64.h" + +unsigned int hde64_disasm(const void *code, hde64s *hs) +{ + uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; + uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; + uint8_t op64 = 0; + + memset(hs, 0, sizeof(hde64s)); + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: case 0x2e: case 0x36: + case 0x3e: case 0x64: case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: + goto pref_done; + } + pref_done: + + hs->flags = (uint32_t)pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((c & 0xf0) == 0x40) { + hs->flags |= F_PREFIX_REX; + if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) + op64++; + hs->rex_r = (c & 7) >> 2; + hs->rex_x = (c & 3) >> 1; + hs->rex_b = c & 1; + if (((c = *p++) & 0xf0) == 0x40) { + opcode = c; + goto error_opcode; + } + } + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + op64++; + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + error_opcode: + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *)(ht + (cflags & 0x7f)); + cflags = (uint8_t)t; + x = (uint8_t)(t >> 8); + } + + if (hs->opcode2) { + ht = hde64_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde64_table + DELTA_FPU_MODRM + t*8; + t = ht[m_reg] << m_rm; + } else { + ht = hde64_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde64_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error: + ; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde64_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde64_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if (*ht++ & pref && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: case 0xd7: case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: + goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else + if (m_rm == 5) + disp_size = 4; + break; + case 1: + disp_size = 1; + break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + } + + if (m_mod != 3 && m_rm == 4) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *)p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *)p; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (op64) { + hs->flags |= F_IMM64; + hs->imm.imm64 = *(uint64_t *)p; + p += 8; + } else if (!(pref & PRE_66)) { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else + goto imm16_ok; + } + + + if (cflags & C_IMM16) { + imm16_ok: + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *)p; + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *)p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + + disasm_done: + + if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int)hs->len; +} + +#endif // defined(_M_X64) || defined(__x86_64__) diff --git a/Amalgam/include/MinHook/hde/hde64.h b/Amalgam/include/MinHook/hde/hde64.h new file mode 100644 index 0000000..ecbf4df --- /dev/null +++ b/Amalgam/include/MinHook/hde/hde64.h @@ -0,0 +1,112 @@ +/* + * Hacker Disassembler Engine 64 + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + * hde64.h: C/C++ header file + * + */ + +#ifndef _HDE64_H_ +#define _HDE64_H_ + +/* stdint.h - C99 standard header + * http://en.wikipedia.org/wiki/stdint.h + * + * if your compiler doesn't contain "stdint.h" header (for + * example, Microsoft Visual C++), you can download file: + * http://www.azillionmonkeys.com/qed/pstdint.h + * and change next line to: + * #include "pstdint.h" + */ +#include "pstdint.h" + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_IMM64 0x00000020 +#define F_DISP8 0x00000040 +#define F_DISP16 0x00000080 +#define F_DISP32 0x00000100 +#define F_RELATIVE 0x00000200 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_REX 0x40000000 +#define F_PREFIX_ANY 0x7f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push,1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t rex; + uint8_t rex_w; + uint8_t rex_r; + uint8_t rex_x; + uint8_t rex_b; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + uint64_t imm64; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde64s; + +#pragma pack(pop) + +#ifdef __cplusplus +extern "C" { +#endif + +/* __cdecl */ +unsigned int hde64_disasm(const void *code, hde64s *hs); + +#ifdef __cplusplus +} +#endif + +#endif /* _HDE64_H_ */ diff --git a/Amalgam/include/MinHook/hde/pstdint.h b/Amalgam/include/MinHook/hde/pstdint.h new file mode 100644 index 0000000..84d82a0 --- /dev/null +++ b/Amalgam/include/MinHook/hde/pstdint.h @@ -0,0 +1,39 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. 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. + * + * 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. + */ + +#pragma once + +#include + +// Integer types for HDE. +typedef INT8 int8_t; +typedef INT16 int16_t; +typedef INT32 int32_t; +typedef INT64 int64_t; +typedef UINT8 uint8_t; +typedef UINT16 uint16_t; +typedef UINT32 uint32_t; +typedef UINT64 uint64_t; diff --git a/Amalgam/include/MinHook/hde/table32.h b/Amalgam/include/MinHook/hde/table32.h new file mode 100644 index 0000000..7b3e12e --- /dev/null +++ b/Amalgam/include/MinHook/hde/table32.h @@ -0,0 +1,73 @@ +/* + * Hacker Disassembler Engine 32 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xf1 +#define DELTA_FPU_MODRM 0xf8 +#define DELTA_PREFIXES 0x130 +#define DELTA_OP_LOCK_OK 0x1a1 +#define DELTA_OP2_LOCK_OK 0x1b9 +#define DELTA_OP_ONLY_MEM 0x1cb +#define DELTA_OP2_ONLY_MEM 0x1da + +unsigned char hde32_table[] = { + 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3, + 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f, + 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3, + 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa, + 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90, + 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f, + 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d, + 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59, + 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59, + 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0, + 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01, + 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11, + 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8, + 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca, + 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff, + 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03, + 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00, + 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f, + 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a, + 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a, + 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a, + 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06, + 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06, + 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08, + 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01, + 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba, + 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00, + 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00, + 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07, + 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf, + 0xe7,0x08,0x00,0xf0,0x02,0x00 +}; diff --git a/Amalgam/include/MinHook/hde/table64.h b/Amalgam/include/MinHook/hde/table64.h new file mode 100644 index 0000000..01d4541 --- /dev/null +++ b/Amalgam/include/MinHook/hde/table64.h @@ -0,0 +1,74 @@ +/* + * Hacker Disassembler Engine 64 C + * Copyright (c) 2008-2009, Vyacheslav Patkov. + * All rights reserved. + * + */ + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xfd +#define DELTA_FPU_MODRM 0x104 +#define DELTA_PREFIXES 0x13c +#define DELTA_OP_LOCK_OK 0x1ae +#define DELTA_OP2_LOCK_OK 0x1c6 +#define DELTA_OP_ONLY_MEM 0x1d8 +#define DELTA_OP2_ONLY_MEM 0x1e7 + +unsigned char hde64_table[] = { + 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, + 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, + 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, + 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, + 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, + 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, + 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, + 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, + 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, + 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, + 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, + 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, + 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, + 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, + 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, + 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, + 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, + 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, + 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, + 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, + 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, + 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, + 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, + 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, + 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, + 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, + 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, + 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, + 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, + 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, + 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, + 0x00,0xf0,0x02,0x00 +}; diff --git a/Amalgam/include/MinHook/hook.c b/Amalgam/include/MinHook/hook.c new file mode 100644 index 0000000..26cc898 --- /dev/null +++ b/Amalgam/include/MinHook/hook.c @@ -0,0 +1,923 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * 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. + * + * 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 HOLDER + * 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 +#include + +#include "MinHook.h" +#include "buffer.h" +#include "trampoline.h" + +#ifndef ARRAYSIZE + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +// Initial capacity of the HOOK_ENTRY buffer. +#define INITIAL_HOOK_CAPACITY 32 + +// Initial capacity of the thread IDs buffer. +#define INITIAL_THREAD_CAPACITY 128 + +// Special hook position values. +#define INVALID_HOOK_POS UINT_MAX +#define ALL_HOOKS_POS UINT_MAX + +// Freeze() action argument defines. +#define ACTION_DISABLE 0 +#define ACTION_ENABLE 1 +#define ACTION_APPLY_QUEUED 2 + +// Thread access rights for suspending/resuming threads. +#define THREAD_ACCESS \ + (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT) + +// Hook information. +typedef struct _HOOK_ENTRY +{ + LPVOID pTarget; // Address of the target function. + LPVOID pDetour; // Address of the detour or relay function. + LPVOID pTrampoline; // Address of the trampoline function. + UINT8 backup[8]; // Original prologue of the target function. + + UINT8 patchAbove : 1; // Uses the hot patch area. + UINT8 isEnabled : 1; // Enabled. + UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled. + + UINT nIP : 4; // Count of the instruction boundaries. + UINT8 oldIPs[8]; // Instruction boundaries of the target function. + UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. +} HOOK_ENTRY, *PHOOK_ENTRY; + +// Suspended threads for Freeze()/Unfreeze(). +typedef struct _FROZEN_THREADS +{ + LPDWORD pItems; // Data heap + UINT capacity; // Size of allocated data heap, items + UINT size; // Actual number of data items +} FROZEN_THREADS, *PFROZEN_THREADS; + +//------------------------------------------------------------------------- +// Global Variables: +//------------------------------------------------------------------------- + +// Spin lock flag for EnterSpinLock()/LeaveSpinLock(). +volatile LONG g_isLocked = FALSE; + +// Private heap handle. If not NULL, this library is initialized. +HANDLE g_hHeap = NULL; + +// Hook entries. +struct +{ + PHOOK_ENTRY pItems; // Data heap + UINT capacity; // Size of allocated data heap, items + UINT size; // Actual number of data items +} g_hooks; + +//------------------------------------------------------------------------- +// Returns INVALID_HOOK_POS if not found. +static UINT FindHookEntry(LPVOID pTarget) +{ + UINT i; + for (i = 0; i < g_hooks.size; ++i) + { + if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget) + return i; + } + + return INVALID_HOOK_POS; +} + +//------------------------------------------------------------------------- +static PHOOK_ENTRY AddHookEntry() +{ + if (g_hooks.pItems == NULL) + { + g_hooks.capacity = INITIAL_HOOK_CAPACITY; + g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc( + g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY)); + if (g_hooks.pItems == NULL) + return NULL; + } + else if (g_hooks.size >= g_hooks.capacity) + { + PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( + g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY)); + if (p == NULL) + return NULL; + + g_hooks.capacity *= 2; + g_hooks.pItems = p; + } + + return &g_hooks.pItems[g_hooks.size++]; +} + +//------------------------------------------------------------------------- +static VOID DeleteHookEntry(UINT pos) +{ + if (pos < g_hooks.size - 1) + g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1]; + + g_hooks.size--; + + if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size) + { + PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc( + g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY)); + if (p == NULL) + return; + + g_hooks.capacity /= 2; + g_hooks.pItems = p; + } +} + +//------------------------------------------------------------------------- +static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip) +{ + UINT i; + + if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL))) + return (DWORD_PTR)pHook->pTarget; + + for (i = 0; i < pHook->nIP; ++i) + { + if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i])) + return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Check relay function. + if (ip == (DWORD_PTR)pHook->pDetour) + return (DWORD_PTR)pHook->pTarget; +#endif + + return 0; +} + +//------------------------------------------------------------------------- +static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip) +{ + UINT i; + for (i = 0; i < pHook->nIP; ++i) + { + if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i])) + return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]; + } + + return 0; +} + +//------------------------------------------------------------------------- +static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) +{ + // If the thread suspended in the overwritten area, + // move IP to the proper address. + + CONTEXT c; +#if defined(_M_X64) || defined(__x86_64__) + DWORD64 *pIP = &c.Rip; +#else + DWORD *pIP = &c.Eip; +#endif + UINT count; + + c.ContextFlags = CONTEXT_CONTROL; + if (!GetThreadContext(hThread, &c)) + return; + + if (pos == ALL_HOOKS_POS) + { + pos = 0; + count = g_hooks.size; + } + else + { + count = pos + 1; + } + + for (; pos < count; ++pos) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + BOOL enable; + DWORD_PTR ip; + + switch (action) + { + case ACTION_DISABLE: + enable = FALSE; + break; + + case ACTION_ENABLE: + enable = TRUE; + break; + + default: // ACTION_APPLY_QUEUED + enable = pHook->queueEnable; + break; + } + if (pHook->isEnabled == enable) + continue; + + if (enable) + ip = FindNewIP(pHook, *pIP); + else + ip = FindOldIP(pHook, *pIP); + + if (ip != 0) + { + *pIP = ip; + SetThreadContext(hThread, &c); + } + } +} + +//------------------------------------------------------------------------- +static BOOL EnumerateThreads(PFROZEN_THREADS pThreads) +{ + BOOL succeeded = FALSE; + + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hSnapshot != INVALID_HANDLE_VALUE) + { + THREADENTRY32 te; + te.dwSize = sizeof(THREADENTRY32); + if (Thread32First(hSnapshot, &te)) + { + succeeded = TRUE; + do + { + if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD)) + && te.th32OwnerProcessID == GetCurrentProcessId() + && te.th32ThreadID != GetCurrentThreadId()) + { + if (pThreads->pItems == NULL) + { + pThreads->capacity = INITIAL_THREAD_CAPACITY; + pThreads->pItems + = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD)); + if (pThreads->pItems == NULL) + { + succeeded = FALSE; + break; + } + } + else if (pThreads->size >= pThreads->capacity) + { + pThreads->capacity *= 2; + LPDWORD p = (LPDWORD)HeapReAlloc( + g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD)); + if (p == NULL) + { + succeeded = FALSE; + break; + } + + pThreads->pItems = p; + } + pThreads->pItems[pThreads->size++] = te.th32ThreadID; + } + + te.dwSize = sizeof(THREADENTRY32); + } while (Thread32Next(hSnapshot, &te)); + + if (succeeded && GetLastError() != ERROR_NO_MORE_FILES) + succeeded = FALSE; + + if (!succeeded && pThreads->pItems != NULL) + { + HeapFree(g_hHeap, 0, pThreads->pItems); + pThreads->pItems = NULL; + } + } + CloseHandle(hSnapshot); + } + + return succeeded; +} + +//------------------------------------------------------------------------- +static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action) +{ + MH_STATUS status = MH_OK; + + pThreads->pItems = NULL; + pThreads->capacity = 0; + pThreads->size = 0; + if (!EnumerateThreads(pThreads)) + { + status = MH_ERROR_MEMORY_ALLOC; + } + else if (pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); + if (hThread != NULL) + { + SuspendThread(hThread); + ProcessThreadIPs(hThread, pos, action); + CloseHandle(hThread); + } + } + } + + return status; +} + +//------------------------------------------------------------------------- +static VOID Unfreeze(PFROZEN_THREADS pThreads) +{ + if (pThreads->pItems != NULL) + { + UINT i; + for (i = 0; i < pThreads->size; ++i) + { + HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]); + if (hThread != NULL) + { + ResumeThread(hThread); + CloseHandle(hThread); + } + } + + HeapFree(g_hHeap, 0, pThreads->pItems); + } +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableHookLL(UINT pos, BOOL enable) +{ + PHOOK_ENTRY pHook = &g_hooks.pItems[pos]; + DWORD oldProtect; + SIZE_T patchSize = sizeof(JMP_REL); + LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget; + + if (pHook->patchAbove) + { + pPatchTarget -= sizeof(JMP_REL); + patchSize += sizeof(JMP_REL_SHORT); + } + + if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) + return MH_ERROR_MEMORY_PROTECT; + + if (enable) + { + PJMP_REL pJmp = (PJMP_REL)pPatchTarget; + pJmp->opcode = 0xE9; + pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL))); + + if (pHook->patchAbove) + { + PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget; + pShortJmp->opcode = 0xEB; + pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL))); + } + } + else + { + if (pHook->patchAbove) + memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); + else + memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL)); + } + + VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect); + + // Just-in-case measure. + FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize); + + pHook->isEnabled = enable; + pHook->queueEnable = enable; + + return MH_OK; +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableAllHooksLL(BOOL enable) +{ + MH_STATUS status = MH_OK; + UINT i, first = INVALID_HOOK_POS; + + for (i = 0; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != enable) + { + first = i; + break; + } + } + + if (first != INVALID_HOOK_POS) + { + FROZEN_THREADS threads; + status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE); + if (status == MH_OK) + { + for (i = first; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != enable) + { + status = EnableHookLL(i, enable); + if (status != MH_OK) + break; + } + } + + Unfreeze(&threads); + } + } + + return status; +} + +//------------------------------------------------------------------------- +static VOID EnterSpinLock(VOID) +{ + SIZE_T spinCount = 0; + + // Wait until the flag is FALSE. + while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE) + { + // No need to generate a memory barrier here, since InterlockedCompareExchange() + // generates a full memory barrier itself. + + // Prevent the loop from being too busy. + if (spinCount < 32) + Sleep(0); + else + Sleep(1); + + spinCount++; + } +} + +//------------------------------------------------------------------------- +static VOID LeaveSpinLock(VOID) +{ + // No need to generate a memory barrier here, since InterlockedExchange() + // generates a full memory barrier itself. + + InterlockedExchange(&g_isLocked, FALSE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_Initialize(VOID) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap == NULL) + { + g_hHeap = HeapCreate(0, 0, 0); + if (g_hHeap != NULL) + { + // Initialize the internal function buffer. + InitializeBuffer(); + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_ALREADY_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_Uninitialize(VOID) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + status = EnableAllHooksLL(FALSE); + if (status == MH_OK) + { + // Free the internal function buffer. + + // HeapFree is actually not required, but some tools detect a false + // memory leak without HeapFree. + + UninitializeBuffer(); + + HeapFree(g_hHeap, 0, g_hooks.pItems); + HeapDestroy(g_hHeap); + + g_hHeap = NULL; + + g_hooks.pItems = NULL; + g_hooks.capacity = 0; + g_hooks.size = 0; + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) + { + UINT pos = FindHookEntry(pTarget); + if (pos == INVALID_HOOK_POS) + { + LPVOID pBuffer = AllocateBuffer(pTarget); + if (pBuffer != NULL) + { + TRAMPOLINE ct; + + ct.pTarget = pTarget; + ct.pDetour = pDetour; + ct.pTrampoline = pBuffer; + if (CreateTrampolineFunction(&ct)) + { + PHOOK_ENTRY pHook = AddHookEntry(); + if (pHook != NULL) + { + pHook->pTarget = ct.pTarget; +#if defined(_M_X64) || defined(__x86_64__) + pHook->pDetour = ct.pRelay; +#else + pHook->pDetour = ct.pDetour; +#endif + pHook->pTrampoline = ct.pTrampoline; + pHook->patchAbove = ct.patchAbove; + pHook->isEnabled = FALSE; + pHook->queueEnable = FALSE; + pHook->nIP = ct.nIP; + memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); + memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); + + // Back up the target function. + + if (ct.patchAbove) + { + memcpy( + pHook->backup, + (LPBYTE)pTarget - sizeof(JMP_REL), + sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); + } + else + { + memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); + } + + if (ppOriginal != NULL) + *ppOriginal = pHook->pTrampoline; + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_UNSUPPORTED_FUNCTION; + } + + if (status != MH_OK) + { + FreeBuffer(pBuffer); + } + } + else + { + status = MH_ERROR_MEMORY_ALLOC; + } + } + else + { + status = MH_ERROR_ALREADY_CREATED; + } + } + else + { + status = MH_ERROR_NOT_EXECUTABLE; + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + UINT pos = FindHookEntry(pTarget); + if (pos != INVALID_HOOK_POS) + { + if (g_hooks.pItems[pos].isEnabled) + { + FROZEN_THREADS threads; + status = Freeze(&threads, pos, ACTION_DISABLE); + if (status == MH_OK) + { + status = EnableHookLL(pos, FALSE); + + Unfreeze(&threads); + } + } + + if (status == MH_OK) + { + FreeBuffer(g_hooks.pItems[pos].pTrampoline); + DeleteHookEntry(pos); + } + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + if (pTarget == MH_ALL_HOOKS) + { + status = EnableAllHooksLL(enable); + } + else + { + UINT pos = FindHookEntry(pTarget); + if (pos != INVALID_HOOK_POS) + { + if (g_hooks.pItems[pos].isEnabled != enable) + { + FROZEN_THREADS threads; + status = Freeze(&threads, pos, ACTION_ENABLE); + if (status == MH_OK) + { + status = EnableHookLL(pos, enable); + + Unfreeze(&threads); + } + } + else + { + status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; + } + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget) +{ + return EnableHook(pTarget, TRUE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget) +{ + return EnableHook(pTarget, FALSE); +} + +//------------------------------------------------------------------------- +static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) +{ + MH_STATUS status = MH_OK; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + if (pTarget == MH_ALL_HOOKS) + { + UINT i; + for (i = 0; i < g_hooks.size; ++i) + g_hooks.pItems[i].queueEnable = queueEnable; + } + else + { + UINT pos = FindHookEntry(pTarget); + if (pos != INVALID_HOOK_POS) + { + g_hooks.pItems[pos].queueEnable = queueEnable; + } + else + { + status = MH_ERROR_NOT_CREATED; + } + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget) +{ + return QueueHook(pTarget, TRUE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget) +{ + return QueueHook(pTarget, FALSE); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_ApplyQueued(VOID) +{ + MH_STATUS status = MH_OK; + UINT i, first = INVALID_HOOK_POS; + + EnterSpinLock(); + + if (g_hHeap != NULL) + { + for (i = 0; i < g_hooks.size; ++i) + { + if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) + { + first = i; + break; + } + } + + if (first != INVALID_HOOK_POS) + { + FROZEN_THREADS threads; + status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); + if (status == MH_OK) + { + for (i = first; i < g_hooks.size; ++i) + { + PHOOK_ENTRY pHook = &g_hooks.pItems[i]; + if (pHook->isEnabled != pHook->queueEnable) + { + status = EnableHookLL(i, pHook->queueEnable); + if (status != MH_OK) + break; + } + } + + Unfreeze(&threads); + } + } + } + else + { + status = MH_ERROR_NOT_INITIALIZED; + } + + LeaveSpinLock(); + + return status; +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookApiEx( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, + LPVOID *ppOriginal, LPVOID *ppTarget) +{ + HMODULE hModule; + LPVOID pTarget; + + hModule = GetModuleHandleW(pszModule); + if (hModule == NULL) + return MH_ERROR_MODULE_NOT_FOUND; + + pTarget = (LPVOID)GetProcAddress(hModule, pszProcName); + if (pTarget == NULL) + return MH_ERROR_FUNCTION_NOT_FOUND; + + if(ppTarget != NULL) + *ppTarget = pTarget; + + return MH_CreateHook(pTarget, pDetour, ppOriginal); +} + +//------------------------------------------------------------------------- +MH_STATUS WINAPI MH_CreateHookApi( + LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal) +{ + return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL); +} + +//------------------------------------------------------------------------- +const char * WINAPI MH_StatusToString(MH_STATUS status) +{ +#define MH_ST2STR(x) \ + case x: \ + return #x; + + switch (status) { + MH_ST2STR(MH_UNKNOWN) + MH_ST2STR(MH_OK) + MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED) + MH_ST2STR(MH_ERROR_NOT_INITIALIZED) + MH_ST2STR(MH_ERROR_ALREADY_CREATED) + MH_ST2STR(MH_ERROR_NOT_CREATED) + MH_ST2STR(MH_ERROR_ENABLED) + MH_ST2STR(MH_ERROR_DISABLED) + MH_ST2STR(MH_ERROR_NOT_EXECUTABLE) + MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION) + MH_ST2STR(MH_ERROR_MEMORY_ALLOC) + MH_ST2STR(MH_ERROR_MEMORY_PROTECT) + MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND) + MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND) + } + +#undef MH_ST2STR + + return "(unknown)"; +} \ No newline at end of file diff --git a/Amalgam/include/MinHook/trampoline.c b/Amalgam/include/MinHook/trampoline.c new file mode 100644 index 0000000..617baf3 --- /dev/null +++ b/Amalgam/include/MinHook/trampoline.c @@ -0,0 +1,320 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * 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. + * + * 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 HOLDER + * 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 _MSC_VER + #include +#endif + +#ifndef ARRAYSIZE + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#endif + +#if defined(_M_X64) || defined(__x86_64__) + #include "./hde/hde64.h" + typedef hde64s HDE; + #define HDE_DISASM(code, hs) hde64_disasm(code, hs) +#else + #include "./hde/hde32.h" + typedef hde32s HDE; + #define HDE_DISASM(code, hs) hde32_disasm(code, hs) +#endif + +#include "trampoline.h" +#include "buffer.h" + +// Maximum size of a trampoline function. +#if defined(_M_X64) || defined(__x86_64__) + #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS)) +#else + #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE +#endif + +//------------------------------------------------------------------------- +static BOOL IsCodePadding(LPBYTE pInst, UINT size) +{ + UINT i; + + if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC) + return FALSE; + + for (i = 1; i < size; ++i) + { + if (pInst[i] != pInst[0]) + return FALSE; + } + return TRUE; +} + +//------------------------------------------------------------------------- +BOOL CreateTrampolineFunction(PTRAMPOLINE ct) +{ +#if defined(_M_X64) || defined(__x86_64__) + CALL_ABS call = { + 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8] + 0xEB, 0x08, // EB 08: JMP +10 + 0x0000000000000000ULL // Absolute destination address + }; + JMP_ABS jmp = { + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; + JCC_ABS jcc = { + 0x70, 0x0E, // 7* 0E: J** +16 + 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6] + 0x0000000000000000ULL // Absolute destination address + }; +#else + CALL_REL call = { + 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + JMP_REL jmp = { + 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx + 0x00000000 // Relative destination address + }; + JCC_REL jcc = { + 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx + 0x00000000 // Relative destination address + }; +#endif + + UINT8 oldPos = 0; + UINT8 newPos = 0; + ULONG_PTR jmpDest = 0; // Destination address of an internal jump. + BOOL finished = FALSE; // Is the function completed? +#if defined(_M_X64) || defined(__x86_64__) + UINT8 instBuf[16]; +#endif + + ct->patchAbove = FALSE; + ct->nIP = 0; + + do + { + HDE hs; + UINT copySize; + LPVOID pCopySrc; + ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos; + ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos; + + copySize = HDE_DISASM((LPVOID)pOldInst, &hs); + if (hs.flags & F_ERROR) + return FALSE; + + pCopySrc = (LPVOID)pOldInst; + if (oldPos >= sizeof(JMP_REL)) + { + // The trampoline function is long enough. + // Complete the function with the jump to the target function. +#if defined(_M_X64) || defined(__x86_64__) + jmp.address = pOldInst; +#else + jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); +#endif + pCopySrc = &jmp; + copySize = sizeof(jmp); + + finished = TRUE; + } +#if defined(_M_X64) || defined(__x86_64__) + else if ((hs.modrm & 0xC7) == 0x05) + { + // Instructions using RIP relative addressing. (ModR/M = 00???101B) + + // Modify the RIP relative address. + PUINT32 pRelAddr; + + // Avoid using memcpy to reduce the footprint. +#ifndef _MSC_VER + memcpy(instBuf, (LPBYTE)pOldInst, copySize); +#else + __movsb(instBuf, (LPBYTE)pOldInst, copySize); +#endif + pCopySrc = instBuf; + + // Relative address is stored at (instruction length - immediate value length - 4). + pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); + *pRelAddr + = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); + + // Complete the function if JMP (FF /4). + if (hs.opcode == 0xFF && hs.modrm_reg == 4) + finished = TRUE; + } +#endif + else if (hs.opcode == 0xE8) + { + // Direct relative CALL + ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; +#if defined(_M_X64) || defined(__x86_64__) + call.address = dest; +#else + call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); +#endif + pCopySrc = &call; + copySize = sizeof(call); + } + else if ((hs.opcode & 0xFD) == 0xE9) + { + // Direct relative JMP (EB or E9) + ULONG_PTR dest = pOldInst + hs.len; + + if (hs.opcode == 0xEB) // isShort jmp + dest += (INT8)hs.imm.imm8; + else + dest += (INT32)hs.imm.imm32; + + // Simply copy an internal jump. + if ((ULONG_PTR)ct->pTarget <= dest + && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) + { + if (jmpDest < dest) + jmpDest = dest; + } + else + { +#if defined(_M_X64) || defined(__x86_64__) + jmp.address = dest; +#else + jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); +#endif + pCopySrc = &jmp; + copySize = sizeof(jmp); + + // Exit the function if it is not in the branch. + finished = (pOldInst >= jmpDest); + } + } + else if ((hs.opcode & 0xF0) == 0x70 + || (hs.opcode & 0xFC) == 0xE0 + || (hs.opcode2 & 0xF0) == 0x80) + { + // Direct relative Jcc + ULONG_PTR dest = pOldInst + hs.len; + + if ((hs.opcode & 0xF0) == 0x70 // Jcc + || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ + dest += (INT8)hs.imm.imm8; + else + dest += (INT32)hs.imm.imm32; + + // Simply copy an internal jump. + if ((ULONG_PTR)ct->pTarget <= dest + && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) + { + if (jmpDest < dest) + jmpDest = dest; + } + else if ((hs.opcode & 0xFC) == 0xE0) + { + // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. + return FALSE; + } + else + { + UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); +#if defined(_M_X64) || defined(__x86_64__) + // Invert the condition in x64 mode to simplify the conditional jump logic. + jcc.opcode = 0x71 ^ cond; + jcc.address = dest; +#else + jcc.opcode1 = 0x80 | cond; + jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); +#endif + pCopySrc = &jcc; + copySize = sizeof(jcc); + } + } + else if ((hs.opcode & 0xFE) == 0xC2) + { + // RET (C2 or C3) + + // Complete the function if not in a branch. + finished = (pOldInst >= jmpDest); + } + + // Can't alter the instruction length in a branch. + if (pOldInst < jmpDest && copySize != hs.len) + return FALSE; + + // Trampoline function is too large. + if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) + return FALSE; + + // Trampoline function has too many instructions. + if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) + return FALSE; + + ct->oldIPs[ct->nIP] = oldPos; + ct->newIPs[ct->nIP] = newPos; + ct->nIP++; + + // Avoid using memcpy to reduce the footprint. +#ifndef _MSC_VER + memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize); +#else + __movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize); +#endif + newPos += copySize; + oldPos += hs.len; + } + while (!finished); + + // Is there enough place for a long jump? + if (oldPos < sizeof(JMP_REL) + && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos)) + { + // Is there enough place for a short jump? + if (oldPos < sizeof(JMP_REL_SHORT) + && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos)) + { + return FALSE; + } + + // Can we place the long jump above the function? + if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL))) + return FALSE; + + if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL))) + return FALSE; + + ct->patchAbove = TRUE; + } + +#if defined(_M_X64) || defined(__x86_64__) + // Create a relay function. + jmp.address = (ULONG_PTR)ct->pDetour; + + ct->pRelay = (LPBYTE)ct->pTrampoline + newPos; + memcpy(ct->pRelay, &jmp, sizeof(jmp)); +#endif + + return TRUE; +} diff --git a/Amalgam/include/MinHook/trampoline.h b/Amalgam/include/MinHook/trampoline.h new file mode 100644 index 0000000..bdffdac --- /dev/null +++ b/Amalgam/include/MinHook/trampoline.h @@ -0,0 +1,105 @@ +/* + * MinHook - The Minimalistic API Hooking Library for x64/x86 + * Copyright (C) 2009-2017 Tsuda Kageyu. + * 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. + * + * 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 HOLDER + * 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. + */ + +#pragma once + +#pragma pack(push, 1) + +// Structs for writing x86/x64 instructions. + +// 8-bit relative jump. +typedef struct _JMP_REL_SHORT +{ + UINT8 opcode; // EB xx: JMP +2+xx + UINT8 operand; +} JMP_REL_SHORT, *PJMP_REL_SHORT; + +// 32-bit direct relative jump/call. +typedef struct _JMP_REL +{ + UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx + UINT32 operand; // Relative destination address +} JMP_REL, *PJMP_REL, CALL_REL; + +// 64-bit indirect absolute jump. +typedef struct _JMP_ABS +{ + UINT8 opcode0; // FF25 00000000: JMP [+6] + UINT8 opcode1; + UINT32 dummy; + UINT64 address; // Absolute destination address +} JMP_ABS, *PJMP_ABS; + +// 64-bit indirect absolute call. +typedef struct _CALL_ABS +{ + UINT8 opcode0; // FF15 00000002: CALL [+6] + UINT8 opcode1; + UINT32 dummy0; + UINT8 dummy1; // EB 08: JMP +10 + UINT8 dummy2; + UINT64 address; // Absolute destination address +} CALL_ABS; + +// 32-bit direct relative conditional jumps. +typedef struct _JCC_REL +{ + UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx + UINT8 opcode1; + UINT32 operand; // Relative destination address +} JCC_REL; + +// 64bit indirect absolute conditional jumps that x64 lacks. +typedef struct _JCC_ABS +{ + UINT8 opcode; // 7* 0E: J** +16 + UINT8 dummy0; + UINT8 dummy1; // FF25 00000000: JMP [+6] + UINT8 dummy2; + UINT32 dummy3; + UINT64 address; // Absolute destination address +} JCC_ABS; + +#pragma pack(pop) + +typedef struct _TRAMPOLINE +{ + LPVOID pTarget; // [In] Address of the target function. + LPVOID pDetour; // [In] Address of the detour function. + LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function. + +#if defined(_M_X64) || defined(__x86_64__) + LPVOID pRelay; // [Out] Address of the relay function. +#endif + BOOL patchAbove; // [Out] Should use the hot patch area? + UINT nIP; // [Out] Number of the instruction boundaries. + UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. + UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. +} TRAMPOLINE, *PTRAMPOLINE; + +BOOL CreateTrampolineFunction(PTRAMPOLINE ct); diff --git a/Amalgam/packages.config b/Amalgam/packages.config new file mode 100644 index 0000000..04f9fc0 --- /dev/null +++ b/Amalgam/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Amalgam/src/Core/Core.cpp b/Amalgam/src/Core/Core.cpp new file mode 100644 index 0000000..2d35b9d --- /dev/null +++ b/Amalgam/src/Core/Core.cpp @@ -0,0 +1,59 @@ +#include "Core.h" + +#include "../SDK/SDK.h" +#include "../Features/Visuals/Materials/Materials.h" +#include "../Features/Configs/Configs.h" +#include "../Features/Commands/Commands.h" +#include "../Features/ImGui/Menu/Menu.h" +#include "../Features/Visuals/Visuals.h" + +void CCore::Load() +{ + // Check the DirectX version + + U::Signatures.Initialize(); + U::Interfaces.Initialize(); + U::Hooks.Initialize(); + U::ConVars.Initialize(); + F::Materials.LoadMaterials(); + F::Commands.Initialize(); + + F::Configs.LoadConfig(F::Configs.sCurrentConfig, false); + F::Menu.ConfigLoaded = true; + + SDK::Output("Amalgam", "Loaded", { 175, 150, 255, 255 }); +} + +void CCore::Unload() +{ + G::Unload = true; + + U::Hooks.Unload(); + U::ConVars.Unload(); + F::Materials.UnloadMaterials(); + + F::Visuals.RestoreWorldModulation(); + Vars::Visuals::World::SkyboxChanger.Value = "Off"; // hooks won't run, remove here + if (I::Input->CAM_IsThirdPerson()) + { + auto pLocal = H::Entities.GetLocal(); + if (pLocal) + { + I::Input->CAM_ToFirstPerson(); + pLocal->ThirdPersonSwitch(); + } + } + if (auto cl_wpn_sway_interp = U::ConVars.FindVar("cl_wpn_sway_interp")) + cl_wpn_sway_interp->SetValue(0.f); + if (auto cl_wpn_sway_scale = U::ConVars.FindVar("cl_wpn_sway_scale")) + cl_wpn_sway_scale->SetValue(0.f); + + Sleep(250); + + SDK::Output("Amalgam", "Unloaded", { 175, 150, 255, 255 }); +} + +bool CCore::ShouldUnload() +{ + return SDK::IsGameWindowInFocus() && GetAsyncKeyState(VK_F11) & 0x8000 || bUnload; +} \ No newline at end of file diff --git a/Amalgam/src/Core/Core.h b/Amalgam/src/Core/Core.h new file mode 100644 index 0000000..ffb265e --- /dev/null +++ b/Amalgam/src/Core/Core.h @@ -0,0 +1,14 @@ +#pragma once +#include "../Utils/Feature/Feature.h" + +class CCore +{ +public: + void Load(); + void Unload(); + + bool ShouldUnload(); + bool bUnload = false; +}; + +ADD_FEATURE_CUSTOM(CCore, Core, U); \ No newline at end of file diff --git a/Amalgam/src/DllMain.cpp b/Amalgam/src/DllMain.cpp new file mode 100644 index 0000000..4a66df1 --- /dev/null +++ b/Amalgam/src/DllMain.cpp @@ -0,0 +1,36 @@ +#include +#include "Core/Core.h" +#include "Utils/Minidump/Minidump.h" + +DWORD WINAPI MainThread(LPVOID lpParam) +{ + while (!GetModuleHandleA("XAudio2_7.dll")) + Sleep(2000); + + U::Core.Load(); + while (!U::Core.ShouldUnload()) + Sleep(50); + U::Core.Unload(); + +#ifndef _DEBUG + SetUnhandledExceptionFilter(nullptr); +#endif + FreeLibraryAndExitThread(static_cast(lpParam), EXIT_SUCCESS); +} + + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { +#ifndef _DEBUG + SetUnhandledExceptionFilter(Minidump::ExceptionFilter); +#endif + + DisableThreadLibraryCalls(hinstDLL); + if (const auto hMainThread = CreateThread(nullptr, 0, MainThread, hinstDLL, 0, nullptr)) + CloseHandle(hMainThread); + } + + return TRUE; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/Aimbot.cpp b/Amalgam/src/Features/Aimbot/Aimbot.cpp new file mode 100644 index 0000000..b761b1f --- /dev/null +++ b/Amalgam/src/Features/Aimbot/Aimbot.cpp @@ -0,0 +1,71 @@ +#include "Aimbot.h" + +#include "AimbotHitscan/AimbotHitscan.h" +#include "AimbotProjectile/AimbotProjectile.h" +#include "AimbotMelee/AimbotMelee.h" +#include "AutoDetonate/AutoDetonate.h" +#include "AutoAirblast/AutoAirblast.h" +#include "AutoUber/AutoUber.h" +#include "AutoRocketJump/AutoRocketJump.h" +#include "../Misc/Misc.h" + +bool CAimbot::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (!pLocal || !pWeapon + || !pLocal->IsAlive() + || pLocal->IsTaunting() + || pLocal->IsBonked() + || pLocal->m_bFeignDeathReady() + || pLocal->IsCloaked() + || pLocal->IsInBumperKart() + || pLocal->IsAGhost()) + return false; + + switch (G::WeaponDefIndex) + { + case Soldier_m_RocketJumper: + case Demoman_s_StickyJumper: + return false; + } + + if (I::EngineVGui->IsGameUIVisible() || I::MatSystemSurface->IsCursorVisible()) + return false; + + return true; +} + +bool CAimbot::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + G::AimPosition = Vec3(); + if (pCmd->weaponselect) + return false; + + F::AutoRocketJump.Run(pLocal, pWeapon, pCmd); + + if (!ShouldRun(pLocal, pWeapon)) + return false; + + F::AutoDetonate.Run(pLocal, pWeapon, pCmd); + F::AutoAirblast.Run(pLocal, pWeapon, pCmd); + F::AutoUber.Run(pLocal, pWeapon, pCmd); + + const bool bAttacking = G::IsAttacking; + switch (G::WeaponType) + { + case EWeaponType::HITSCAN: F::AimbotHitscan.Run(pLocal, pWeapon, pCmd); break; + case EWeaponType::PROJECTILE: F::AimbotProjectile.Run(pLocal, pWeapon, pCmd); break; + case EWeaponType::MELEE: F::AimbotMelee.Run(pLocal, pWeapon, pCmd); break; + } + + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_COMPOUND_BOW: + case TF_WEAPON_PIPEBOMBLAUNCHER: + case TF_WEAPON_STICKY_BALL_LAUNCHER: + case TF_WEAPON_GRENADE_STICKY_BALL: + case TF_WEAPON_CANNON: + if (!(G::Buttons & IN_ATTACK) && pCmd->buttons & IN_ATTACK) + return true; + } + return bAttacking != G::IsAttacking; +} diff --git a/Amalgam/src/Features/Aimbot/Aimbot.h b/Amalgam/src/Features/Aimbot/Aimbot.h new file mode 100644 index 0000000..9a3ffae --- /dev/null +++ b/Amalgam/src/Features/Aimbot/Aimbot.h @@ -0,0 +1,13 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CAimbot +{ +private: + bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + +public: + bool Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CAimbot, Aimbot) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp b/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp new file mode 100644 index 0000000..8043b00 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp @@ -0,0 +1,124 @@ +#include "AimbotGlobal.h" + +#include "../../Players/PlayerUtils.h" + +void CAimbotGlobal::SortTargets(std::vector* targets, const ESortMethod& method) +{ // Sort by preference + std::sort((*targets).begin(), (*targets).end(), [&](const Target_t& a, const Target_t& b) -> bool + { + switch (method) + { + case ESortMethod::FOV: return a.m_flFOVTo < b.m_flFOVTo; + case ESortMethod::DISTANCE: return a.m_flDistTo < b.m_flDistTo; + default: return false; + } + }); +} + +void CAimbotGlobal::SortPriority(std::vector* targets) +{ // Sort by priority + std::sort((*targets).begin(), (*targets).end(), [&](const Target_t& a, const Target_t& b) -> bool + { + return a.m_nPriority > b.m_nPriority; + }); +} + +bool CAimbotGlobal::ShouldIgnore(CTFPlayer* pTarget, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bMedigun) +{ + PlayerInfo_t pi{}; + if (!pTarget || pTarget == pLocal || pTarget->IsDormant()) + return true; + if (!I::EngineClient->GetPlayerInfo(pTarget->entindex(), &pi)) + return true; + + if (pLocal->m_iTeamNum() == pTarget->m_iTeamNum()) + { + if (bMedigun) + return pTarget->IsInvisible(); + return false; + } + + if (Vars::Aimbot::General::Ignore.Value & INVUL && pTarget->IsInvulnerable()) + { + if (G::WeaponDefIndex != Heavy_t_TheHolidayPunch) + return true; + } + if (Vars::Aimbot::General::Ignore.Value & CLOAKED && pTarget->IsInvisible()) + { + if (pTarget->GetInvisPercentage() >= Vars::Aimbot::General::IgnoreCloakPercentage.Value) + return true; + } + if (Vars::Aimbot::General::Ignore.Value & DEADRINGER && pTarget->m_bFeignDeathReady()) + return true; + if (Vars::Aimbot::General::Ignore.Value & TAUNTING && pTarget->IsTaunting()) + return true; + if (Vars::Aimbot::General::Ignore.Value & VACCINATOR) + { + switch (G::WeaponType) + { + case EWeaponType::HITSCAN: + if (pTarget->IsBulletResist() && G::WeaponDefIndex != Spy_m_TheEnforcer) + return true; + break; + case EWeaponType::PROJECTILE: + if (pTarget->IsFireResist() && (pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER || pWeapon->m_iWeaponID() == TF_WEAPON_FLAREGUN)) + return true; + else if (pTarget->IsBulletResist() && pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW) + return true; + else if (pTarget->IsBlastResist()) + return true; + } + } + if (Vars::Aimbot::General::Ignore.Value & DISGUISED && pTarget->IsDisguised()) + return true; + + if (F::PlayerUtils.IsIgnored(pi.friendsID)) + return true; + + return false; +} + +int CAimbotGlobal::GetPriority(int targetIdx) +{ + return F::PlayerUtils.GetPriority(targetIdx); +} + +// will not predict for projectile weapons +bool CAimbotGlobal::ValidBomb(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pBomb) +{ + if (G::WeaponType == EWeaponType::PROJECTILE) + return false; + + Vec3 vOrigin = pBomb->m_vecOrigin(); + + CBaseEntity* pEntity; + for (CEntitySphereQuery sphere(vOrigin, 300.f); + (pEntity = sphere.GetCurrentEntity()) != nullptr; + sphere.NextEntity()) + { + if (!pEntity || pEntity == pLocal || pEntity->IsPlayer() && (!pEntity->As()->IsAlive() || pEntity->As()->IsAGhost()) || pEntity->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + + Vec3 vPos = {}; reinterpret_cast(pEntity->GetCollideable())->CalcNearestPoint(vOrigin, &vPos); + if (vOrigin.DistTo(vPos) > 300.f) + continue; + + bool isPlayer = Vars::Aimbot::General::Target.Value & PLAYER && pEntity->IsPlayer(); + bool isSentry = Vars::Aimbot::General::Target.Value & SENTRY && pEntity->IsSentrygun(); + bool isDispenser = Vars::Aimbot::General::Target.Value & DISPENSER && pEntity->IsDispenser(); + bool isTeleporter = Vars::Aimbot::General::Target.Value & TELEPORTER && pEntity->IsTeleporter(); + bool isNPC = Vars::Aimbot::General::Target.Value & NPC && pEntity->IsNPC(); + if (isPlayer || isSentry || isDispenser || isTeleporter || isNPC) + { + if (isPlayer && ShouldIgnore(pEntity->As(), pLocal, pWeapon)) + continue; + + if (!SDK::VisPosProjectile(pBomb, pEntity, vOrigin, isPlayer ? pEntity->m_vecOrigin() + pEntity->As()->GetViewOffset() : pEntity->GetCenter(), MASK_SHOT)) + continue; + + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.h b/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.h new file mode 100644 index 0000000..856537c --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.h @@ -0,0 +1,70 @@ +#pragma once +#include "../../../SDK/SDK.h" +#include "../../Backtrack/Backtrack.h" + +enum struct ETargetType +{ + UNKNOWN, + PLAYER, + SENTRY, + DISPENSER, + TELEPORTER, + STICKY, + NPC, + BOMBS +}; + +enum struct ESortMethod +{ + FOV, + DISTANCE +}; + +enum Target +{ + PLAYER = 1 << 0, + SENTRY = 1 << 1, + DISPENSER = 1 << 2, + TELEPORTER = 1 << 3, + STICKY = 1 << 4, + NPC = 1 << 5, + BOMB = 1 << 6 +}; + +enum Ignored +{ + INVUL = 1 << 0, + CLOAKED = 1 << 1, + DEADRINGER = 1 << 2, + VACCINATOR = 1 << 3, + UNSIMULATED = 1 << 4, + DISGUISED = 1 << 5, + TAUNTING = 1 << 6 +}; + +struct Target_t +{ + CBaseEntity* m_pEntity = nullptr; + ETargetType m_TargetType = ETargetType::UNKNOWN; + Vec3 m_vPos = {}; + Vec3 m_vAngleTo = {}; + float m_flFOVTo = std::numeric_limits::max(); + float m_flDistTo = std::numeric_limits::max(); + int m_nPriority = 0; + int m_nAimedHitbox = -1; + + TickRecord m_Tick = {}; + bool m_bBacktrack = false; +}; + +class CAimbotGlobal +{ +public: + void SortTargets(std::vector*, const ESortMethod& method); + void SortPriority(std::vector*); + bool ShouldIgnore(CTFPlayer* pTarget, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bMedigun = false); + int GetPriority(int targetIdx); + bool ValidBomb(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pBomb); +}; + +ADD_FEATURE(CAimbotGlobal, AimbotGlobal) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp b/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp new file mode 100644 index 0000000..f97fa21 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp @@ -0,0 +1,786 @@ +#include "AimbotHitscan.h" + +#include "../../Backtrack/Backtrack.h" +#include "../../Resolver/Resolver.h" +#include "../../Visuals/Visuals.h" + +bool CAimbotHitscan::PlayerBoneInFOV(CTFPlayer* pTarget, Vec3 vLocalPos, Vec3 vLocalAngles, float& flFOVTo, Vec3& vPos, Vec3& vAngleTo) // this won't prevent shooting bones outside of fov +{ + bool bReturn = false; + + float flMinFOV = 180.f; + for (int nHitbox = 0; nHitbox < pTarget->GetNumOfHitboxes(); nHitbox++) + { + if (!IsHitboxValid(nHitbox)) + continue; + + Vec3 vCurPos = pTarget->GetHitboxPos(nHitbox); + Vec3 vCurAngleTo = Math::CalcAngle(vLocalPos, vCurPos); + float flCurFOVTo = Math::CalcFov(vLocalAngles, vCurAngleTo); + + if (flCurFOVTo < flMinFOV && flCurFOVTo < Vars::Aimbot::General::AimFOV.Value) + { + bReturn = true; + vPos = vCurPos; + vAngleTo = vCurAngleTo; + flFOVTo = flMinFOV = flCurFOVTo; + } + } + + return bReturn; +} + +std::vector CAimbotHitscan::GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + std::vector validTargets; + const auto sortMethod = static_cast(Vars::Aimbot::General::TargetSelection.Value); + + const Vec3 vLocalPos = pLocal->GetShootPos(); + const Vec3 vLocalAngles = I::EngineClient->GetViewAngles(); + + const bool bIsMedigun = pWeapon->m_iWeaponID() == TF_WEAPON_MEDIGUN; + + if (Vars::Aimbot::General::Target.Value & PLAYER) + { + const bool bPissRifle = G::WeaponDefIndex == Sniper_m_TheSydneySleeper; + + EGroupType groupType = EGroupType::PLAYERS_ENEMIES; + if (bIsMedigun) + groupType = EGroupType::PLAYERS_TEAMMATES; + else if (bPissRifle) + groupType = EGroupType::PLAYERS_ALL; + + for (auto pEntity : H::Entities.GetGroup(groupType)) + { + auto pPlayer = pEntity->As(); + if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost()) + continue; + + // Can we extinguish a teammate using the piss rifle? + if (bPissRifle && (pPlayer->m_iTeamNum() == pLocal->m_iTeamNum())) + { + if (!(Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 6)) || !pPlayer->IsOnFire()) + continue; + } + + if (F::AimbotGlobal.ShouldIgnore(pPlayer, pLocal, pWeapon, bIsMedigun)) + continue; + + float flFOVTo; Vec3 vPos, vAngleTo; + if (!PlayerBoneInFOV(pPlayer, vLocalPos, vLocalAngles, flFOVTo, vPos, vAngleTo)) + continue; + + const float flDistTo = vLocalPos.DistTo(vPos); + const int priority = F::AimbotGlobal.GetPriority(pPlayer->entindex()); + validTargets.push_back({ pPlayer, ETargetType::PLAYER, vPos, vAngleTo, flFOVTo, flDistTo, priority }); + } + } + + if (bIsMedigun) // do not attempt to heal buildings or other + return validTargets; + + if (Vars::Aimbot::General::Target.Value) + { + for (auto pEntity : H::Entities.GetGroup(EGroupType::BUILDINGS_ENEMIES)) + { + auto pBuilding = pEntity->As(); + + bool isSentry = pBuilding->IsSentrygun(), isDispenser = pBuilding->IsDispenser(), isTeleporter = pBuilding->IsTeleporter(); + + if (!(Vars::Aimbot::General::Target.Value & SENTRY) && isSentry) + continue; + if (!(Vars::Aimbot::General::Target.Value & DISPENSER) && isDispenser) + continue; + if (!(Vars::Aimbot::General::Target.Value & TELEPORTER) && isTeleporter) + continue; + + Vec3 vPos = pBuilding->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + const float flDistTo = vLocalPos.DistTo(vPos); + validTargets.push_back({ pBuilding, isSentry ? ETargetType::SENTRY : (isDispenser ? ETargetType::DISPENSER : ETargetType::TELEPORTER), vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + if (Vars::Aimbot::General::Target.Value & STICKY) + { + for (auto pEntity : H::Entities.GetGroup(EGroupType::WORLD_PROJECTILES)) + { + if (pEntity->GetClassID() != ETFClassID::CTFGrenadePipebombProjectile) + continue; + + auto pProjectile = pEntity->As(); + if (pProjectile->m_iType() != TF_GL_MODE_REMOTE_DETONATE || !pProjectile->m_bTouched()) + continue; + + auto pOwner = pProjectile->m_hThrower().Get(); + if (!pOwner || pOwner->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + + Vec3 vPos = pProjectile->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + const float flDistTo = vLocalPos.DistTo(vPos); + validTargets.push_back({ pProjectile, ETargetType::STICKY, vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + if (Vars::Aimbot::General::Target.Value & NPC) + { + for (auto pNPC : H::Entities.GetGroup(EGroupType::WORLD_NPC)) + { + Vec3 vPos = pNPC->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + const float flDistTo = vLocalPos.DistTo(vPos); + validTargets.push_back({ pNPC, ETargetType::NPC, vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + if (Vars::Aimbot::General::Target.Value & BOMB) + { + for (auto pBomb : H::Entities.GetGroup(EGroupType::WORLD_BOMBS)) + { + Vec3 vPos = pBomb->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + const float flDistTo = sortMethod == ESortMethod::DISTANCE ? vLocalPos.DistTo(vPos) : 0.0f; + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + if (!F::AimbotGlobal.ValidBomb(pLocal, pWeapon, pBomb)) + continue; + + validTargets.push_back({ pBomb, ETargetType::BOMBS, vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + return validTargets; +} + +std::vector CAimbotHitscan::SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + auto validTargets = GetTargets(pLocal, pWeapon); + + const auto& sortMethod = static_cast(Vars::Aimbot::General::TargetSelection.Value); + F::AimbotGlobal.SortTargets(&validTargets, sortMethod); + + std::vector sortedTargets = {}; + int i = 0; for (auto& target : validTargets) + { + i++; if (i > Vars::Aimbot::General::MaxTargets.Value) break; + + sortedTargets.push_back(target); + } + + F::AimbotGlobal.SortPriority(&sortedTargets); + + return sortedTargets; +} + + + +bool CAimbotHitscan::IsHitboxValid(int nHitbox) // check that this & all other uses are right +{ + const int iHitboxes = Vars::Aimbot::Hitscan::Hitboxes.Value; + switch (nHitbox) + { + case -1: return true; + case HITBOX_HEAD: return iHitboxes & (1 << 0); + case HITBOX_NECK: return iHitboxes & (1 << 1); + case HITBOX_LOWER_NECK: + case HITBOX_PELVIS: + case HITBOX_BODY: + case HITBOX_THORAX: return iHitboxes & (1 << 2); + case HITBOX_CHEST: + case HITBOX_UPPER_CHEST: + case HITBOX_RIGHT_THIGH: + case HITBOX_LEFT_THIGH: + case HITBOX_RIGHT_CALF: + case HITBOX_LEFT_CALF: return iHitboxes & (1 << 3); + case HITBOX_RIGHT_FOOT: + case HITBOX_LEFT_FOOT: + case HITBOX_RIGHT_HAND: + case HITBOX_LEFT_HAND: + case HITBOX_RIGHT_UPPER_ARM: + case HITBOX_RIGHT_FOREARM: + case HITBOX_LEFT_UPPER_ARM: + case HITBOX_LEFT_FOREARM: return iHitboxes & (1 << 4); + } + + return false; +} + +int CAimbotHitscan::GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pTarget) +{ + bool bHeadshot = false; + { + const int nClassNum = pLocal->m_iClass(); + + if (nClassNum == TF_CLASS_SNIPER) + { + if (G::WeaponDefIndex != Sniper_m_TheClassic && pLocal->IsScoped() || + G::WeaponDefIndex == Sniper_m_TheClassic && pWeapon->As()->m_flChargedDamage() > 149.9f) + bHeadshot = true; + } + if (nClassNum == TF_CLASS_SPY) + { + if ((G::WeaponDefIndex == Spy_m_TheAmbassador || G::WeaponDefIndex == Spy_m_FestiveAmbassador) && pWeapon->AmbassadorCanHeadshot()) + bHeadshot = true; + } + + if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 5) && bHeadshot && pTarget->IsPlayer()) + { + { + float flBodyMult = 1.f; + switch (G::WeaponDefIndex) + { + case Sniper_m_TheClassic: flBodyMult = 0.9f; break; + case Sniper_m_TheHitmansHeatmaker: flBodyMult = 0.8f; break; + case Sniper_m_TheMachina: + case Sniper_m_ShootingStar: if (pWeapon->As()->m_flChargedDamage() > 149.9f) flBodyMult = 1.15f; + } + if (pWeapon->As()->m_flChargedDamage() * flBodyMult >= pTarget->As()->m_iHealth()) + bHeadshot = false; + } + + if (G::WeaponDefIndex == Spy_m_TheAmbassador || G::WeaponDefIndex == Spy_m_FestiveAmbassador) + { + const float flDistTo = pTarget->m_vecOrigin().DistTo(pLocal->m_vecOrigin()); + const int nAmbassadorBodyshotDamage = Math::RemapValClamped(flDistTo, 90, 900, 51, 18); + + if (pTarget->As()->m_iHealth() < (nAmbassadorBodyshotDamage + 2)) // whatever + bHeadshot = false; + } + } + } + + switch (nHitbox) + { + case -1: return 2; + case HITBOX_HEAD: return bHeadshot ? 0 : 2; + case HITBOX_NECK: return 2; + case HITBOX_LOWER_NECK: + case HITBOX_PELVIS: + case HITBOX_BODY: + case HITBOX_THORAX: return bHeadshot ? 1 : 0; + case HITBOX_CHEST: + case HITBOX_UPPER_CHEST: + case HITBOX_RIGHT_THIGH: + case HITBOX_LEFT_THIGH: + case HITBOX_RIGHT_CALF: + case HITBOX_LEFT_CALF: return 2; + case HITBOX_RIGHT_FOOT: + case HITBOX_LEFT_FOOT: + case HITBOX_RIGHT_HAND: + case HITBOX_LEFT_HAND: + case HITBOX_RIGHT_UPPER_ARM: + case HITBOX_RIGHT_FOREARM: + case HITBOX_LEFT_UPPER_ARM: + case HITBOX_LEFT_FOREARM: return 2; + } + + return 2; +}; + +float CAimbotHitscan::GetMaxRange(CTFWeaponBase* pWeapon) +{ + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_MEDIGUN: return 450.f; + case TF_WEAPON_MECHANICAL_ARM: return 256.f; + } + + auto tfWeaponInfo = pWeapon->GetWeaponInfo(); + return tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_flRange : 8192.f; +} + +int CAimbotHitscan::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (Vars::Aimbot::General::Ignore.Value & UNSIMULATED && G::ChokeMap[target.m_pEntity->entindex()] > Vars::Aimbot::General::TickTolerance.Value) + return false; + + Vec3 vEyePos = pLocal->GetShootPos(); + const float flMaxRange = powf(GetMaxRange(pWeapon), 2.f); + + auto pModel = target.m_pEntity->GetModel(); + if (!pModel) return false; + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) return false; + auto pSet = pHDR->pHitboxSet(target.m_pEntity->As()->m_nHitboxSet()); + if (!pSet) return false; + + std::deque vRecords; + { + auto pRecords = F::Backtrack.GetRecords(target.m_pEntity); + if (pRecords && target.m_TargetType == ETargetType::PLAYER) + { + vRecords = F::Backtrack.GetValidRecords(pRecords, pLocal); + if (!Vars::Backtrack::Enabled.Value && !vRecords.empty()) + vRecords = { vRecords.front() }; + } + else + { + matrix3x4 bones[128]; + if (!target.m_pEntity->SetupBones(bones, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime())) + return false; + + vRecords.push_front({ + target.m_pEntity->m_flSimulationTime(), + I::GlobalVars->curtime, + I::GlobalVars->tickcount, + false, + *reinterpret_cast(&bones), + target.m_pEntity->m_vecOrigin() + }); + } + } + + auto RayToOBB = [](const Vec3& origin, const Vec3& direction, const Vec3& position, const Vec3& min, const Vec3& max, const matrix3x4 orientation) -> bool + { + if (Vars::Aimbot::General::AimType.Value != 2) + return true; + + return Math::RayToOBB(origin, direction, position, min, max, orientation); + }; + + int iReturn = false; + for (auto& pTick : vRecords) + { + if (target.m_TargetType == ETargetType::PLAYER || target.m_TargetType == ETargetType::SENTRY) + { + auto boneMatrix = (matrix3x4*)(&pTick.BoneMatrix.BoneMatrix); + if (!boneMatrix) + continue; + + std::vector> hitboxes; + { + if (target.m_TargetType != ETargetType::SENTRY) + { + std::vector> primary, secondary, tertiary; // dumb + for (int nHitbox = 0; nHitbox < target.m_pEntity->As()->GetNumOfHitboxes(); nHitbox++) + { + if (!IsHitboxValid(nHitbox)) + continue; + + auto pBox = pSet->pHitbox(nHitbox); + if (!pBox) continue; + + switch (GetHitboxPriority(nHitbox, pLocal, pWeapon, target.m_pEntity)) + { + case 0: primary.push_back({ pBox, nHitbox }); break; + case 1: secondary.push_back({ pBox, nHitbox }); break; + case 2: tertiary.push_back({ pBox, nHitbox }); break; + } + } + for (auto& pair : primary) hitboxes.push_back(pair); + for (auto& pair : secondary) hitboxes.push_back(pair); + for (auto& pair : tertiary) hitboxes.push_back(pair); + } + else + { + for (int nHitbox = 0; nHitbox < target.m_pEntity->As()->GetNumOfHitboxes(); nHitbox++) + { + const mstudiobbox_t* pBox = pSet->pHitbox(nHitbox); + if (!pBox) continue; + + hitboxes.push_back({ pBox, nHitbox }); + } + std::sort(hitboxes.begin(), hitboxes.end(), [&](const auto& a, const auto& b) -> bool + { + Vec3 aCenter = {}, bCenter = {}, vCenter = target.m_pEntity->GetCenter(); + Math::VectorTransform({}, boneMatrix[a.first->bone], aCenter); + Math::VectorTransform({}, boneMatrix[b.first->bone], bCenter); + + return vCenter.DistTo(aCenter) < vCenter.DistTo(bCenter); + }); + } + } + + for (auto& pair : hitboxes) + { + const float flScale = Vars::Aimbot::Hitscan::PointScale.Value / 100; + const Vec3 vMins = pair.first->bbmin, vMinsS = vMins * flScale; + const Vec3 vMaxs = pair.first->bbmax, vMaxsS = vMaxs * flScale; + + std::vector vecPoints = { Vec3() }; + if (flScale > 0.f) + { + vecPoints = { + Vec3(), + Vec3(vMinsS.x, vMinsS.y, vMaxsS.z), + Vec3(vMaxsS.x, vMinsS.y, vMaxsS.z), + Vec3(vMinsS.x, vMaxsS.y, vMaxsS.z), + Vec3(vMaxsS.x, vMaxsS.y, vMaxsS.z), + Vec3(vMinsS.x, vMinsS.y, vMinsS.z), + Vec3(vMaxsS.x, vMinsS.y, vMinsS.z), + Vec3(vMinsS.x, vMaxsS.y, vMinsS.z), + Vec3(vMaxsS.x, vMaxsS.y, vMinsS.z) + }; + } + + for (const auto& point : vecPoints) + { + Vec3 vCenter = {}, vTransformed = {}; + Math::VectorTransform({}, boneMatrix[pair.first->bone], vCenter); + Math::VectorTransform(point, boneMatrix[pair.first->bone], vTransformed); + + if (vEyePos.DistToSqr(vTransformed) > flMaxRange) + continue; + + auto vAngles = Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(pLocal->GetShootPos(), vTransformed)); + Vec3 vForward = {}; + Math::AngleVectors(vAngles, &vForward); + + if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed)) + { + target.m_vAngleTo = vAngles; + if (RayToOBB(vEyePos, vForward, vCenter, vMins, vMaxs, boneMatrix[pair.first->bone])) // for the time being, no vischecks against other hitboxes + { + bool bWillHit = true; + if (target.m_TargetType == ETargetType::SENTRY) // point of hit for sentries needs to be within bbox + { + const matrix3x4& transform = target.m_pEntity->RenderableToWorldTransform(); + const Vec3 vMin = target.m_pEntity->m_vecMins(), vMax = target.m_pEntity->m_vecMaxs(); + bWillHit = RayToOBB(vEyePos, vForward, target.m_pEntity->m_vecOrigin(), vMin, vMax, transform); + } + if (bWillHit) + { + target.m_Tick = pTick; + target.m_vPos = vTransformed; + if (target.m_TargetType == ETargetType::PLAYER) + { + //if (Vars::Backtrack::Enabled.Value) + target.m_bBacktrack = target.m_TargetType == ETargetType::PLAYER; + target.m_nAimedHitbox = pair.second; + } + return true; + } + } + iReturn = 2; + } + } + } + } + else + { + const float flScale = Vars::Aimbot::Hitscan::PointScale.Value / 100; + const Vec3 vMins = target.m_pEntity->m_vecMins(), vMinsS = vMins * flScale; + const Vec3 vMaxs = target.m_pEntity->m_vecMaxs(), vMaxsS = vMaxs * flScale; + + std::vector vecPoints = { Vec3() }; + if (flScale > 0.f) + { + vecPoints = { + Vec3(), + Vec3(vMinsS.x, vMinsS.y, vMaxsS.z), + Vec3(vMaxsS.x, vMinsS.y, vMaxsS.z), + Vec3(vMinsS.x, vMaxsS.y, vMaxsS.z), + Vec3(vMaxsS.x, vMaxsS.y, vMaxsS.z), + Vec3(vMinsS.x, vMinsS.y, vMinsS.z), + Vec3(vMaxsS.x, vMinsS.y, vMinsS.z), + Vec3(vMinsS.x, vMaxsS.y, vMinsS.z), + Vec3(vMaxsS.x, vMaxsS.y, vMinsS.z) + }; + } + + const matrix3x4& transform = target.m_pEntity->RenderableToWorldTransform(); + for (const auto& point : vecPoints) + { + Vec3 vTransformed = target.m_pEntity->GetCenter() + point; + + if (vEyePos.DistToSqr(vTransformed) > flMaxRange) + continue; + + auto vAngles = Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(pLocal->GetShootPos(), vTransformed)); + Vec3 vForward = {}; + Math::AngleVectors(vAngles, &vForward); + + if (SDK::VisPos(pLocal, target.m_pEntity, vEyePos, vTransformed)) + { + target.m_vAngleTo = vAngles; + if (RayToOBB(vEyePos, vForward, target.m_pEntity->m_vecOrigin(), vMins, vMaxs, transform)) // for the time being, no vischecks against other hitboxes + { + target.m_Tick = pTick; + target.m_vPos = vTransformed; + return true; + } + iReturn = 2; + } + } + } + } + + return iReturn; +} + + + +/* Returns whether AutoShoot should fire */ +bool CAimbotHitscan::ShouldFire(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd, const Target_t& target) +{ + if (!Vars::Aimbot::General::AutoShoot.Value) return false; + + switch (pLocal->m_iClass()) + { + case TF_CLASS_SNIPER: + { + const bool bIsScoped = pLocal->IsScoped(); + + if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 1)) + { + if (G::WeaponDefIndex != Sniper_m_TheClassic + && G::WeaponDefIndex != Sniper_m_TheSydneySleeper + && !G::CanHeadshot && bIsScoped) + { + return false; + } + } + + if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 2) && (bIsScoped || G::WeaponDefIndex == Sniper_m_TheClassic)) + { + auto pPlayer = target.m_pEntity->As(); + auto pSniperRifle = pWeapon->As(); + const int nHealth = pPlayer->m_iHealth(); + const bool bIsCritBoosted = pLocal->IsCritBoosted(); + + if (target.m_nAimedHitbox == HITBOX_HEAD && G::WeaponDefIndex != Sniper_m_TheSydneySleeper && (G::WeaponDefIndex != Sniper_m_TheClassic || G::WeaponDefIndex == Sniper_m_TheClassic && pSniperRifle->m_flChargedDamage() > 149.9f)) + { + if (nHealth > 150) + { + const float flDamage = Math::RemapValClamped(pSniperRifle->m_flChargedDamage(), 0.0f, 150.0f, 0.0f, 450.0f); + const int nDamage = static_cast(flDamage); + + if (nDamage < nHealth && nDamage != 450) + return false; + } + else if (!bIsCritBoosted && !G::CanHeadshot) + return false; + } + else + { + if (nHealth > (bIsCritBoosted ? 150 : 50)) + { + float flCritMult = pPlayer->IsInJarate() ? 1.36f : 1.0f; + + if (bIsCritBoosted) + flCritMult = 3.0f; + + float flBodyMult = 1.f; + switch (G::WeaponDefIndex) + { + case Sniper_m_TheClassic: flBodyMult = 0.9f; break; + case Sniper_m_TheHitmansHeatmaker: flBodyMult = 0.8f; break; + case Sniper_m_TheMachina: + case Sniper_m_ShootingStar: if (pSniperRifle->m_flChargedDamage() > 149.9f) flBodyMult = 1.15f; + } + + const float flMax = 150.0f * flCritMult * flBodyMult; + const int nDamage = static_cast(pSniperRifle->m_flChargedDamage() * flCritMult * flBodyMult); + + if (nDamage < pPlayer->m_iHealth() && nDamage != static_cast(flMax)) + return false; + } + } + } + + break; + } + case TF_CLASS_SPY: + if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 1) && !pWeapon->AmbassadorCanHeadshot()) + return false; + break; + } + + return true; +} + +// assume angle calculated outside with other overload +void CAimbotHitscan::Aim(CUserCmd* pCmd, Vec3& vAngle) +{ + if (Vars::Aimbot::General::AimType.Value != 3) + { + pCmd->viewangles = vAngle; + I::EngineClient->SetViewAngles(pCmd->viewangles); // remove these if uncommenting l124 of createmove + } + else if (G::IsAttacking) + { + SDK::FixMovement(pCmd, vAngle); + pCmd->viewangles = vAngle; + G::SilentAngles = true; + } +} + +Vec3 CAimbotHitscan::Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod) +{ + Vec3 vReturn = {}; + + vToAngle -= G::PunchAngles; + Math::ClampAngles(vToAngle); + + switch (iMethod) + { + case 1: // Plain + case 3: // Silent + vReturn = vToAngle; + break; + case 2: //Smooth + { + auto shortDist = [](const float flAngleA, const float flAngleB) + { + const float flDelta = fmodf((flAngleA - flAngleB), 360.f); + return fmodf(2 * flDelta, 360.f) - flDelta; + }; + const float t = 1.f - Vars::Aimbot::General::Smoothing.Value / 100.f; + vReturn.x = vCurAngle.x - shortDist(vCurAngle.x, vToAngle.x) * t; + vReturn.y = vCurAngle.y - shortDist(vCurAngle.y, vToAngle.y) * t; + break; + } + } + + return vReturn; +} + +void CAimbotHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + static int iStaticAimType = Vars::Aimbot::General::AimType.Value; + const int iRealAimType = Vars::Aimbot::General::AimType.Value; + const int iLastAimType = iStaticAimType; + iStaticAimType = iRealAimType; + + const int nWeaponID = pWeapon->m_iWeaponID(); + + const bool bAutomatic = pWeapon->IsStreamingWeapon(), bKeepFiring = bAutomatic && G::LastUserCmd->buttons & IN_ATTACK; + if (bKeepFiring && !G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value) + pCmd->buttons |= IN_ATTACK; + + switch (nWeaponID) + { + case TF_WEAPON_SNIPERRIFLE_CLASSIC: + if (!iRealAimType && iLastAimType && G::IsAttacking) + Vars::Aimbot::General::AimType.Value = iLastAimType; + } + + if (!Vars::Aimbot::General::AimType.Value || !G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value == 3 && (nWeaponID == TF_WEAPON_MINIGUN ? pWeapon->As()->m_iWeaponState() == AC_STATE_FIRING || pWeapon->As()->m_iWeaponState() == AC_STATE_SPINNING : true)) + return; + + switch (nWeaponID) + { + case TF_WEAPON_MINIGUN: + pCmd->buttons |= IN_ATTACK2; + if (pWeapon->As()->m_iWeaponState() != AC_STATE_FIRING && pWeapon->As()->m_iWeaponState() != AC_STATE_SPINNING) + return; + break; + case TF_WEAPON_SNIPERRIFLE: + case TF_WEAPON_SNIPERRIFLE_DECAP: + { + const bool bScoped = pLocal->IsScoped(); + + if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 4) && !bScoped) + { + pCmd->buttons |= IN_ATTACK2; + return; + } + + if ((Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 3) || G::WeaponDefIndex == Sniper_m_TheMachina || G::WeaponDefIndex == Sniper_m_ShootingStar) && !bScoped) + return; + + break; + } + case TF_WEAPON_SNIPERRIFLE_CLASSIC: + if (iRealAimType) + pCmd->buttons |= IN_ATTACK; + } + + auto targets = SortTargets(pLocal, pWeapon); + if (targets.empty()) + return; + + for (auto& target : targets) + { + const auto iResult = CanHit(target, pLocal, pWeapon); + if (!iResult) continue; + if (iResult == 2) + { + Aim(pCmd, target.m_vAngleTo); + break; + } + + G::Target = { target.m_pEntity->entindex(), I::GlobalVars->tickcount }; + if (Vars::Aimbot::General::AimType.Value == 3) + G::AimPosition = target.m_vPos; + + bool bShouldFire = ShouldFire(pLocal, pWeapon, pCmd, target); + + if (bShouldFire) + { + pCmd->buttons |= IN_ATTACK; + + if (nWeaponID == TF_WEAPON_SNIPERRIFLE_CLASSIC && pWeapon->As()->m_flChargedDamage()) + pCmd->buttons &= ~IN_ATTACK; + + if (G::WeaponDefIndex == Engi_s_TheWrangler || G::WeaponDefIndex == Engi_s_FestiveWrangler) + pCmd->buttons |= IN_ATTACK2; + + if (Vars::Aimbot::Hitscan::Modifiers.Value & (1 << 0) && nWeaponID == TF_WEAPON_MINIGUN && !pLocal->IsPrecisionRune()) + { + if (pLocal->GetShootPos().DistTo(target.m_vPos) > Vars::Aimbot::Hitscan::TapFireDist.Value && pWeapon->GetWeaponSpread() != 0.f) + { + const float flTimeSinceLastShot = (pLocal->m_nTickBase() * TICK_INTERVAL) - pWeapon->m_flLastFireTime(); + + auto tfWeaponInfo = pWeapon->GetWeaponInfo(); + if (tfWeaponInfo && tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot > 1) + { + if (flTimeSinceLastShot <= 0.25f) + pCmd->buttons &= ~IN_ATTACK; + } + else if (flTimeSinceLastShot <= 1.25f) + pCmd->buttons &= ~IN_ATTACK; + } + } + } + + G::IsAttacking = SDK::IsAttacking(pLocal, pWeapon, pCmd); + + if (G::IsAttacking) + { + if (target.m_pEntity->IsPlayer()) + F::Resolver.Aimbot(target.m_pEntity->As(), target.m_nAimedHitbox == 0); + + if (target.m_bBacktrack) + pCmd->tick_count = TIME_TO_TICKS(target.m_Tick.flSimTime) + TIME_TO_TICKS(F::Backtrack.flFakeInterp); + + if (!pWeapon->IsInReload()) + { + if (Vars::Visuals::Bullet::BulletTracer.Value) + { + G::BulletsStorage.clear(); + G::BulletsStorage.push_back({ {pLocal->GetShootPos(), target.m_vPos}, I::GlobalVars->curtime + 5.f, Vars::Colors::BulletTracer.Value, true }); + } + if (Vars::Visuals::Hitbox::ShowHitboxes.Value) + { + G::BoxesStorage.clear(); + auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)(&target.m_Tick.BoneMatrix.BoneMatrix), target.m_pEntity->As()); + G::BoxesStorage.insert(G::BoxesStorage.end(), vBoxes.begin(), vBoxes.end()); + } + } + } + + Aim(pCmd, target.m_vAngleTo); + break; + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.h b/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.h new file mode 100644 index 0000000..c08945b --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.h @@ -0,0 +1,25 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#include "../AimbotGlobal/AimbotGlobal.h" + +class CAimbotHitscan +{ + bool PlayerBoneInFOV(CTFPlayer* pTarget, Vec3 vLocalPos, Vec3 vLocalAngles, float& flFOVTo, Vec3& vPos, Vec3& vAngleTo); + std::vector GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + std::vector SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + + bool IsHitboxValid(int nHitbox); + int GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CBaseEntity* pTarget); + float GetMaxRange(CTFWeaponBase* pWeapon); + int CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + + void Aim(CUserCmd* pCmd, Vec3& vAngle); + Vec3 Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod = Vars::Aimbot::General::AimType.Value); + bool ShouldFire(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd, const Target_t& target); + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CAimbotHitscan, AimbotHitscan) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp new file mode 100644 index 0000000..8aedcbb --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp @@ -0,0 +1,662 @@ +#include "AimbotMelee.h" + +#include "../../Simulation/MovementSimulation/MovementSimulation.h" +#include "../../TickHandler/TickHandler.h" +#include "../../Backtrack/Backtrack.h" +#include "../../Visuals/Visuals.h" +#include "../../EnginePrediction/EnginePrediction.h" + +std::vector CAimbotMelee::GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + std::vector validTargets; + + const Vec3 vLocalPos = pLocal->GetShootPos(); + const Vec3 vLocalAngles = I::EngineClient->GetViewAngles(); + if (lockedTarget.m_pEntity) + { + auto pPlayer = lockedTarget.m_pEntity->As(); + if (!pPlayer->IsAlive() || pPlayer->IsAGhost()) + lockedTarget.m_pEntity = nullptr; + else + { + Vec3 vPos = pPlayer->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + + const float flDistTo = vLocalPos.DistTo(vPos); + validTargets.push_back({ lockedTarget.m_pEntity, lockedTarget.m_TargetType, vPos, vAngleTo, lockedTarget.m_flFOVTo, flDistTo, lockedTarget.m_nPriority }); + + return validTargets; + } + } + + if (Vars::Aimbot::General::Target.Value & PLAYER) + { + const bool bDisciplinary = Vars::Aimbot::Melee::WhipTeam.Value && pWeapon->m_iItemDefinitionIndex() == Soldier_t_TheDisciplinaryAction; + for (auto pEntity : H::Entities.GetGroup(bDisciplinary ? EGroupType::PLAYERS_ALL : EGroupType::PLAYERS_ENEMIES)) + { + auto pPlayer = pEntity->As(); + if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost()) + continue; + + if (F::AimbotGlobal.ShouldIgnore(pPlayer, pLocal, pWeapon)) + continue; + + Vec3 vPos = pPlayer->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + const float flDistTo = vLocalPos.DistTo(vPos); + const int priority = F::AimbotGlobal.GetPriority(pPlayer->entindex()); + validTargets.push_back({ pPlayer, ETargetType::PLAYER, vPos, vAngleTo, flFOVTo, flDistTo, priority }); + } + } + + if (Vars::Aimbot::General::Target.Value) + { + const bool hasWrench = (pWeapon->m_iWeaponID() == TF_WEAPON_WRENCH); + const bool canDestroySapper = (G::WeaponDefIndex == Pyro_t_Homewrecker || + G::WeaponDefIndex == Pyro_t_TheMaul || + G::WeaponDefIndex == Pyro_t_NeonAnnihilator || + G::WeaponDefIndex == Pyro_t_NeonAnnihilatorG); + + for (auto pEntity : H::Entities.GetGroup(hasWrench || canDestroySapper ? EGroupType::BUILDINGS_ALL : EGroupType::BUILDINGS_ENEMIES)) + { + auto pBuilding = pEntity->As(); + + bool isSentry = pBuilding->IsSentrygun(), isDispenser = pBuilding->IsDispenser(), isTeleporter = pBuilding->IsTeleporter(); + + if (!(Vars::Aimbot::General::Target.Value & SENTRY) && isSentry) + continue; + if (!(Vars::Aimbot::General::Target.Value & DISPENSER) && isDispenser) + continue; + if (!(Vars::Aimbot::General::Target.Value & TELEPORTER) && isTeleporter) + continue; + + if (pBuilding->m_iTeamNum() == pLocal->m_iTeamNum()) + { + if (hasWrench) + { + if (!AimFriendlyBuilding(pBuilding)) + continue; + } + + if (canDestroySapper) + { + if (!pBuilding->m_bHasSapper()) + continue; + } + } + + Vec3 vPos = pBuilding->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + const float flDistTo = vLocalPos.DistTo(vPos); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + validTargets.push_back({ pBuilding, isSentry ? ETargetType::SENTRY : (isDispenser ? ETargetType::DISPENSER : ETargetType::TELEPORTER), vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + if (Vars::Aimbot::General::Target.Value & NPC) + { + for (auto pNPC : H::Entities.GetGroup(EGroupType::WORLD_NPC)) + { + Vec3 vPos = pNPC->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + const float flDistTo = vLocalPos.DistTo(vPos); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + validTargets.push_back({ pNPC, ETargetType::NPC, vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + return validTargets; +} + +bool CAimbotMelee::AimFriendlyBuilding(CBaseObject* pBuilding) +{ + if (!pBuilding->m_bMiniBuilding() && pBuilding->m_iUpgradeLevel() != 3 || pBuilding->m_bHasSapper() || pBuilding->m_iHealth() < pBuilding->m_iMaxHealth()) + return true; + + if (pBuilding->IsSentrygun()) + { + auto pSentry = pBuilding->As(); + int iShells, iMaxShells, iRockets, iMaxRockets; + + pSentry->GetAmmoCount(iShells, iMaxShells, iRockets, iMaxRockets); + + if (iShells < iMaxShells || iRockets < iMaxRockets) + return true; + } + + return false; +} + +std::vector CAimbotMelee::SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (lockedTarget.m_pEntity) + return { lockedTarget }; + + auto validTargets = GetTargets(pLocal, pWeapon); + + const auto& sortMethod = ESortMethod::DISTANCE; //static_cast(Vars::Aimbot::Melee::SortMethod.Value); + F::AimbotGlobal.SortTargets(&validTargets, sortMethod); + + std::vector sortedTargets = {}; + int i = 0; for (auto& target : validTargets) + { + i++; if (i > Vars::Aimbot::General::MaxTargets.Value) break; + + sortedTargets.push_back(target); + } + + F::AimbotGlobal.SortPriority(&sortedTargets); + + return sortedTargets; +} + + + +int CAimbotMelee::GetSwingTime(CTFWeaponBase* pWeapon) +{ + if (pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE) + return 0; + return Vars::Aimbot::Melee::SwingTicks.Value; +} + +void CAimbotMelee::SimulatePlayers(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::vector targets, + Vec3& vEyePos, std::unordered_map>& pRecordMap, + std::unordered_map>>& simLines) +{ + if (lockedTarget.m_pEntity) + return; + + // swing prediction / auto warp + const int iSwingTicks = GetSwingTime(pWeapon); + int iMax = (iDoubletapTicks && Vars::CL_Move::Doubletap::AntiWarp.Value && pLocal->OnSolid()) + ? std::max(iSwingTicks - Vars::CL_Move::Doubletap::TickLimit.Value - 1, 0) + : std::max(iSwingTicks, iDoubletapTicks); + + if ((Vars::Aimbot::Melee::SwingPrediction.Value || iDoubletapTicks) && pWeapon->m_flSmackTime() < 0.f && iMax) + { + PlayerStorage localStorage; + std::unordered_map targetStorage; + + F::MoveSim.Initialize(pLocal, localStorage, false, iDoubletapTicks); + if (pLocal->OnSolid()) // lol + { + localStorage.m_MoveData.m_flForwardMove = G::CurrentUserCmd->forwardmove; + localStorage.m_MoveData.m_flSideMove = G::CurrentUserCmd->sidemove; + localStorage.m_MoveData.m_flUpMove = G::CurrentUserCmd->upmove; + + localStorage.m_MoveData.m_vecAngles.y = localStorage.m_MoveData.m_vecOldAngles.y = localStorage.m_MoveData.m_vecViewAngles.y = G::CurrentUserCmd->viewangles.y; + } + for (auto& target : targets) + F::MoveSim.Initialize(target.m_pEntity, targetStorage[target.m_pEntity], false); + + for (int i = 0; i < iMax; i++) // intended for plocal to collide with targets + { + if (i < iMax) + { + if (pLocal->IsCharging() && iMax - i <= GetSwingTime(pWeapon)) // demo charge fix for swing pred + { + localStorage.m_MoveData.m_flMaxSpeed = pLocal->TeamFortress_CalculateMaxSpeed(true); + localStorage.m_MoveData.m_flClientMaxSpeed = localStorage.m_MoveData.m_flMaxSpeed; + } + F::MoveSim.RunTick(localStorage); + } + if (i < iSwingTicks - iDoubletapTicks) + { + for (auto& target : targets) + { + F::MoveSim.RunTick(targetStorage[target.m_pEntity]); + if (!targetStorage[target.m_pEntity].m_bFailed) + pRecordMap[target.m_pEntity].push_front({ + target.m_pEntity->m_flSimulationTime() + TICKS_TO_TIME(i + 1), + I::GlobalVars->curtime + TICKS_TO_TIME(i + 1), + I::GlobalVars->tickcount + i + 1, + false, + BoneMatrixes{}, + targetStorage[target.m_pEntity].m_MoveData.m_vecAbsOrigin + }); + } + } + } + vEyePos = localStorage.m_MoveData.m_vecAbsOrigin + pLocal->m_vecViewOffset(); + + if (Vars::Visuals::Simulation::SwingLines.Value) + { + const bool bAlwaysDraw = !Vars::Aimbot::General::AutoShoot.Value || Vars::Debug::Info.Value; + if (!bAlwaysDraw) + { + simLines[pLocal] = localStorage.PredictionLines; + for (auto& target : targets) + simLines[target.m_pEntity] = targetStorage[target.m_pEntity].PredictionLines; + } + else + { + G::LinesStorage.clear(); + G::LinesStorage.push_back({ localStorage.PredictionLines, I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value }); + for (auto& target : targets) + G::LinesStorage.push_back({ targetStorage[target.m_pEntity].PredictionLines, I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value }); + } + } + + F::MoveSim.Restore(localStorage); + for (auto& target : targets) + F::MoveSim.Restore(targetStorage[target.m_pEntity]); + } +} + +bool CAimbotMelee::CanBackstab(CBaseEntity* pTarget, CTFPlayer* pLocal, Vec3 eyeAngles) +{ + if (!pLocal || !pTarget) + return false; + + if (Vars::Aimbot::Melee::IgnoreRazorback.Value) + { + CUtlVector itemList; + int iBackstabShield = SDK::AttribHookValue(0, "set_blockbackstab_once", pTarget, &itemList); + if (iBackstabShield && itemList.Count()) + { + CBaseEntity* pEntity = itemList.Element(0); + if (pEntity && pEntity->ShouldDraw()) + return false; + } + } + + Vector vToTarget; + vToTarget = pTarget->GetAbsOrigin() - pLocal->m_vecOrigin(); + vToTarget.z = 0.f; + const float flDist = vToTarget.Length(); + vToTarget.Normalize(); + + Vector vOwnerForward; + Math::AngleVectors(eyeAngles, &vOwnerForward); + vOwnerForward.z = 0.f; + vOwnerForward.Normalize(); + + Vector vTargetForward; + Math::AngleVectors(F::Backtrack.mEyeAngles[pTarget], &vTargetForward); + vTargetForward.z = 0.f; + vTargetForward.Normalize(); + + const float flPosVsTargetViewDot = vToTarget.Dot(vTargetForward); // Behind? + const float flPosVsOwnerViewDot = vToTarget.Dot(vOwnerForward); // Facing? + const float flViewAnglesDot = vTargetForward.Dot(vOwnerForward); // Facestab? + + return flDist > 0.1f && flPosVsTargetViewDot > (0.f + 0.0031f) && flPosVsOwnerViewDot > 0.5f && flViewAnglesDot > (-0.3f + 0.0031f); // 0.00306795676297 ? +} + +int CAimbotMelee::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Vec3 vEyePos, std::deque newRecords) +{ + float flHull = SDK::AttribHookValue(18, "melee_bounds_multiplier", pWeapon); + float flRange = pWeapon->GetSwingRange(pLocal); + if (pLocal->m_flModelScale() > 1.0f) + { + flRange *= pLocal->m_flModelScale(); + flRange *= pLocal->m_flModelScale(); + flRange *= pLocal->m_flModelScale(); + } + flRange = SDK::AttribHookValue(flRange, "melee_range_multiplier", pWeapon); + if (flHull <= 0.f || flRange <= 0.f) + return false; + + static Vec3 vecSwingMins = { -flHull, -flHull, -flHull }; + static Vec3 vecSwingMaxs = { flHull, flHull, flHull }; + + CGameTrace trace; + CTraceFilterHitscan filter; + filter.pSkip = pLocal; + + matrix3x4 bones[128]; + target.m_pEntity->SetupBones(bones, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime()); + + std::deque vRecords; + { + auto pRecords = F::Backtrack.GetRecords(target.m_pEntity); + if (pRecords && target.m_TargetType == ETargetType::PLAYER) + vRecords = *pRecords; + else + { + matrix3x4 bones[128]; + if (!target.m_pEntity->SetupBones(bones, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime())) + return false; + + vRecords.push_front({ + target.m_pEntity->m_flSimulationTime(), + I::GlobalVars->curtime, + I::GlobalVars->tickcount, + false, + *reinterpret_cast(&bones), + target.m_pEntity->m_vecOrigin() + }); + } + } + if (!newRecords.empty()) + { + for (TickRecord& pTick : newRecords) + { + vRecords.pop_back(); vRecords.push_front({ pTick.flSimTime, pTick.flCreateTime, pTick.iTickCount, false, *reinterpret_cast(&bones), pTick.vOrigin }); + } + for (TickRecord& pTick : vRecords) + { + pTick.flSimTime -= TICKS_TO_TIME(newRecords.size()); + pTick.flCreateTime -= TICKS_TO_TIME(newRecords.size()); + pTick.iTickCount -= int(newRecords.size()); + } + } + std::deque validRecords = target.m_TargetType == ETargetType::PLAYER ? F::Backtrack.GetValidRecords(&vRecords, pLocal, true) : vRecords; + if (!Vars::Backtrack::Enabled.Value && !validRecords.empty()) + validRecords = { validRecords.front() }; + + // this might be retarded + const float flTargetPos = (target.m_pEntity->m_vecMaxs().z - target.m_pEntity->m_vecMins().z) * 65.f / 82.f; + const float flLocalPos = (pLocal->m_vecMaxs().z - pLocal->m_vecMins().z) * 65.f / 82.f; + const Vec3 vecDiff = { 0, 0, std::min(flTargetPos, flLocalPos) }; + + for (auto& pTick : validRecords) + { + const Vec3 vRestore = target.m_pEntity->GetAbsOrigin(); + target.m_pEntity->SetAbsOrigin(pTick.vOrigin); + + target.m_vPos = pTick.vOrigin + vecDiff; + target.m_vAngleTo = Aim(G::CurrentUserCmd->viewangles, Math::CalcAngle(vEyePos, target.m_vPos), iAimType); + + Vec3 vecForward = Vec3(); + Math::AngleVectors(target.m_vAngleTo, &vecForward); + Vec3 vecTraceEnd = vEyePos + (vecForward * flRange); + + SDK::Trace(vEyePos, vecTraceEnd, MASK_SHOT | CONTENTS_GRATE, &filter, &trace); + bool bReturn = trace.m_pEnt && trace.m_pEnt == target.m_pEntity; + if (!bReturn) + { + SDK::TraceHull(vEyePos, vecTraceEnd, vecSwingMins, vecSwingMaxs, MASK_SHOT | CONTENTS_GRATE, &filter, &trace); + bReturn = trace.m_pEnt && trace.m_pEnt == target.m_pEntity; + } + + if (bReturn && Vars::Aimbot::Melee::AutoBackstab.Value && pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE) + { + if (target.m_TargetType == ETargetType::PLAYER) + bReturn = CanBackstab(target.m_pEntity, pLocal, target.m_vAngleTo); + else + bReturn = false; + } + + target.m_pEntity->SetAbsOrigin(vRestore); + + if (bReturn) + { + target.m_Tick = pTick; + if (target.m_TargetType == ETargetType::PLAYER) // && Vars::Backtrack::Enabled.Value + target.m_bBacktrack = true; + + return true; + } + else if (iAimType == 2) + { + auto vAngle = Math::CalcAngle(vEyePos, target.m_vPos); + + Vec3 vecForward = Vec3(); + Math::AngleVectors(vAngle, &vecForward); + Vec3 vecTraceEnd = vEyePos + (vecForward * flRange); + + SDK::Trace(vEyePos, vecTraceEnd, MASK_SHOT | CONTENTS_GRATE, &filter, &trace); + if (trace.m_pEnt && trace.m_pEnt == target.m_pEntity) + return 2; + } + } + + return false; +} + + + +bool CAimbotMelee::IsAttacking(const CUserCmd* pCmd, CTFWeaponBase* pWeapon) +{ + if (pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE) + return pCmd->buttons & IN_ATTACK; + + return TIME_TO_TICKS(pWeapon->m_flSmackTime()) == I::GlobalVars->tickcount - 1; // seems to work most (?) of the time +} + +// assume angle calculated outside with other overload +void CAimbotMelee::Aim(CUserCmd* pCmd, Vec3& vAngle) +{ + if (iAimType != 3) + { + pCmd->viewangles = vAngle; + I::EngineClient->SetViewAngles(pCmd->viewangles); + } + else if (G::IsAttacking) + { + SDK::FixMovement(pCmd, vAngle); + pCmd->viewangles = vAngle; + G::PSilentAngles = true; + } +} + +Vec3 CAimbotMelee::Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod) +{ + Vec3 vReturn = {}; + + Math::ClampAngles(vToAngle); + + switch (iMethod) + { + case 1: // Plain + case 3: // Silent + vReturn = vToAngle; + break; + case 2: // Smooth + { + auto shortDist = [](const float flAngleA, const float flAngleB) + { + const float flDelta = fmodf((flAngleA - flAngleB), 360.f); + return fmodf(2 * flDelta, 360.f) - flDelta; + }; + const float t = 1.f - Vars::Aimbot::General::Smoothing.Value / 100.f; + vReturn.x = vCurAngle.x - shortDist(vCurAngle.x, vToAngle.x) * t; + vReturn.y = vCurAngle.y - shortDist(vCurAngle.y, vToAngle.y) * t; + break; + } + } + + return vReturn; +} + +void CAimbotMelee::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (lockedTarget.m_pEntity && pWeapon->m_flSmackTime() < 0.f) + lockedTarget.m_pEntity = nullptr; + + if (!Vars::Aimbot::General::AimType.Value && !lockedTarget.m_pEntity || (!G::CanPrimaryAttack || !Vars::Aimbot::General::AutoShoot.Value) && pWeapon->m_flSmackTime() < 0.f) + return; + else if (!lockedTarget.m_pEntity) + iAimType = Vars::Aimbot::General::AimType.Value; + + if (RunSapper(pLocal, pWeapon, pCmd)) + return; + + auto targets = SortTargets(pLocal, pWeapon); + if (targets.empty()) + return; + + iDoubletapTicks = F::Ticks.GetTicks(pLocal); + const bool bShouldSwing = iDoubletapTicks <= (GetSwingTime(pWeapon) ? 14 : 0) || Vars::CL_Move::Doubletap::AntiWarp.Value && pLocal->OnSolid(); + + Vec3 vEyePos = pLocal->GetShootPos(); + std::unordered_map> pRecordMap; + std::unordered_map>> simLines; + SimulatePlayers(pLocal, pWeapon, targets, vEyePos, pRecordMap, simLines); + + for (auto& target : targets) + { + const auto iResult = CanHit(target, pLocal, pWeapon, vEyePos, pRecordMap[target.m_pEntity]); + if (!iResult) continue; + if (iResult == 2) + { + Aim(pCmd, target.m_vAngleTo); + break; + } + + G::Target = { target.m_pEntity->entindex(), I::GlobalVars->tickcount }; + if (!pRecordMap[target.m_pEntity].empty() && !lockedTarget.m_pEntity) + lockedTarget = target; + + if (iAimType == 3) + G::AimPosition = target.m_vPos; + + if (Vars::Aimbot::General::AutoShoot.Value && pWeapon->m_flSmackTime() < 0.f) + { + if (bShouldSwing) + pCmd->buttons |= IN_ATTACK; + if (iDoubletapTicks) + G::DoubleTap = true; + } + + /* + // game will not manage this while shifting w/o prediction, force its hand + if (!Vars::Misc::Game::NetworkFix.Value && !Vars::Misc::Game::PredictionFix.Value + && G::DoubleTap && pWeapon->m_iWeaponID() != TF_WEAPON_KNIFE) + { + if (pCmd->buttons & IN_ATTACK && pWeapon->m_flSmackTime() < 0.f) + pWeapon->m_flSmackTime() = TICKS_TO_TIME(I::GlobalVars->tickcount + 13); + I::Prediction->Update(I::ClientState->m_nDeltaTick, I::ClientState->m_nDeltaTick > 0, I::ClientState->last_command_ack, I::ClientState->lastoutgoingcommand + I::ClientState->chokedcommands); + } + */ + + const bool bAttacking = IsAttacking(pCmd, pWeapon); + G::IsAttacking = bAttacking || bShouldSwing && G::DoubleTap; // dumb but works + + if (G::IsAttacking) + { + if (target.m_bBacktrack) + pCmd->tick_count = TIME_TO_TICKS(target.m_Tick.flSimTime) + TIME_TO_TICKS(F::Backtrack.flFakeInterp); + // bug: fast old records seem to be progressively more unreliable ? + + if (Vars::Visuals::Bullet::BulletTracer.Value) + { + G::BulletsStorage.clear(); + G::BulletsStorage.push_back({ {vEyePos, target.m_vPos}, I::GlobalVars->curtime + 5.f, Vars::Colors::BulletTracer.Value, true }); + } + if (Vars::Visuals::Simulation::SwingLines.Value) + { + const bool bAlwaysDraw = !Vars::Aimbot::General::AutoShoot.Value || Vars::Debug::Info.Value; + if (!bAlwaysDraw) + { + G::LinesStorage.clear(); + G::LinesStorage.push_back({ simLines[pLocal], I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value }); + G::LinesStorage.push_back({ simLines[target.m_pEntity], I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value }); + } + } + if (Vars::Visuals::Hitbox::ShowHitboxes.Value) + { + G::BoxesStorage.clear(); + auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)(&target.m_Tick.BoneMatrix.BoneMatrix), target.m_pEntity->As()); + G::BoxesStorage.insert(G::BoxesStorage.end(), vBoxes.begin(), vBoxes.end()); + } + } + + Aim(pCmd, target.m_vAngleTo); + G::IsAttacking = bAttacking; + break; + } +} + +int GetAttachment(CBaseObject* pBuilding, int i) +{ + int iAttachment = pBuilding->GetBuildPointAttachmentIndex(i); + if (pBuilding->IsSentrygun() && pBuilding->m_iUpgradeLevel() > 1) // idk why i need this + iAttachment = 3; + return iAttachment; +} +bool CAimbotMelee::FindNearestBuildPoint(CBaseObject* pBuilding, CTFPlayer* pLocal, Vec3& vPoint) +{ + bool bFoundPoint = false; + + static auto tf_obj_max_attach_dist = U::ConVars.FindVar("tf_obj_max_attach_dist"); + float flNearestPoint = tf_obj_max_attach_dist ? tf_obj_max_attach_dist->GetFloat() : 160.f; + for (int i = 0; i < pBuilding->GetNumBuildPoints(); i++) + { + int v = GetAttachment(pBuilding, i); + + Vec3 vOrigin; + if (pBuilding->GetAttachment(v, vOrigin)) // issues using pBuilding->GetBuildPoint i on sentries above level 1 for some reason + { + if (!SDK::VisPos(pLocal, pBuilding, pLocal->GetShootPos(), vOrigin)) + continue; + + float flDist = (vOrigin - pLocal->GetAbsOrigin()).Length(); + if (flDist < flNearestPoint) + { + flNearestPoint = flDist; + vPoint = vOrigin; + bFoundPoint = true; + } + } + } + + return bFoundPoint; +} + +bool CAimbotMelee::RunSapper(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (pWeapon->m_iWeaponID() != TF_WEAPON_BUILDER) + return false; + + std::vector validTargets; + + const Vec3 vLocalPos = pLocal->GetShootPos(); + const Vec3 vLocalAngles = I::EngineClient->GetViewAngles(); + for (auto pEntity : H::Entities.GetGroup(EGroupType::BUILDINGS_ENEMIES)) + { + auto pBuilding = pEntity->As(); + if (pBuilding->m_bHasSapper() || pBuilding->m_iTeamNum() != 2 && pBuilding->m_iTeamNum() != 3) + continue; + + Vec3 vPoint; + if (!FindNearestBuildPoint(pBuilding, pLocal, vPoint)) + continue; + + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPoint); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + const float flDistTo = vLocalPos.DistTo(vPoint); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + validTargets.push_back({ pBuilding, ETargetType::UNKNOWN, vPoint, vAngleTo, flFOVTo, flDistTo }); + } + + F::AimbotGlobal.SortTargets(&validTargets, ESortMethod::DISTANCE); + for (auto& target : validTargets) + { + static int iLastRun = 0; + + if ((Vars::Aimbot::General::AimType.Value == 3 ? iLastRun != I::GlobalVars->tickcount - 1 || G::PSilentAngles && G::ShiftedTicks == G::MaxShift : true) && Vars::Aimbot::General::AutoShoot.Value) + pCmd->buttons |= IN_ATTACK; + + if (pCmd->buttons & IN_ATTACK) + { + target.m_vAngleTo = Aim(pCmd->viewangles, Math::CalcAngle(vLocalPos, target.m_vPos)); + target.m_vAngleTo.x = pCmd->viewangles.x; // we don't need to care about pitch + Aim(pCmd, target.m_vAngleTo); + + iLastRun = I::GlobalVars->tickcount; + } + + break; + } + + return true; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.h b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.h new file mode 100644 index 0000000..9729fa0 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.h @@ -0,0 +1,34 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#include "../AimbotGlobal/AimbotGlobal.h" + +class CAimbotMelee +{ + std::vector GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + bool AimFriendlyBuilding(CBaseObject* pBuilding); + std::vector SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + + int GetSwingTime(CTFWeaponBase* pWeapon); + void SimulatePlayers(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::vector targets, Vec3& vEyePos, + std::unordered_map>& pRecordMap, + std::unordered_map>>& simLines); + bool CanBackstab(CBaseEntity* pTarget, CTFPlayer* pLocal, Vec3 eyeAngles); + int CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Vec3 vEyePos, std::deque newRecords); + + bool IsAttacking(const CUserCmd* pCmd, CTFWeaponBase* pWeapon); + void Aim(CUserCmd* pCmd, Vec3& vAngle); + Vec3 Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod = Vars::Aimbot::General::AimType.Value); + + bool FindNearestBuildPoint(CBaseObject* pBuilding, CTFPlayer* pLocal, Vec3& vPoint); + bool RunSapper(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + + Target_t lockedTarget; + int iAimType = 0; + int iDoubletapTicks = 0; + int iDoubletapMax = 0; +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CAimbotMelee, AimbotMelee) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp new file mode 100644 index 0000000..cda8289 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp @@ -0,0 +1,974 @@ +#include "AimbotProjectile.h" + +#include "../../Simulation/MovementSimulation/MovementSimulation.h" +#include "../../Simulation/ProjectileSimulation/ProjectileSimulation.h" +#include "../../Backtrack/Backtrack.h" +#include "../../Visuals/Visuals.h" + +std::vector CAimbotProjectile::GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + std::vector validTargets; + const auto sortMethod = static_cast(Vars::Aimbot::General::TargetSelection.Value); + + const Vec3 vLocalPos = pLocal->GetShootPos(); + const Vec3 vLocalAngles = I::EngineClient->GetViewAngles(); + + if (Vars::Aimbot::General::Target.Value & PLAYER) + { + EGroupType groupType = EGroupType::PLAYERS_ENEMIES; + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_CROSSBOW: groupType = EGroupType::PLAYERS_ALL; break; + case TF_WEAPON_LUNCHBOX: groupType = EGroupType::PLAYERS_TEAMMATES; break; + } + + for (auto pEntity : H::Entities.GetGroup(groupType)) + { + auto pPlayer = pEntity->As(); + if (pPlayer == pLocal || !pPlayer->IsAlive() || pPlayer->IsAGhost()) + continue; + + // Check if weapon should shoot at friendly players + if ((groupType == EGroupType::PLAYERS_ALL || groupType == EGroupType::PLAYERS_TEAMMATES) && + pPlayer->m_iTeamNum() == pLocal->m_iTeamNum()) + { + if (pPlayer->m_iHealth() >= pPlayer->m_iMaxHealth()) + continue; + } + + if (F::AimbotGlobal.ShouldIgnore(pPlayer, pLocal, pWeapon)) + continue; + + Vec3 vPos = pPlayer->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + const float flDistTo = (sortMethod == ESortMethod::DISTANCE) ? vLocalPos.DistTo(vPos) : 0.0f; + const int priority = F::AimbotGlobal.GetPriority(pPlayer->entindex()); + validTargets.push_back({ pPlayer, ETargetType::PLAYER, vPos, vAngleTo, flFOVTo, flDistTo, priority }); + } + } + + const bool bIsRescueRanger = pWeapon->m_iWeaponID() == TF_WEAPON_SHOTGUN_BUILDING_RESCUE; + for (auto pEntity : H::Entities.GetGroup(bIsRescueRanger ? EGroupType::BUILDINGS_ALL : EGroupType::BUILDINGS_ENEMIES)) + { + auto pBuilding = pEntity->As(); + + bool isSentry = pBuilding->IsSentrygun(), isDispenser = pBuilding->IsDispenser(), isTeleporter = pBuilding->IsTeleporter(); + + if (!(Vars::Aimbot::General::Target.Value & SENTRY) && isSentry) + continue; + if (!(Vars::Aimbot::General::Target.Value & DISPENSER) && isDispenser) + continue; + if (!(Vars::Aimbot::General::Target.Value & TELEPORTER) && isTeleporter) + continue; + + // Check if the Rescue Ranger should shoot at friendly buildings + if (bIsRescueRanger && (pBuilding->m_iTeamNum() == pLocal->m_iTeamNum())) + { + if (pBuilding->m_iHealth() >= pBuilding->m_iMaxHealth()) + continue; + } + + Vec3 vPos = pBuilding->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + const float flDistTo = sortMethod == ESortMethod::DISTANCE ? vLocalPos.DistTo(vPos) : 0.0f; + validTargets.push_back({ pBuilding, isSentry ? ETargetType::SENTRY : (isDispenser ? ETargetType::DISPENSER : ETargetType::TELEPORTER), vPos, vAngleTo, flFOVTo, flDistTo }); + } + + if (Vars::Aimbot::General::Target.Value & NPC) + { + for (auto pNPC : H::Entities.GetGroup(EGroupType::WORLD_NPC)) + { + Vec3 vPos = pNPC->GetCenter(); + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vPos); + + const float flFOVTo = Math::CalcFov(vLocalAngles, vAngleTo); + const float flDistTo = sortMethod == ESortMethod::DISTANCE ? vLocalPos.DistTo(vPos) : 0.0f; + + if (flFOVTo > Vars::Aimbot::General::AimFOV.Value) + continue; + + validTargets.push_back({ pNPC, ETargetType::NPC, vPos, vAngleTo, flFOVTo, flDistTo }); + } + } + + return validTargets; +} + +std::vector CAimbotProjectile::SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + auto validTargets = GetTargets(pLocal, pWeapon); + + const auto& sortMethod = static_cast(Vars::Aimbot::General::TargetSelection.Value); + F::AimbotGlobal.SortTargets(&validTargets, sortMethod); + + std::vector sortedTargets = {}; + int i = 0; for (auto& target : validTargets) + { + i++; if (i > Vars::Aimbot::General::MaxTargets.Value) break; + + sortedTargets.push_back(target); + } + + F::AimbotGlobal.SortPriority(&sortedTargets); + + return sortedTargets; +} + + + +float GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pLocal = nullptr) +{ + float flRadius = 0.f; + + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_PARTICLE_CANNON: + case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT: + case TF_WEAPON_ROCKETLAUNCHER: + case TF_WEAPON_PIPEBOMBLAUNCHER: + flRadius = 146.f; + } + if (G::WeaponDefIndex == Pyro_s_TheScorchShot) + flRadius = 110.f; + + if (!flRadius) + return 0.f; + + flRadius = SDK::AttribHookValue(flRadius, "mult_explosion_radius", pWeapon); + if (pLocal && pLocal->InCond(TF_COND_BLASTJUMPING) && SDK::AttribHookValue(1.f, "rocketjump_attackrate_bonus", pWeapon) != 1.f) + { + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_PARTICLE_CANNON: + case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT: + case TF_WEAPON_ROCKETLAUNCHER: + flRadius *= 0.8f; + } + } + return flRadius * Vars::Aimbot::Projectile::SplashRadius.Value / 100; +} + +float PrimeTime(CTFWeaponBase* pWeapon) +{ + if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER) + { + static auto tf_grenadelauncher_livetime = U::ConVars.FindVar("tf_grenadelauncher_livetime"); + const float flLiveTime = tf_grenadelauncher_livetime ? tf_grenadelauncher_livetime->GetFloat() : 0.8f; + return SDK::AttribHookValue(flLiveTime, "sticky_arm_time", pWeapon); + } + + return 0.f; +} + +int CAimbotProjectile::GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target) +{ + bool bHeadshot = target.m_TargetType == ETargetType::PLAYER && pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW; + if (Vars::Aimbot::Projectile::Modifiers.Value & (1 << 2) && bHeadshot) + { + float charge = I::GlobalVars->curtime - pWeapon->As()->m_flChargeBeginTime(); + float damage = Math::RemapValClamped(charge, 0.f, 1.f, 50.f, 120.f); + if (pLocal->IsMiniCritBoosted()) + damage *= 1.36f; + if (damage >= target.m_pEntity->As()->m_iHealth()) + bHeadshot = false; + + if (pLocal->IsCritBoosted()) // for reliability + bHeadshot = false; + } + const bool bLower = target.m_TargetType == ETargetType::PLAYER && target.m_pEntity->As()->IsOnGround() && GetSplashRadius(pWeapon); + + if (bHeadshot) + target.m_nAimedHitbox = HITBOX_HEAD; + + switch (nHitbox) + { + case 0: return bHeadshot ? 0 : 2; // head + case 1: return bHeadshot ? 3 : (bLower ? 1 : 0); // body + case 2: return bHeadshot ? 3 : (bLower ? 0 : 1); // feet + } + + return 3; +}; + +std::unordered_map CAimbotProjectile::GetDirectPoints(Target_t& target, bool bPlayer, CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + std::unordered_map mPoints = {}; + + const Vec3 vMins = target.m_pEntity->m_vecMins(), vMaxs = target.m_pEntity->m_vecMaxs(); + for (int i = 0; i < 3; i++) + { + const int iPriority = GetHitboxPriority(i, pLocal, pWeapon, target); + if (iPriority == 3) + continue; + + switch (i) + { + case 0: + if (bPlayer && target.m_nAimedHitbox == HITBOX_HEAD) + { + //const Vec3 vOff = target.m_pEntity->As()->GetHitboxPos(HITBOX_HEAD) - target.m_pEntity->GetAbsOrigin(); // uncomment if https://www.youtube.com/watch?v=_PSGD-pJUrM is fixed + + Vec3 vCenter, vBBoxMins, vBBoxMaxs; target.m_pEntity->As()->GetHitboxInfo(HITBOX_HEAD, &vCenter, &vBBoxMins, &vBBoxMaxs); + Vec3 vOff = vCenter + (vBBoxMins + vBBoxMaxs) / 2 - target.m_pEntity->GetAbsOrigin(); + + const float flHeight = vOff.z + (vMaxs.z - vOff.z) * (Vars::Aimbot::Projectile::HuntermanLerp.Value / 100.f); + const float flMax = vMaxs.z - Vars::Aimbot::Projectile::VerticalShift.Value; + mPoints[iPriority] = Vec3(vOff.x, vOff.y, std::min(flHeight, flMax)); + } + else + mPoints[iPriority] = Vec3(0, 0, vMaxs.z - Vars::Aimbot::Projectile::VerticalShift.Value); + break; + case 1: mPoints[iPriority] = Vec3(0, 0, (vMaxs.z - vMins.z) / 2); break; + case 2: mPoints[iPriority] = Vec3(0, 0, vMins.z + Vars::Aimbot::Projectile::VerticalShift.Value); break; + } + } + + return mPoints; +} + +// seode +std::vector ComputeSphere(float flRadius, int iSamples) +{ + std::vector vPoints; + vPoints.reserve(iSamples); + + for (int n = 0; n < iSamples; n++) + { + float a1 = acosf(1.f - 2.f * n / iSamples); + float a2 = PI * (3.f - sqrtf(5.f)) * n; + + Vec3 point = Vec3(sinf(a1) * cosf(a2), sinf(a1) * sinf(a2), -cosf(a1)) * flRadius; + + vPoints.push_back(point); + } + + return vPoints; +}; +std::vector CAimbotProjectile::GetSplashPoints(Target_t& target, std::vector& vSpherePoints, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Info_t& tInfo, int iSimTime) // possibly add air splash for autodet weapons +{ + std::vector vPoints = {}; + + const Vec3 vLocalEye = pLocal->GetShootPos(), vTargetEye = target.m_vPos + target.m_pEntity->As()->GetViewOffset(); + + auto checkPoint = [&](CGameTrace& trace, Vec3 vNormal, bool& bErase, bool bGrate = false) + { + bErase = true; + + if (!trace.DidHit() || !trace.m_pEnt || !trace.m_pEnt->GetAbsVelocity().IsZero() || trace.surface.flags & 0x0004 /*SURF_SKY*/) + return false; + + bErase = false; + + Point_t tPoint = { trace.endpos, {} }; + CalculateAngle(vLocalEye, tPoint.m_vPoint, tInfo, iSimTime, pLocal, pWeapon, tPoint.m_Solution); + if (tPoint.m_Solution.m_iCalculated == 1) + { + bErase = true; + + if (int(tPoint.m_Solution.m_flTime / TICK_INTERVAL) == iSimTime - 1) + { + Vec3 vForward; Math::AngleVectors({ tPoint.m_Solution.m_flPitch, tPoint.m_Solution.m_flYaw, 0.f }, &vForward); + if (vForward.Dot(vNormal) < 0) + vPoints.push_back(tPoint); + } + } + + return true; + }; + for (auto it = vSpherePoints.begin(); it != vSpherePoints.end();) + { + bool bErase = false; + + Vec3 vPoint = *it + vTargetEye; + Solution_t solution; CalculateAngle(pLocal->GetShootPos(), vPoint, tInfo, iSimTime, pLocal, pWeapon, solution, false); + if (solution.m_iCalculated != 3 && abs(solution.m_flTime - TICKS_TO_TIME(iSimTime)) < tInfo.flRadius / tInfo.flVelocity) + { + bErase = true; + + CGameTrace trace = {}; + CTraceFilterWorldAndPropsOnly filter = {}; + SDK::Trace(vTargetEye, vPoint, MASK_SOLID, &filter, &trace); + if (checkPoint(trace, trace.plane.normal, bErase) && !bErase) // regular + { + SDK::Trace(vPoint, vTargetEye, MASK_SHOT, &filter, &trace); + if (!trace.DidHit()) + { + SDK::Trace(vPoint, vTargetEye, MASK_SOLID, &filter, &trace); + checkPoint(trace, trace.plane.normal, bErase, true); // grate + } + } + } + + if (bErase) + it = vSpherePoints.erase(it); + else + ++it; + } + + std::sort(vPoints.begin(), vPoints.end(), [&](const auto& a, const auto& b) -> bool + { + return a.m_vPoint.DistTo(target.m_vPos) < b.m_vPoint.DistTo(target.m_vPos); + }); + vPoints.resize(Vars::Aimbot::Projectile::SplashCount.Value); + + const Vec3 vOriginal = target.m_pEntity->GetAbsOrigin(); + target.m_pEntity->SetAbsOrigin(target.m_vPos); + for (auto it = vPoints.begin(); it != vPoints.end();) + { + auto& vPoint = *it; + bool bValid = vPoint.m_Solution.m_iCalculated; + if (bValid) + { + Vec3 vPos = {}; reinterpret_cast(target.m_pEntity->GetCollideable())->CalcNearestPoint(vPoint.m_vPoint, &vPos); + bValid = vPoint.m_vPoint.DistTo(vPos) < tInfo.flRadius; + } + + if (bValid) + ++it; + else + it = vPoints.erase(it); + } + target.m_pEntity->SetAbsOrigin(vOriginal); + + return vPoints; +} + + + +void SolveProjectileSpeed(CTFWeaponBase* pWeapon, const Vec3& vLocalPos, const Vec3& vTargetPos, float& flVelocity, float& flDragTime, const float flGravity) +{ + if (F::ProjSim.obj->m_dragBasis.IsZero()) + return; + + const float flGrav = flGravity * 800.0f; + const Vec3 vDelta = vTargetPos - vLocalPos; + const float flDist = vDelta.Length2D(); + + const float flRoot = pow(flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flVelocity, 2)); + if (flRoot < 0.f) + return; + + const float flPitch = atan((pow(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); + const float flTime = flDist / (cos(flPitch) * flVelocity); + + float flDrag = 0.f; + if (Vars::Aimbot::Projectile::DragOverride.Value) + flDrag = Vars::Aimbot::Projectile::DragOverride.Value; + else + { + switch (pWeapon->m_iItemDefinitionIndex()) // the remaps are dumb but they work so /shrug + { + case Demoman_m_GrenadeLauncher: + case Demoman_m_GrenadeLauncherR: + case Demoman_m_FestiveGrenadeLauncher: + case Demoman_m_Autumn: + case Demoman_m_MacabreWeb: + case Demoman_m_Rainbow: + case Demoman_m_SweetDreams: + case Demoman_m_CoffinNail: + case Demoman_m_TopShelf: + case Demoman_m_Warhawk: + case Demoman_m_ButcherBird: + case Demoman_m_TheIronBomber: flDrag = Math::RemapValClamped(flVelocity, 1217.f, k_flMaxVelocity, 0.120f, 0.200f); break; // 0.120 normal, 0.200 capped, 0.300 v3000 + case Demoman_m_TheLochnLoad: flDrag = Math::RemapValClamped(flVelocity, 1504.f, k_flMaxVelocity, 0.070f, 0.085f); break; // 0.070 normal, 0.085 capped, 0.120 v3000 + case Demoman_m_TheLooseCannon: flDrag = Math::RemapValClamped(flVelocity, 1454.f, k_flMaxVelocity, 0.385f, 0.530f); break; // 0.385 normal, 0.530 capped, 0.790 v3000 + case Demoman_s_StickybombLauncher: + case Demoman_s_StickybombLauncherR: + case Demoman_s_FestiveStickybombLauncher: + case Demoman_s_TheQuickiebombLauncher: + case Demoman_s_TheScottishResistance: flDrag = Math::RemapValClamped(flVelocity, 922.f, k_flMaxVelocity, 0.085f, 0.190f); break; // 0.085 low, 0.190 capped, 0.230 v2400 + } + } + + flDragTime = powf(flTime, 2) * flDrag / 1.5f; // rough estimate to prevent m_flTime being too low + flVelocity = flVelocity - flVelocity * flTime * flDrag; + + if (Vars::Aimbot::Projectile::TimeOverride.Value) + flDragTime = Vars::Aimbot::Projectile::TimeOverride.Value; +} +void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, Info_t& tInfo, int iSimTime, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Solution_t& out, bool bAccuracy) +{ + if (out.m_iCalculated) + return; + + const float flGrav = tInfo.flGravity * 800.f; //U::ConVars.FindVar("sv_gravity")->GetFloat() + + float flPitch, flYaw; + { // basic trajectory pass + const Vec3 vDelta = vTargetPos - vLocalPos; + const float flDist = vDelta.Length2D(); + + if (!flGrav) + { + const Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vTargetPos); + flPitch = -DEG2RAD(vAngleTo.x); + flYaw = DEG2RAD(vAngleTo.y); + } + else + { // arch + const float flRoot = pow(tInfo.flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(tInfo.flVelocity, 2)); + if (flRoot < 0.f) + { out.m_iCalculated = 3; return; } + flPitch = atan((pow(tInfo.flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); + flYaw = atan2(vDelta.y, vDelta.x); + } + out.m_flTime = flDist / (cos(flPitch) * tInfo.flVelocity) - tInfo.flOffset; + flPitch = -RAD2DEG(flPitch) - tInfo.flUpFix, flYaw = RAD2DEG(flYaw); + } + + if (int(out.m_flTime / TICK_INTERVAL) >= iSimTime) + { out.m_iCalculated = 2; return; } + + ProjectileInfo projInfo = {}; + if (!F::ProjSim.GetInfo(pLocal, pWeapon, { flPitch, flYaw, 0 }, projInfo, bAccuracy)) + { out.m_iCalculated = 3; return; } + + { // correct angles + Vec3 vAngle; Math::VectorAngles(vTargetPos - projInfo.m_vPos, vAngle); + flPitch -= projInfo.m_vAng.x; + out.m_flYaw = flYaw + vAngle.y - projInfo.m_vAng.y; + } + + { // calculate trajectory from projectile origin + float flNewVel = tInfo.flVelocity, flDragTime = 0.f; + SolveProjectileSpeed(pWeapon, projInfo.m_vPos, vTargetPos, flNewVel, flDragTime, tInfo.flGravity); + + const Vec3 vDelta = vTargetPos - projInfo.m_vPos; + const float flDist = vDelta.Length2D(); + + if (!flGrav) + { + const Vec3 vAngleTo = Math::CalcAngle(projInfo.m_vPos, vTargetPos); + out.m_flPitch = -DEG2RAD(vAngleTo.x); + } + else + { // arch + const float flRoot = pow(flNewVel, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flNewVel, 2)); + if (flRoot < 0.f) + { out.m_iCalculated = 3; return; } + out.m_flPitch = atan((pow(flNewVel, 2) - sqrt(flRoot)) / (flGrav * flDist)); + } + out.m_flTime = flDist / (cos(out.m_flPitch) * flNewVel) + flDragTime; + out.m_flPitch = -RAD2DEG(out.m_flPitch) + flPitch - tInfo.flUpFix; + } + + out.m_iCalculated = int(out.m_flTime / TICK_INTERVAL) < iSimTime ? 1 : 2; +} + +bool CAimbotProjectile::TestAngle(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target, Vec3& vPoint, Vec3& vAngles, int iSimTime, bool bSplash, std::deque>* pProjLines) +{ + ProjectileInfo projInfo = {}; + if (!F::ProjSim.GetInfo(pLocal, pWeapon, vAngles, projInfo) || !F::ProjSim.Initialize(projInfo)) + return false; + + int bDidHit = 0; + + CGameTrace trace = {}; + CTraceFilterProjectile filter = {}; filter.pSkip = pLocal; + CTraceFilterWorldAndPropsOnly filterWorld = {}; + + //if (!projInfo.m_flGravity && !SDK::VisPosWorld(pLocal, target.m_pEntity, projInfo.m_vPos, vPoint, MASK_SOLID)) + // return false; + if (!projInfo.m_flGravity) + { + SDK::TraceHull(projInfo.m_vPos, vPoint, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filterWorld, &trace); + if (trace.fraction < 0.999f) + return false; + } + + if (Vars::Aimbot::General::AimType.Value != 2) + projInfo.m_vHull += Vec3(Vars::Aimbot::Projectile::HullInc.Value, Vars::Aimbot::Projectile::HullInc.Value, Vars::Aimbot::Projectile::HullInc.Value); + + const Vec3 vOriginal = target.m_pEntity->GetAbsOrigin(); + target.m_pEntity->SetAbsOrigin(target.m_vPos); + for (int n = -1; n < iSimTime; n++) + { + Vec3 Old = F::ProjSim.GetOrigin(); + F::ProjSim.RunTick(projInfo); + Vec3 New = F::ProjSim.GetOrigin(); + + if (bDidHit) + { + trace.endpos = New; + continue; + } + + if (!bSplash) + SDK::TraceHull(Old, New, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filter, &trace); + else + SDK::TraceHull(Old, New, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filterWorld, &trace); + if (trace.DidHit()) + { + const bool bTarget = trace.m_pEnt == target.m_pEntity; + const bool bTime = iSimTime - n < 5; + + bool bValid = (bTarget || bSplash) && bTime; + bValid = bValid && (bSplash ? SDK::VisPosWorld(nullptr, target.m_pEntity, trace.endpos, vPoint, MASK_SOLID) : true); + + if (bValid) + { + if (Vars::Aimbot::General::AimType.Value == 2) + { + // attempted to have a headshot check though this seems more detrimental than useful outside of smooth aimbot + if (target.m_nAimedHitbox == HITBOX_HEAD) + { // i think this is accurate? nope, 218 + const Vec3 vOffset = (trace.endpos - New) + (vOriginal - target.m_vPos); + + Vec3 vOld = F::ProjSim.GetOrigin() + vOffset; + F::ProjSim.RunTick(projInfo); + Vec3 vNew = F::ProjSim.GetOrigin() + vOffset; + + CGameTrace trace = {}; + SDK::Trace(vOld, vNew, MASK_SHOT, &filter, &trace); + trace.endpos -= vOffset; + + if (trace.DidHit() && (trace.m_pEnt != target.m_pEntity || trace.hitbox != HITBOX_HEAD)) + { bDidHit = 2; continue; } + + if (!trace.DidHit()) // loop and see if closest hitbox is head + { + auto pModel = target.m_pEntity->GetModel(); + if (!pModel) { bDidHit = 2; continue; } + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) { bDidHit = 2; continue; } + auto pSet = pHDR->pHitboxSet(target.m_pEntity->As()->m_nHitboxSet()); + if (!pSet) { bDidHit = 2; continue; } + + matrix3x4 BoneMatrix[128]; + if (!target.m_pEntity->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime())) + { bDidHit = 2; continue; } + + QAngle direction; Vector forward; + Math::VectorAngles(Old - New, direction); + Math::AngleVectors(direction, &forward); + const Vec3 vPos = trace.endpos + forward * 16 + vOriginal - target.m_vPos; + + //G::BulletsStorage.clear(); + //G::BulletsStorage.push_back({ {pLocal->GetShootPos(), vPos}, I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value }); + + float closestDist; int closestId = -1; + for (int i = 0; i < pSet->numhitboxes; ++i) + { + auto bbox = pSet->pHitbox(i); + if (!bbox) + continue; + + matrix3x4 rotMatrix; + Math::AngleMatrix(bbox->angle, rotMatrix); + matrix3x4 matrix; + Math::ConcatTransforms(BoneMatrix[bbox->bone], rotMatrix, matrix); + Vec3 mOrigin; + Math::GetMatrixOrigin(matrix, mOrigin); + + const float flDist = vPos.DistTo(mOrigin); + if (closestId != -1 && flDist < closestDist || closestId == -1) + { + closestDist = flDist; + closestId = i; + } + } + bDidHit = closestId == 0 ? true : 2; continue; + } + } + + if (bSplash && trace.endpos.DistTo(vPoint) > projInfo.m_flVelocity * TICK_INTERVAL) + { bDidHit = 2; continue; } + } + + bDidHit = true; + } + else + bDidHit = 2; + + if (!bSplash) + trace.endpos = New; + + if (!bTarget) + break; + } + } + target.m_pEntity->SetAbsOrigin(vOriginal); + + if (bDidHit == 1) + { + projInfo.PredictionLines.push_back({ trace.endpos, Math::GetRotatedPosition(trace.endpos, Math::VelocityToAngles(F::ProjSim.GetVelocity() * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) }); + *pProjLines = projInfo.PredictionLines; + } + + return bDidHit == 1; +} + + + +int CAimbotProjectile::CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::deque>* pMoveLines, std::deque>* pProjLines, std::vector* pBoxes, float* pTimeTo) +{ + if (Vars::Aimbot::General::Ignore.Value & UNSIMULATED && G::ChokeMap[target.m_pEntity->entindex()] > Vars::Aimbot::General::TickTolerance.Value) + return false; + + PlayerStorage storage; + F::MoveSim.Initialize(target.m_pEntity, storage); + target.m_vPos = target.m_pEntity->m_vecOrigin(); + const float flSize = target.m_pEntity->m_vecMins().DistTo(target.m_pEntity->m_vecMaxs()); + + int iMaxTime; Info_t tInfo = {}; + ProjectileInfo projInfo = {}; + { + if (!F::ProjSim.GetInfo(pLocal, pWeapon, {}, projInfo, false) || !F::ProjSim.Initialize(projInfo, false)) + { + F::MoveSim.Restore(storage); + return false; + } + + iMaxTime = TIME_TO_TICKS(std::min(projInfo.m_flLifetime, Vars::Aimbot::Projectile::PredictionTime.Value)); + + Vec3 vVelocity = F::ProjSim.GetVelocity(); + tInfo.flVelocity = vVelocity.Length(); // account for up velocity & capped velocity + Vec3 vBadAngle = {}; Math::VectorAngles(vVelocity, vBadAngle); tInfo.flUpFix = vBadAngle.x; // account for up velocity + + tInfo.vOffset = projInfo.m_vPos - pLocal->GetShootPos(); tInfo.vOffset.y *= -1; + tInfo.flOffset = tInfo.vOffset.Length() / tInfo.flVelocity; // silly + + tInfo.flGravity = projInfo.m_flGravity; + tInfo.flRadius = GetSplashRadius(pWeapon, pLocal); + tInfo.flSphere = (tInfo.flRadius + flSize) / tInfo.flVelocity; + + tInfo.iPrimeTime = TIME_TO_TICKS(PrimeTime(pWeapon)); + } + + const float flLatency = F::Backtrack.GetReal() + TICKS_TO_TIME(G::AnticipatedChoke - 1 + Vars::Aimbot::Projectile::LatOff.Value); + const bool bCanSplash = Vars::Aimbot::Projectile::SplashPrediction.Value && tInfo.flRadius; + const int iSplash = bCanSplash ? Vars::Aimbot::Projectile::SplashPrediction.Value : 0; + + auto mDirectPoints = iSplash == 3 ? std::unordered_map {} : GetDirectPoints(target, target.m_TargetType == ETargetType::PLAYER, pLocal, pWeapon); + auto vSpherePoints = !iSplash ? std::vector {} : ComputeSphere(tInfo.flRadius + flSize, Vars::Aimbot::Projectile::SplashPoints.Value); + + Vec3 vAngleTo, vPredicted, vTarget; + int iLowestPriority = std::numeric_limits::max(); float flLowestDist = std::numeric_limits::max(); + for (int i = 0; i < iMaxTime; i++) + { + const int iSimTime = i - TIME_TO_TICKS(flLatency); + if (!storage.m_bFailed) + { + F::MoveSim.RunTick(storage); + target.m_vPos = storage.m_MoveData.m_vecAbsOrigin; + } + + std::vector vSplashPoints = {}; + if (iSplash) + { + Solution_t solution; CalculateAngle(pLocal->GetShootPos(), target.m_vPos, tInfo, iSimTime, pLocal, pWeapon, solution, false); + if (solution.m_iCalculated != 3) + { + const float flTimeTo = solution.m_flTime - TICKS_TO_TIME(iSimTime); + if (flTimeTo < -tInfo.flSphere || vSpherePoints.empty()) + break; + else if (abs(flTimeTo) < tInfo.flSphere) + vSplashPoints = GetSplashPoints(target, vSpherePoints, pLocal, pWeapon, tInfo, iSimTime); + } + } + else if (mDirectPoints.empty()) + break; + + std::vector> vPoints = {}; + for (const auto& [iIndex, vPoint] : mDirectPoints) + vPoints.push_back({ { target.m_vPos + vPoint, {}}, iIndex + (iSplash == 2 ? Vars::Aimbot::Projectile::SplashCount.Value : 0), iIndex }); + for (const auto& vPoint : vSplashPoints) + vPoints.push_back({ vPoint, iSplash == 1 ? 3 : 0, -1 }); + + for (auto& [vPoint, iPriority, iIndex] : vPoints) // get most ideal point + { + const bool bSplash = iIndex == -1; + + float flDist = bSplash ? target.m_vPos.DistTo(vPoint.m_vPoint) : flLowestDist; + if (!bSplash + ? (iPriority >= iLowestPriority || !iLowestPriority || tInfo.iPrimeTime > iSimTime && !storage.m_MoveData.m_vecVelocity.IsZero()) + : (iPriority > iLowestPriority || flDist > flLowestDist)) + { + continue; + } + + CalculateAngle(pLocal->GetShootPos(), vPoint.m_vPoint, tInfo, iSimTime, pLocal, pWeapon, vPoint.m_Solution); + if (!bSplash && (vPoint.m_Solution.m_iCalculated == 1 || vPoint.m_Solution.m_iCalculated == 3)) + mDirectPoints.erase(iIndex); + if (vPoint.m_Solution.m_iCalculated != 1) + continue; + + Vec3 vAngles = Aim(G::CurrentUserCmd->viewangles, { vPoint.m_Solution.m_flPitch, vPoint.m_Solution.m_flYaw, 0.f }); + std::deque> vProjLines; + if (TestAngle(pLocal, pWeapon, target, vPoint.m_vPoint, vAngles, iSimTime, bSplash, &vProjLines)) + { + iLowestPriority = iPriority; flLowestDist = flDist; + vAngleTo = vAngles, vPredicted = target.m_vPos, vTarget = vPoint.m_vPoint; + *pTimeTo = vPoint.m_Solution.m_flTime + flLatency; + *pMoveLines = storage.PredictionLines; + if (!pMoveLines->empty()) + pMoveLines->push_back({ storage.m_MoveData.m_vecAbsOrigin, Math::GetRotatedPosition(storage.m_MoveData.m_vecAbsOrigin, Math::VelocityToAngles(storage.m_MoveData.m_vecVelocity * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) }); + *pProjLines = vProjLines; + } + } + } + F::MoveSim.Restore(storage); + + const float flTime = TICKS_TO_TIME(pProjLines->size()); + target.m_vPos = vTarget; + + if (iLowestPriority != std::numeric_limits::max() && + (target.m_TargetType == ETargetType::PLAYER ? !storage.m_bFailed : true)) // don't attempt to aim at players when movesim fails + { + target.m_vAngleTo = vAngleTo; + if (Vars::Visuals::Hitbox::ShowHitboxes.Value) + { + pBoxes->push_back({ vPredicted, target.m_pEntity->m_vecMins(), target.m_pEntity->m_vecMaxs(), Vec3(), I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f), Vars::Colors::HitboxEdge.Value, Vars::Colors::HitboxFace.Value, true }); + + const float flSize = std::clamp(projInfo.m_vHull.x, 1.f, 3.f); + const Vec3 vSize = { flSize, flSize, flSize }; + pBoxes->push_back({ vTarget, vSize * -1, vSize, Vec3(), I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f), Vars::Colors::HitboxEdge.Value, Vars::Colors::HitboxFace.Value, true }); + + if (Vars::Debug::Info.Value && target.m_nAimedHitbox == HITBOX_HEAD) // huntsman head + { + const Vec3 vOriginOffset = target.m_pEntity->GetAbsOrigin() - vPredicted; + + matrix3x4 BoneMatrix[128]; + if (!target.m_pEntity->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime())) + return true; + + auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)BoneMatrix, target.m_pEntity->As(), HITBOX_HEAD); + for (auto& bBox : vBoxes) + { + bBox.m_vecPos -= vOriginOffset; + bBox.m_flTime = I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f); + pBoxes->push_back(bBox); + } + } + if (Vars::Debug::Info.Value && target.m_nAimedHitbox == HITBOX_HEAD) // huntsman head, broken; removeme once 218 is fixed + { + const Vec3 vOriginOffset = target.m_pEntity->GetAbsOrigin() - vPredicted; + + matrix3x4 BoneMatrix[128]; + if (!target.m_pEntity->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, target.m_pEntity->m_flSimulationTime())) + return true; + + auto vBoxes = F::Visuals.GetHitboxes((matrix3x4*)BoneMatrix, target.m_pEntity->As(), HITBOX_HEAD); + for (auto& bBox : vBoxes) + { + bBox.m_vecPos -= vOriginOffset; + bBox.m_flTime = I::GlobalVars->curtime + (Vars::Visuals::Simulation::Timed.Value ? flTime : 5.f); + bBox.m_vecOrientation = Vec3(); + pBoxes->push_back(bBox); + } + } + } + return true; + } + + return false; +} + + + +// assume angle calculated outside with other overload +void CAimbotProjectile::Aim(CUserCmd* pCmd, Vec3& vAngle) +{ + if (Vars::Aimbot::General::AimType.Value != 3) + { + pCmd->viewangles = vAngle; + I::EngineClient->SetViewAngles(pCmd->viewangles); + } + else if (G::IsAttacking) + { + SDK::FixMovement(pCmd, vAngle); + pCmd->viewangles = vAngle; + G::PSilentAngles = true; + } +} + +Vec3 CAimbotProjectile::Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod) +{ + Vec3 vReturn = {}; + + Math::ClampAngles(vToAngle); + + switch (iMethod) + { + case 1: // Plain + case 3: // Silent + vReturn = vToAngle; + break; + case 2: // Smooth + { + auto shortDist = [](const float flAngleA, const float flAngleB) + { + const float flDelta = fmodf((flAngleA - flAngleB), 360.f); + return fmodf(2 * flDelta, 360.f) - flDelta; + }; + const float t = 1.f - Vars::Aimbot::General::Smoothing.Value / 100.f; + vReturn.x = vCurAngle.x - shortDist(vCurAngle.x, vToAngle.x) * t; + vReturn.y = vCurAngle.y - shortDist(vCurAngle.y, vToAngle.y) * t; + break; + } + } + + return vReturn; +} + +bool CAimbotProjectile::RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + static int iStaticAimType = Vars::Aimbot::General::AimType.Value; + const int iRealAimType = Vars::Aimbot::General::AimType.Value; + const int iLastAimType = iStaticAimType; + iStaticAimType = iRealAimType; + + const int nWeaponID = pWeapon->m_iWeaponID(); + + const bool bAutomatic = pWeapon->IsStreamingWeapon(), bKeepFiring = bAutomatic && G::LastUserCmd->buttons & IN_ATTACK; + if (bKeepFiring && !G::CanPrimaryAttack) + pCmd->buttons |= IN_ATTACK; + + switch (nWeaponID) + { + case TF_WEAPON_COMPOUND_BOW: + case TF_WEAPON_PIPEBOMBLAUNCHER: + case TF_WEAPON_CANNON: + if (!Vars::Aimbot::General::AutoShoot.Value && !iRealAimType && iLastAimType && G::IsAttacking) + Vars::Aimbot::General::AimType.Value = iLastAimType; + } + + if (!Vars::Aimbot::General::AimType.Value || !G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value == 3 && nWeaponID != TF_WEAPON_PIPEBOMBLAUNCHER && nWeaponID != TF_WEAPON_CANNON) + return true; + + auto targets = SortTargets(pLocal, pWeapon); + if (targets.empty()) + return true; + + if (Vars::Aimbot::Projectile::Modifiers.Value & (1 << 0) && iRealAimType + && (nWeaponID == TF_WEAPON_COMPOUND_BOW || nWeaponID == TF_WEAPON_PIPEBOMBLAUNCHER || nWeaponID == TF_WEAPON_CANNON)) + { + pCmd->buttons |= IN_ATTACK; + if (!G::CanPrimaryAttack && Vars::Aimbot::General::AimType.Value == 3) + return true; + } + + for (auto& target : targets) + { + float flTimeTo = 0.f; std::deque> vMoveLines, vProjLines; std::vector vBoxes = {}; + const int result = CanHit(target, pLocal, pWeapon, &vMoveLines, &vProjLines, &vBoxes, &flTimeTo); + if (!result) continue; + + G::Target = { target.m_pEntity->entindex(), I::GlobalVars->tickcount }; + if (Vars::Aimbot::General::AimType.Value == 3) + G::AimPosition = target.m_vPos; + + if (Vars::Aimbot::General::AutoShoot.Value) + { + pCmd->buttons |= IN_ATTACK; + + if (G::WeaponDefIndex == Soldier_m_TheBeggarsBazooka) + { + if (pWeapon->m_iClip1() > 0) + pCmd->buttons &= ~IN_ATTACK; + } + else + { + if ((nWeaponID == TF_WEAPON_COMPOUND_BOW || nWeaponID == TF_WEAPON_PIPEBOMBLAUNCHER) && pWeapon->As()->m_flChargeBeginTime() > 0.f) + pCmd->buttons &= ~IN_ATTACK; + else if (nWeaponID == TF_WEAPON_CANNON && pWeapon->As()->m_flDetonateTime() > 0.f) + { + bool bHealth = target.m_pEntity->IsPlayer() && target.m_pEntity->As()->m_iHealth() > 50 || target.m_pEntity->IsBuilding() && target.m_pEntity->As()->m_iHealth() > 50; + if (Vars::Aimbot::Projectile::Modifiers.Value & (1 << 0) && bHealth) + { + float flCharge = pWeapon->As()->m_flDetonateTime() - I::GlobalVars->curtime; + if (std::clamp(flCharge - 0.05f, 0.f, 1.f) < flTimeTo) + pCmd->buttons &= ~IN_ATTACK; + } + else + pCmd->buttons &= ~IN_ATTACK; + } + } + } + + G::IsAttacking = SDK::IsAttacking(pLocal, pWeapon, pCmd); + + if ((G::IsAttacking || !Vars::Aimbot::General::AutoShoot.Value) && (!pWeapon->IsInReload() || pWeapon->m_iWeaponID() == TF_WEAPON_CROSSBOW)) + { + if (Vars::Visuals::Simulation::Enabled.Value) + { + G::LinesStorage.clear(); + G::LinesStorage.push_back({ vMoveLines, Vars::Visuals::Simulation::Timed.Value ? -int(vMoveLines.size()) : I::GlobalVars->curtime + 5.f, Vars::Colors::PredictionColor.Value }); + if (G::IsAttacking) + G::LinesStorage.push_back({ vProjLines, Vars::Visuals::Simulation::Timed.Value ? -int(vProjLines.size()) - TIME_TO_TICKS(F::Backtrack.GetReal()) : I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value }); + } + if (Vars::Visuals::Hitbox::ShowHitboxes.Value) + { + G::BoxesStorage.clear(); + G::BoxesStorage.insert(G::BoxesStorage.end(), vBoxes.begin(), vBoxes.end()); + } + if (Vars::Visuals::Simulation::Enabled.Value || Vars::Visuals::Hitbox::ShowHitboxes.Value) + G::BulletsStorage.clear(); + } + + Aim(pCmd, target.m_vAngleTo); + if (G::PSilentAngles && pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER) + G::PSilentAngles = false, G::SilentAngles = true; + break; + } + + return false; +} + +void CAimbotProjectile::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + const bool bEarly = RunMain(pLocal, pWeapon, pCmd); + + float flAmount = 0.f; + if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER) + { + const float flCharge = pWeapon->As()->m_flChargeBeginTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As()->m_flChargeBeginTime() : 0.f; + flAmount = Math::RemapValClamped(flCharge, 0.f, SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon), 0.f, 1.f); + } + else if (pWeapon->m_iWeaponID() == TF_WEAPON_CANNON) + { + const float flMortar = SDK::AttribHookValue(0.f, "grenade_launcher_mortar_mode", pWeapon); + const float flCharge = pWeapon->As()->m_flDetonateTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As()->m_flDetonateTime() : -flMortar; + flAmount = flMortar ? Math::RemapValClamped(flCharge, -flMortar, 0.f, 0.f, 1.f) : 0.f; + } + + if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER && Vars::Aimbot::Projectile::AutoRelease.Value && flAmount > Vars::Aimbot::Projectile::AutoRelease.Value / 100) + pCmd->buttons &= ~IN_ATTACK; + else if (G::CanPrimaryAttack && Vars::Aimbot::Projectile::Modifiers.Value & (1 << 1)) + { + if (bLastTickHeld && (!Vars::Aimbot::General::AimType.Value && G::LastUserCmd->buttons & IN_ATTACK && !(pCmd->buttons & IN_ATTACK) || flAmount > 0.95f)) + { + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_COMPOUND_BOW: + pCmd->buttons |= IN_ATTACK2; + pCmd->buttons &= ~IN_ATTACK; + break; + case TF_WEAPON_CANNON: + if (auto pSwap = pLocal->GetWeaponFromSlot(SLOT_SECONDARY)) + { + pCmd->weaponselect = pSwap->entindex(); + bLastTickCancel = pWeapon->entindex(); + } + break; + case TF_WEAPON_PIPEBOMBLAUNCHER: + if (auto pSwap = pLocal->GetWeaponFromSlot(SLOT_PRIMARY)) + { + pCmd->weaponselect = pSwap->entindex(); + bLastTickCancel = pWeapon->entindex(); + } + } + } + } + + bLastTickHeld = Vars::Aimbot::General::AimType.Value; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h new file mode 100644 index 0000000..71c56fa --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h @@ -0,0 +1,56 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#include "../AimbotGlobal/AimbotGlobal.h" + +struct Solution_t +{ + float m_flPitch = 0.f; + float m_flYaw = 0.f; + float m_flTime = 0.f; + int m_iCalculated = 0; +}; +struct Point_t +{ + Vec3 m_vPoint = {}; + Solution_t m_Solution = {}; +}; +struct Info_t +{ + Vec3 vOffset = {}; + float flVelocity = 0.f; + float flGravity = 0.f; + float flRadius = 0.f; + float flSphere = 0.f; + float flUpFix = 0.f; + float flOffset = 0.f; + int iPrimeTime = 0; +}; + +class CAimbotProjectile +{ + std::vector GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + std::vector SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + + int GetHitboxPriority(int nHitbox, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target); + std::unordered_map GetDirectPoints(Target_t& target, bool bPlayer, CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + std::vector GetSplashPoints(Target_t& target, std::vector& vSpherePoints, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Info_t& tInfo, int iSimTime); + + void CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, Info_t& tInfo, int iSimTime, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Solution_t& out, bool bAccuracy = true); + bool TestAngle(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, Target_t& target, Vec3& vPoint, Vec3& vAngles, int iSimTime, bool bSplash, std::deque>* pProjLines); + + int CanHit(Target_t& target, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, std::deque>* pMoveLines, std::deque>* pProjLines, std::vector* pBoxes, float* pTimeTo); + bool RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + + void Aim(CUserCmd* pCmd, Vec3& vAngle); + Vec3 Aim(Vec3 vCurAngle, Vec3 vToAngle, int iMethod = Vars::Aimbot::General::AimType.Value); + + bool bLastTickHeld = false; + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + + int bLastTickCancel = 0; +}; + +ADD_FEATURE(CAimbotProjectile, AimbotProjectile) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoAirblast/AutoAirblast.cpp b/Amalgam/src/Features/Aimbot/AutoAirblast/AutoAirblast.cpp new file mode 100644 index 0000000..cd48e6f --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoAirblast/AutoAirblast.cpp @@ -0,0 +1,114 @@ +#include "AutoAirblast.h" + +bool CAutoAirblast::CanAirblastEntity(CTFPlayer* pLocal, CBaseEntity* pEntity, Vec3& vAngle, Vec3& vPos) +{ + Vec3 vForward = {}; Math::AngleVectors(vAngle, &vForward); + const Vec3 vOrigin = pLocal->GetShootPos() + (vForward * 128.f); + + CBaseEntity* pTarget; + for (CEntitySphereQuery sphere(vOrigin, 128.f); + (pTarget = sphere.GetCurrentEntity()) != nullptr; + sphere.NextEntity()) + { + if (pTarget == pEntity) + break; + } + + return pTarget == pEntity && SDK::VisPos(pLocal, pEntity, pLocal->GetShootPos(), vPos); +} + +void CAutoAirblast::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (!Vars::Aimbot::Projectile::AutoAirblast.Value || !G::CanSecondaryAttack /*|| Vars::Auto::Airblast::DisableOnAttack.Value && pCmd->buttons & IN_ATTACK*/) + return; + + const int iWeaponID = pWeapon->m_iWeaponID(); + if (iWeaponID != TF_WEAPON_FLAMETHROWER && iWeaponID != TF_WEAPON_FLAME_BALL || G::WeaponDefIndex == Pyro_m_ThePhlogistinator) + return; + + const Vec3 vEyePos = pLocal->GetShootPos(); + bool bShouldBlast = false; + + for (auto pProjectile : H::Entities.GetGroup(EGroupType::WORLD_PROJECTILES)) + { + if (pProjectile->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + + switch (pProjectile->GetClassID()) + { + case ETFClassID::CTFGrenadePipebombProjectile: + case ETFClassID::CTFStunBall: + { + if (pProjectile->As()->m_bTouched()) + continue; // Ignore landed stickies and sandman balls + break; + } + case ETFClassID::CTFProjectile_Arrow: + { + if (pProjectile->GetAbsVelocity().IsZero()) + continue; // Ignore arrows with no velocity / not moving + } + } + + Vec3 vPos = pProjectile->m_vecOrigin(); + if (Math::GetFov(I::EngineClient->GetViewAngles(), vEyePos, vPos) > Vars::Aimbot::General::AimFOV.Value) + continue; + + if (CanAirblastEntity(pLocal, pProjectile, pCmd->viewangles, vPos)) + { + bShouldBlast = true; + break; + } + if (!bShouldBlast && Vars::Aimbot::Projectile::AutoAirblast.Value == 2) // possibly implement proj aimbot somehow ? + { + Vec3 vAngle = Math::CalcAngle(vEyePos, vPos); + if (CanAirblastEntity(pLocal, pProjectile, vAngle, vPos)) + { + SDK::FixMovement(pCmd, vAngle); + pCmd->viewangles = vAngle; + G::PSilentAngles = true; + bShouldBlast = true; + break; + } + } + } + + /* + if (!bShouldBlast && Vars::Auto::Airblast::ExtinguishPlayers.Value) + { + for (auto pPlayer : H::Entities.GetGroup(EGroupType::PLAYERS_TEAMMATES)) + { + if (!pPlayer->IsOnFire() || !pPlayer->IsAlive() || pPlayer->IsAGhost()) + continue; + + Vec3 vPos = pPlayer->m_vecOrigin() + pPlayer->GetViewOffset(); // this seems to like to overpredict ? + if (Math::GetFov(I::EngineClient->GetViewAngles(), vEyePos, vPos) > Vars::Aimbot::General::AimFOV.Value) + continue; + + if (CanAirblastEntity(pLocal, pPlayer, pCmd->viewangles, vPos)) + { + bShouldBlast = true; + break; + } + if (!bShouldBlast && Vars::Aimbot::Projectile::AutoAirblast.Value == 2) + { + Vec3 vAngle = Math::CalcAngle(vEyePos, pPlayer->GetCenter()); + if (CanAirblastEntity(pLocal, pPlayer, vAngle, vPos)) + { + SDK::FixMovement(pCmd, vAngle); + pCmd->viewangles = vAngle; + G::PSilentAngles = true; + bShouldBlast = true; + break; + } + } + } + } + */ + + if (bShouldBlast) + { + G::IsAttacking = true; + pCmd->buttons |= IN_ATTACK2; + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoAirblast/AutoAirblast.h b/Amalgam/src/Features/Aimbot/AutoAirblast/AutoAirblast.h new file mode 100644 index 0000000..4c006cb --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoAirblast/AutoAirblast.h @@ -0,0 +1,12 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CAutoAirblast +{ + bool CanAirblastEntity(CTFPlayer* pLocal, CBaseEntity* pEntity, Vec3& vAngle, Vec3& vPos); + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CAutoAirblast, AutoAirblast) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp b/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp new file mode 100644 index 0000000..6b50baf --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp @@ -0,0 +1,80 @@ +#include "AutoDetonate.h" + +bool CAutoDetonate::CheckDetonation(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, EGroupType entityGroup, float flRadiusScale, CUserCmd* pCmd) +{ + for (auto pEntity : H::Entities.GetGroup(entityGroup)) + { + auto pExplosive = pEntity->As(); + if (pExplosive->m_iType() == TF_GL_MODE_REMOTE_DETONATE_PRACTICE || !pExplosive->m_bPulsed()) + continue; + + const Vec3 vOrigin = pExplosive->GetCenter(); + if (entityGroup == EGroupType::MISC_LOCAL_STICKIES) + { + if (pExplosive->m_iType() == TF_GL_MODE_REMOTE_DETONATE && !pExplosive->m_bTouched()) + { + static auto tf_grenadelauncher_livetime = U::ConVars.FindVar("tf_grenadelauncher_livetime"); + static auto tf_sticky_radius_ramp_time = U::ConVars.FindVar("tf_sticky_radius_ramp_time"); + static auto tf_sticky_airdet_radius = U::ConVars.FindVar("tf_sticky_airdet_radius"); + float flLiveTime = tf_grenadelauncher_livetime ? tf_grenadelauncher_livetime->GetFloat() : 0.8f; + float flRampTime = tf_sticky_radius_ramp_time ? tf_sticky_radius_ramp_time->GetFloat() : 2.f; + float flAirdetRadius = tf_sticky_airdet_radius ? tf_sticky_airdet_radius->GetFloat() : 0.85f; + flRadiusScale *= Math::RemapValClamped(I::GlobalVars->curtime - pExplosive->m_flCreationTime(), flLiveTime, flLiveTime + flRampTime, flAirdetRadius, 1.f); + } + } + float flRadius = (entityGroup == EGroupType::MISC_LOCAL_STICKIES ? 146.f : 110.f) * flRadiusScale; + + // Iterate through entities in sphere radius + CBaseEntity* pEntity; + for (CEntitySphereQuery sphere(vOrigin, flRadius); + (pEntity = sphere.GetCurrentEntity()) != nullptr; + sphere.NextEntity()) + { + if (!pEntity || pEntity == pLocal || pEntity->IsPlayer() && (!pEntity->As()->IsAlive() || pEntity->As()->IsAGhost()) || pEntity->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + + // CEntitySphereQuery actually does a box test so we need to make sure the distance is less than the radius first + Vec3 vPos = {}; reinterpret_cast(pEntity->GetCollideable())->CalcNearestPoint(vOrigin, &vPos); + if (vOrigin.DistTo(vPos) > flRadius) + continue; + + const bool isPlayer = pEntity->IsPlayer() && Vars::Aimbot::General::Target.Value & PLAYER && !F::AimbotGlobal.ShouldIgnore(pEntity->As(), pLocal, pWeapon); + const bool isSentry = Vars::Aimbot::General::Target.Value & SENTRY && pEntity->IsSentrygun(); + const bool isDispenser = Vars::Aimbot::General::Target.Value & DISPENSER && pEntity->IsDispenser(); + const bool isTeleporter = Vars::Aimbot::General::Target.Value & TELEPORTER && pEntity->IsTeleporter(); + const bool isSticky = Vars::Aimbot::General::Target.Value & STICKY && pEntity->GetClassID() == ETFClassID::CTFGrenadePipebombProjectile && pEntity->As()->m_iType() == TF_GL_MODE_REMOTE_DETONATE && (G::WeaponDefIndex == Demoman_s_TheQuickiebombLauncher || G::WeaponDefIndex == Demoman_s_TheScottishResistance); + const bool isNPC = Vars::Aimbot::General::Target.Value & NPC && pEntity->IsNPC(); + const bool isBomb = Vars::Aimbot::General::Target.Value & BOMB && pEntity->IsBomb(); + if (isPlayer || isSentry || isDispenser || isTeleporter || isNPC || isBomb || isSticky) + { + if (!SDK::VisPosProjectile(pExplosive, pEntity, vOrigin, isPlayer ? pEntity->m_vecOrigin() + pEntity->As()->GetViewOffset() : pEntity->GetCenter(), MASK_SHOT)) + continue; + + if (G::WeaponDefIndex == Demoman_s_TheScottishResistance) + { + Vec3 vAngleTo = Math::CalcAngle(pLocal->GetShootPos(), vOrigin); + SDK::FixMovement(pCmd, vAngleTo); + pCmd->viewangles = vAngleTo; + G::PSilentAngles = true; + } + return true; + } + } + } + + return false; +} + +void CAutoDetonate::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (!Vars::Aimbot::Projectile::AutoDetonate.Value) + return; + + // Check sticky detonation + if (Vars::Aimbot::Projectile::AutoDetonate.Value & (1 << 0) && CheckDetonation(pLocal, pWeapon, EGroupType::MISC_LOCAL_STICKIES, Vars::Aimbot::Projectile::AutodetRadius.Value / 100, pCmd)) + pCmd->buttons |= IN_ATTACK2; + + // Check flare detonation + if (Vars::Aimbot::Projectile::AutoDetonate.Value & (1 << 1) && CheckDetonation(pLocal, pWeapon, EGroupType::MISC_LOCAL_FLARES, Vars::Aimbot::Projectile::AutodetRadius.Value / 100, pCmd)) + pCmd->buttons |= IN_ATTACK2; +} diff --git a/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.h b/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.h new file mode 100644 index 0000000..782b241 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.h @@ -0,0 +1,14 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#include "../AimbotGlobal/AimbotGlobal.h" + +class CAutoDetonate +{ + bool CheckDetonation(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, EGroupType entityGroup, float flRadiusScale, CUserCmd* pCmd); + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CAutoDetonate, AutoDetonate) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp b/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp new file mode 100644 index 0000000..e6d0fbf --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp @@ -0,0 +1,192 @@ +#include "AutoRocketJump.h" + +#include "../../Simulation/ProjectileSimulation/ProjectileSimulation.h" +#include "../../Simulation/MovementSimulation/MovementSimulation.h" + +void CAutoRocketJump::ManageAngle(CTFWeaponBase* pWeapon, CUserCmd* pCmd, Vec3& viewAngles) +{ + Vec3 wishVel = { pCmd->forwardmove, pCmd->sidemove, 0.f }, wishAng; + Math::VectorAngles(wishVel, wishAng); + + const bool bMoving = wishVel.Length2D() > 200.f; + + float v_x = 0.f; + float v_y = bMoving ? viewAngles.y - wishAng.y : viewAngles.y; + if (pWeapon->m_iItemDefinitionIndex() == Soldier_m_TheOriginal) + { + v_x = bMoving ? 70.f : 89.f; + v_y -= 180.f; + } + else + { + v_x = bMoving ? 75.f : 89.f; + v_y -= bMoving ? 133.f : 81.5f; + } + viewAngles = { v_x, v_y, 0 }; +} + +void CAutoRocketJump::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (!pLocal || !pWeapon || !pCmd || !pLocal->IsAlive() || pLocal->IsAGhost() || I::EngineVGui->IsGameUIVisible() || I::MatSystemSurface->IsCursorVisible()) + { + iFrame = -1; + return; + } + + bool bValidWeapon = false; + { + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_ROCKETLAUNCHER: + case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT: + case TF_WEAPON_PARTICLE_CANNON: bValidWeapon = true; + } + } + if (bValidWeapon && (Vars::Misc::Movement::AutoRocketJump.Value || Vars::Misc::Movement::AutoCTap.Value)) + pCmd->buttons &= ~IN_ATTACK2; // fix for retarded issue + if (!bValidWeapon) + { + iFrame = -1; + return; + } + + const bool bCurrGrounded = pLocal->OnSolid(); + + // doesn't seem 100% consistent, unsure if it's fps related, user error, or what + if (iFrame == -1 && (pWeapon->m_iItemDefinitionIndex() == Soldier_m_TheBeggarsBazooka ? G::IsAttacking : G::CanPrimaryAttack)) + { + const bool bReloading = pWeapon->IsInReload(); + Vec3 viewAngles = pCmd->viewangles; + if (Vars::Misc::Movement::AutoRocketJump.Value) + ManageAngle(pWeapon, pCmd, viewAngles); + + bool bWillHit = false; + if (Vars::Misc::Movement::AutoRocketJump.Value || Vars::Misc::Movement::AutoCTap.Value) + { + PlayerStorage localStorage; + ProjectileInfo projInfo = {}; + if (F::MoveSim.Initialize(pLocal, localStorage, false) && F::ProjSim.GetInfo(pLocal, pWeapon, viewAngles, projInfo) && F::ProjSim.Initialize(projInfo)) + { + F::ProjSim.RunTick(projInfo); // run an initial time because dumb + for (int n = 1; n < 10; n++) + { + Vec3 Old = F::ProjSim.GetOrigin(); + F::ProjSim.RunTick(projInfo); + Vec3 New = F::ProjSim.GetOrigin(); + + F::MoveSim.RunTick(localStorage); + + CGameTrace trace = {}; + CTraceFilterProjectile filter = {}; + filter.pSkip = pLocal; + SDK::Trace(Old, New, MASK_SOLID, &filter, &trace); + if (trace.DidHit()) + { + auto WillHit = [](CTFPlayer* pLocal, const Vec3& vOrigin, const Vec3& vPoint) + { + const Vec3 vOriginal = pLocal->GetAbsOrigin(); + pLocal->SetAbsOrigin(vOrigin); + Vec3 vPos = {}; reinterpret_cast(pLocal->GetCollideable())->CalcNearestPoint(vPoint, &vPos); + pLocal->SetAbsOrigin(vOriginal); + + return vPoint.DistTo(vPos) < 120.f && SDK::VisPos(pLocal, pLocal, vPoint, vOrigin + pLocal->m_vecViewOffset(), MASK_SHOT); + }; + + bWillHit = WillHit(pLocal, localStorage.m_MoveData.m_vecAbsOrigin, trace.endpos); + iDelay = std::max(n + (n > Vars::Misc::Movement::ApplyAbove.Value ? Vars::Misc::Movement::TimingOffset.Value : 0), 0); + + if (bWillHit) + { + SDK::Output("Auto jump", std::format("Ticks to hit: {} ({})", iDelay, n).c_str(), { 255, 0, 0, 255 }, Vars::Debug::Logging.Value); + if (Vars::Debug::Info.Value) + { + G::LinesStorage.clear(); G::BoxesStorage.clear(); + G::LinesStorage.push_back({ {{ pLocal->GetShootPos(), {} }, { trace.endpos, {} }}, I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value, true }); + Vec3 angles; Math::VectorAngles(trace.plane.normal, angles); + G::BoxesStorage.push_back({ trace.endpos, { -1.f, -1.f, -1.f }, { 1.f, 1.f, 1.f }, angles, I::GlobalVars->curtime + 5.f, Vars::Colors::ProjectileColor.Value, {}, true }); + } + } + + break; + } + } + } + F::MoveSim.Restore(localStorage); + } + + if (bWillHit) + { + if (bCurrGrounded && bCurrGrounded == bLastGrounded && !pLocal->IsDucking()) + { + if (Vars::Misc::Movement::AutoRocketJump.Value) + { + iFrame = 0; + bFull = true; + } + else if (Vars::Misc::Movement::AutoCTap.Value) + iFrame = 0; + } + else if (!bCurrGrounded && pCmd->buttons & IN_DUCK) + { + if (pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka) + pCmd->buttons |= IN_ATTACK; + + if (Vars::Misc::Movement::AutoRocketJump.Value && !bReloading) + { + G::SilentAngles = true; // would use G::PSilentAngles but that would mess with timing + pCmd->viewangles = viewAngles; + } + } + + if (iFrame != -1 && bReloading && pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka) + { + iFrame = -1; + bFull = false; + pCmd->buttons |= IN_ATTACK; + } + } + + if (iFrame == -1 && pWeapon->m_iWeaponID() == TF_WEAPON_PARTICLE_CANNON && G::Buttons & IN_ATTACK2) + pCmd->buttons |= IN_ATTACK2; + } + + if (iFrame != -1) + { + iFrame++; + G::IsAttacking = true; // even if we aren't attacking, prevent other stuff from messing with timing, e.g. antiaim + + if (iFrame == 1) + { + if (pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka) + pCmd->buttons |= IN_ATTACK; + + if (bFull) + { + G::SilentAngles = true; // would use G::PSilentAngles but that would mess with timing + ManageAngle(pWeapon, pCmd, pCmd->viewangles); + } + } + + if (iDelay > 1) + { + switch (iFrame - iDelay + 1) + { + case 0: + pCmd->buttons |= IN_DUCK; + break; + case 1: + pCmd->buttons |= IN_JUMP; + } + } + else // won't ctap in time + pCmd->buttons |= IN_DUCK | IN_JUMP; + + if (iFrame == iDelay + (iDelay > 1 ? 1 : 3)) + { + iFrame = -1; + bFull = false; + } + } + + bLastGrounded = bCurrGrounded; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.h b/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.h new file mode 100644 index 0000000..8a97823 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.h @@ -0,0 +1,19 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CAutoRocketJump +{ + void ManageAngle(CTFWeaponBase* pWeapon, CUserCmd* pCmd, Vec3& viewAngles); + + bool bLastGrounded = false; + + bool bFull = false; + int iDelay = 0; + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + + int iFrame = -1; +}; + +ADD_FEATURE(CAutoRocketJump, AutoRocketJump) \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoUber/AutoUber.cpp b/Amalgam/src/Features/Aimbot/AutoUber/AutoUber.cpp new file mode 100644 index 0000000..71ddd73 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoUber/AutoUber.cpp @@ -0,0 +1,10 @@ +#include "AutoUber.h" + +#include "../../Players/PlayerUtils.h" + +// this will be rewritten soon + +void CAutoUber::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + +} \ No newline at end of file diff --git a/Amalgam/src/Features/Aimbot/AutoUber/AutoUber.h b/Amalgam/src/Features/Aimbot/AutoUber/AutoUber.h new file mode 100644 index 0000000..97ab380 --- /dev/null +++ b/Amalgam/src/Features/Aimbot/AutoUber/AutoUber.h @@ -0,0 +1,12 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#include "../AimbotGlobal/AimbotGlobal.h" + +class CAutoUber +{ +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CAutoUber, AutoUber) \ No newline at end of file diff --git a/Amalgam/src/Features/AutoQueue/AutoQueue.cpp b/Amalgam/src/Features/AutoQueue/AutoQueue.cpp new file mode 100644 index 0000000..7290a9c --- /dev/null +++ b/Amalgam/src/Features/AutoQueue/AutoQueue.cpp @@ -0,0 +1,10 @@ +#include "AutoQueue.h" + +void CAutoQueue::Run() +{ + if (Vars::Misc::Queueing::AutoCasualQueue.Value && !I::TFPartyClient->BInQueueForMatchGroup(k_eTFMatchGroup_Casual_Default)) + { + I::TFPartyClient->LoadSavedCasualCriteria(); + I::TFPartyClient->RequestQueueForMatch(k_eTFMatchGroup_Casual_Default); + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/AutoQueue/AutoQueue.h b/Amalgam/src/Features/AutoQueue/AutoQueue.h new file mode 100644 index 0000000..c6d4904 --- /dev/null +++ b/Amalgam/src/Features/AutoQueue/AutoQueue.h @@ -0,0 +1,10 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CAutoQueue +{ +public: + void Run(); +}; + +ADD_FEATURE(CAutoQueue, AutoQueue); \ No newline at end of file diff --git a/Amalgam/src/Features/Backtrack/Backtrack.cpp b/Amalgam/src/Features/Backtrack/Backtrack.cpp new file mode 100644 index 0000000..7a50624 --- /dev/null +++ b/Amalgam/src/Features/Backtrack/Backtrack.cpp @@ -0,0 +1,325 @@ +#include "Backtrack.h" + +//#include "../Simulation/MovementSimulation/MovementSimulation.h" + +#define ROUND_TO_TICKS(t) (TICKS_TO_TIME(TIME_TO_TICKS(t))) + +void CBacktrack::Restart() +{ + mRecords.clear(); + dSequences.clear(); + iLastInSequence = 0; +} + + + +// Returns the wish cl_interp +float CBacktrack::GetLerp() +{ + return Vars::Backtrack::Enabled.Value ? std::clamp(static_cast(Vars::Backtrack::Interp.Value), G::Lerp * 1000.f, flMaxUnlag * 1000.f) / 1000.f : G::Lerp; +} + +// Returns the current (custom) backtrack latency +float CBacktrack::GetFake() +{ + return bFakeLatency ? std::clamp(static_cast(Vars::Backtrack::Latency.Value), 0.f, flMaxUnlag * 1000.f) / 1000.f : 0.f; +} + +// Returns the current real latency +float CBacktrack::GetReal(int iFlow) +{ + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (!pNetChan) + return 0.f; + + if (iFlow != -1) + return pNetChan->GetLatency(iFlow) - (iFlow == FLOW_INCOMING ? GetFake() : 0.f); + return pNetChan->GetLatency(FLOW_INCOMING) - GetFake() + pNetChan->GetLatency(FLOW_OUTGOING); +} + +void CBacktrack::SendLerp() +{ + auto pNetChan = reinterpret_cast(I::EngineClient->GetNetChannelInfo()); + if (!pNetChan) + return; + + static Timer interpTimer{}; + if (interpTimer.Run(100)) + { + float flTarget = GetLerp(); + if (flTarget == flWishInterp) return; + flWishInterp = flTarget; + + SDK::Output("SendNetMsg", std::format("cl_interp: {}", flTarget).c_str(), { 224, 255, 131, 255 }, Vars::Debug::Logging.Value); + + NET_SetConVar cl_interp("cl_interp", std::to_string(flTarget).c_str()); + pNetChan->SendNetMsg(cl_interp); + + NET_SetConVar cl_interp_ratio("cl_interp_ratio", "1.0"); + pNetChan->SendNetMsg(cl_interp_ratio); + + NET_SetConVar cl_interpolate("cl_interpolate", "1"); + pNetChan->SendNetMsg(cl_interpolate); + } +} + +// Manages cl_interp client value +void CBacktrack::SetLerp(IGameEvent* pEvent) +{ + const bool bLocal = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid")) == I::EngineClient->GetLocalPlayer(); + if (bLocal) + flFakeInterp = flWishInterp; +} + +// Store the last 2048 sequences +void CBacktrack::UpdateDatagram() +{ + auto pNetChan = static_cast(I::EngineClient->GetNetChannelInfo()); + if (!pNetChan) + return; + + if (pNetChan->m_nInSequenceNr > iLastInSequence) + { + iLastInSequence = pNetChan->m_nInSequenceNr; + dSequences.push_front(CIncomingSequence(pNetChan->m_nInReliableState, pNetChan->m_nInSequenceNr, I::GlobalVars->realtime)); + } + + if (dSequences.size() > 2048) + dSequences.pop_back(); +} + + + +bool CBacktrack::WithinRewind(const TickRecord& record) +{ + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (!pNetChan) + return false; + + const float flCorrect = std::clamp(pNetChan->GetLatency(FLOW_OUTGOING) + ROUND_TO_TICKS(flFakeInterp) + GetFake(), 0.f, flMaxUnlag) - pNetChan->GetLatency(FLOW_OUTGOING); + const int iServerTick = iTickCount + (Vars::Misc::Game::NetworkFix.Value ? 1 : 0) + G::AnticipatedChoke + Vars::Backtrack::Offset.Value; + + const float flDelta = flCorrect - TICKS_TO_TIME(iServerTick - TIME_TO_TICKS(record.flSimTime)); + + return fabsf(flDelta) < float(Vars::Backtrack::Window.Value) / 1000; +} + +std::deque* CBacktrack::GetRecords(CBaseEntity* pEntity) +{ + if (mRecords[pEntity].empty()) + return nullptr; + + return &mRecords[pEntity]; +} + +std::deque CBacktrack::GetValidRecords(std::deque* pRecords, CTFPlayer* pLocal, bool bDistance) +{ + std::deque validRecords = {}; + if (!pRecords) + return validRecords; + + for (auto& pTick : *pRecords) + { + if (!WithinRewind(pTick)) + continue; + + validRecords.push_back(pTick); + } + + if (pLocal) + { + if (bDistance) + std::sort(validRecords.begin(), validRecords.end(), [&](const TickRecord& a, const TickRecord& b) -> bool + { + if (Vars::Backtrack::PreferOnShot.Value && a.bOnShot != b.bOnShot) + return a.bOnShot > b.bOnShot; + + return pLocal->m_vecOrigin().DistTo(a.vOrigin) < pLocal->m_vecOrigin().DistTo(b.vOrigin); + }); + else + { + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (!pNetChan) + return validRecords; + + const float flCorrect = std::clamp(pNetChan->GetLatency(FLOW_OUTGOING) + ROUND_TO_TICKS(flFakeInterp) + GetFake(), 0.f, flMaxUnlag) - pNetChan->GetLatency(FLOW_OUTGOING); + const int iServerTick = iTickCount + (Vars::Misc::Game::NetworkFix.Value ? 1 : 0) + G::AnticipatedChoke + Vars::Backtrack::Offset.Value; + + std::sort(validRecords.begin(), validRecords.end(), [&](const TickRecord& a, const TickRecord& b) -> bool + { + if (Vars::Backtrack::PreferOnShot.Value && a.bOnShot != b.bOnShot) + return a.bOnShot > b.bOnShot; + + const float flADelta = flCorrect - TICKS_TO_TIME(iServerTick - TIME_TO_TICKS(a.flSimTime)); + const float flBDelta = flCorrect - TICKS_TO_TIME(iServerTick - TIME_TO_TICKS(b.flSimTime)); + return fabsf(flADelta) < fabsf(flBDelta); + }); + } + } + + return validRecords; +} + + + +void CBacktrack::StoreNolerp() +{ + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + if (pEntity->entindex() == I::EngineClient->GetLocalPlayer()) + continue; + + // more of a placeholder, still interpolated iirc + bSettingUpBones = true; + mBones[pEntity].first = pEntity->SetupBones(mBones[pEntity].second, 128, BONE_USED_BY_ANYTHING, pEntity->m_flSimulationTime()); + bSettingUpBones = false; + + mEyeAngles[pEntity] = pEntity->As()->GetEyeAngles(); + } +} + +void CBacktrack::MakeRecords() +{ + if (iLastCreationTick == I::GlobalVars->tickcount) + return; + iLastCreationTick = I::GlobalVars->tickcount; + + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + if (pEntity->entindex() == I::EngineClient->GetLocalPlayer() || !mBones[pEntity].first) + continue; + + const float flSimTime = pEntity->m_flSimulationTime(), flOldSimTime = pEntity->m_flOldSimulationTime(); + if (TIME_TO_TICKS(flSimTime - flOldSimTime) <= 0) + continue; + + const TickRecord curRecord = { + flSimTime, + I::GlobalVars->curtime, + I::GlobalVars->tickcount, + mDidShoot[pEntity->entindex()], + *reinterpret_cast(&mBones[pEntity].second), + pEntity->m_vecOrigin() + }; + + bool bLagComp = false; + if (!mRecords[pEntity].empty()) // check for lagcomp breaking here + { + const Vec3 vDelta = curRecord.vOrigin - mRecords[pEntity].front().vOrigin; + + static auto sv_lagcompensation_teleport_dist = U::ConVars.FindVar("sv_lagcompensation_teleport_dist"); + const float flDist = powf(sv_lagcompensation_teleport_dist ? sv_lagcompensation_teleport_dist->GetFloat() : 64.f, 2.f); + if (vDelta.Length2DSqr() > flDist) + { + bLagComp = true; + for (auto& pRecord : mRecords[pEntity]) + pRecord.bInvalid = true; + } + + for (auto& pRecord : mRecords[pEntity]) + { + if (!pRecord.bInvalid) + continue; + + pRecord.bOnShot = curRecord.bOnShot; + pRecord.BoneMatrix = curRecord.BoneMatrix; + pRecord.vOrigin = curRecord.vOrigin; + } + } + + mRecords[pEntity].push_front(curRecord); + mLagCompensation[pEntity] = bLagComp; + + mDidShoot[pEntity->entindex()] = false; + } +} + +void CBacktrack::CleanRecords() +{ + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (pEntity->entindex() == I::EngineClient->GetLocalPlayer()) + continue; + + if (!pEntity->IsPlayer() || pEntity->IsDormant() || !pPlayer->IsAlive() || pPlayer->IsAGhost()) + { + mRecords[pEntity].clear(); + continue; + } + + //const int iOldSize = pRecords.size(); + + const int flDeadtime = I::GlobalVars->curtime + GetReal() - flMaxUnlag; // int ??? + while (!mRecords[pEntity].empty()) + { + if (mRecords[pEntity].back().flSimTime >= flDeadtime) + break; + + mRecords[pEntity].pop_back(); + } + + //const int iNewSize = pRecords.size(); + //if (iOldSize != iNewSize) + // SDK::Output("Clear", std::format("{} -> {}", iOldSize, iNewSize).c_str(), { 255, 0, 200, 255 }, Vars::Debug::Logging.Value); + } +} + + + +void CBacktrack::FrameStageNotify() +{ + UpdateDatagram(); + if (!I::EngineClient->IsInGame()) + return Restart(); + + static auto sv_maxunlag = U::ConVars.FindVar("sv_maxunlag"); + flMaxUnlag = sv_maxunlag ? sv_maxunlag->GetFloat() : 1.f; + + StoreNolerp(); + MakeRecords(); + CleanRecords(); +} + +void CBacktrack::Run(CUserCmd* pCmd) +{ + SendLerp(); + + // might not even be necessary + G::AnticipatedChoke = 0; + if (G::ShiftedTicks != G::MaxShift && G::WeaponType != EWeaponType::HITSCAN && Vars::Aimbot::General::AimType.Value == 3) + G::AnticipatedChoke = 1; + if (G::ChokeAmount && !Vars::CL_Move::Fakelag::UnchokeOnAttack.Value && G::ShiftedTicks == G::ShiftedGoal && !G::DoubleTap) + G::AnticipatedChoke = G::ChokeGoal - G::ChokeAmount; // iffy, unsure if there is a good way to get it to work well without unchoking +} + +void CBacktrack::ResolverUpdate(CBaseEntity* pEntity) +{ + mRecords[pEntity].clear(); // TODO: eventually remake records and rotate them or smthn idk, maybe just rotate them +} + +void CBacktrack::ReportShot(int iIndex) +{ + if (!Vars::Backtrack::PreferOnShot.Value) + return; + + auto pEntity = I::ClientEntityList->GetClientEntity(iIndex); + if (!pEntity || SDK::GetWeaponType(pEntity->As()->m_hActiveWeapon().Get()->As()) != EWeaponType::HITSCAN) + return; + + mDidShoot[pEntity->entindex()] = true; +} + +// Adjusts the fake latency ping +void CBacktrack::AdjustPing(CNetChannel* netChannel) +{ + for (const auto& cSequence : dSequences) + { + if (I::GlobalVars->realtime - cSequence.CurTime >= GetFake()) + { + netChannel->m_nInReliableState = cSequence.InReliableState; + netChannel->m_nInSequenceNr = cSequence.SequenceNr; + break; + } + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/Backtrack/Backtrack.h b/Amalgam/src/Features/Backtrack/Backtrack.h new file mode 100644 index 0000000..525cba2 --- /dev/null +++ b/Amalgam/src/Features/Backtrack/Backtrack.h @@ -0,0 +1,89 @@ +#pragma once +#include "../../SDK/SDK.h" + +#pragma warning ( disable : 4091 ) + +class CIncomingSequence +{ +public: + int InReliableState; + int SequenceNr; + float CurTime; + + CIncomingSequence(int inState, int seqNr, float time) + { + InReliableState = inState; + SequenceNr = seqNr; + CurTime = time; + } +}; + +using BoneMatrixes = struct +{ + float BoneMatrix[128][3][4]; +}; + +struct TickRecord +{ + float flSimTime = 0.f; + float flCreateTime = 0.f; + int iTickCount = 0; + bool bOnShot = false; + BoneMatrixes BoneMatrix{}; + Vec3 vOrigin = {}; + bool bInvalid = false; +}; + +class CBacktrack +{ + // logic + bool WithinRewind(const TickRecord& record); + + // utils + void SendLerp(); + void UpdateDatagram(); + void StoreNolerp(); + void MakeRecords(); + void CleanRecords(); + + // data + std::unordered_map mDidShoot; + int iLastCreationTick = 0; + + // data - fake latency + std::deque dSequences; + int iLastInSequence = 0; + + bool bLastTickHeld = false; + +public: + float GetLerp(); + float GetFake(); + float GetReal(int iFlow = -1); + + std::deque* GetRecords(CBaseEntity* pEntity); + std::deque GetValidRecords(std::deque* pRecords, CTFPlayer* pLocal = nullptr, bool bDistance = false); + + void Restart(); + void FrameStageNotify(); + void Run(CUserCmd* pCmd); + void SetLerp(IGameEvent* pEvent); + void ResolverUpdate(CBaseEntity* pEntity); + void ReportShot(int iIndex); + void AdjustPing(CNetChannel* netChannel); + + bool bFakeLatency = false; + float flWishInterp = 0.015f; + float flFakeInterp = 0.015f; + std::unordered_map> mRecords; + std::unordered_map> mBones; + std::unordered_map mEyeAngles; + std::unordered_map mLagCompensation; + + bool bSettingUpBones = false; + + int iTickCount = 0; + float flMaxUnlag = 1.f; +}; + +ADD_FEATURE(CBacktrack, Backtrack) \ No newline at end of file diff --git a/Amalgam/src/Features/CameraWindow/CameraWindow.cpp b/Amalgam/src/Features/CameraWindow/CameraWindow.cpp new file mode 100644 index 0000000..4d6f4c3 --- /dev/null +++ b/Amalgam/src/Features/CameraWindow/CameraWindow.cpp @@ -0,0 +1,70 @@ +#include "CameraWindow.h" + +void CCameraWindow::Init() +{ + // Create camera texture + CameraTex = I::MaterialSystem->CreateNamedRenderTargetTextureEx("mirrorcam_rt", 1, 1, RT_SIZE_FULL_FRAME_BUFFER, IMAGE_FORMAT_RGB888, MATERIAL_RT_DEPTH_SHARED, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, CREATERENDERTARGETFLAGS_HDR); + + // Create camera material + static auto* kv = new KeyValues("UnlitGeneric"); + kv->SetString("$basetexture", "mirrorcam_rt"); + CameraMat = I::MaterialSystem->CreateMaterial("m_cameraMat", kv); +} + +// Draws camera to the screen +void CCameraWindow::Draw() +{ + if (!ShouldDraw || !CameraMat || !I::EngineClient->IsInGame()) + return; + + const WindowBox_t& info = Vars::Visuals::Simulation::ProjectileWindow.Value; + + // Draw to screen + const auto renderCtx = I::MaterialSystem->GetRenderContext(); + renderCtx->DrawScreenSpaceRectangle( + CameraMat, + info.x, info.y, info.w, info.h, + 0, 0, info.w, info.h, + CameraTex->GetActualWidth(), CameraTex->GetActualHeight(), + nullptr, 1, 1 + ); + renderCtx->Release(); +} + +// Renders another view onto a texture +void CCameraWindow::RenderView(void* ecx, const CViewSetup& pViewSetup) +{ + if (!ShouldDraw || !CameraTex) + return; + + const WindowBox_t& info = Vars::Visuals::Simulation::ProjectileWindow.Value; + + CViewSetup viewSetup = pViewSetup; + viewSetup.x = 0; + viewSetup.y = 0; + + viewSetup.origin = CameraOrigin; + viewSetup.angles = CameraAngles; + + viewSetup.width = info.w + 1; + viewSetup.height = info.h + 1; + viewSetup.m_flAspectRatio = static_cast(viewSetup.width) / static_cast(viewSetup.height); + viewSetup.fov = 90; + + RenderCustomView(ecx, viewSetup, CameraTex); +} + +void CCameraWindow::RenderCustomView(void* ecx, const CViewSetup& pViewSetup, ITexture* pTexture) +{ + const auto renderCtx = I::MaterialSystem->GetRenderContext(); + + renderCtx->PushRenderTargetAndViewport(); + renderCtx->SetRenderTarget(pTexture); + + static auto ViewRender_RenderView = U::Hooks.m_mHooks["ViewRender_RenderView"]; + if (ViewRender_RenderView) + ViewRender_RenderView->Original()(ecx, pViewSetup, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, RENDERVIEW_UNSPECIFIED); + + renderCtx->PopRenderTargetAndViewport(); + renderCtx->Release(); +} \ No newline at end of file diff --git a/Amalgam/src/Features/CameraWindow/CameraWindow.h b/Amalgam/src/Features/CameraWindow/CameraWindow.h new file mode 100644 index 0000000..8f3b561 --- /dev/null +++ b/Amalgam/src/Features/CameraWindow/CameraWindow.h @@ -0,0 +1,21 @@ +#pragma once +#include "../../SDK/SDK.h" + +using RenderViewFN = void(__fastcall*)(void* ecx, const CViewSetup& view, ClearFlags_t nClearFlags, RenderViewInfo_t whatToDraw); + +class CCameraWindow +{ +public: + IMaterial* CameraMat; + ITexture* CameraTex; + Vec3 CameraOrigin; + Vec3 CameraAngles; + bool ShouldDraw = false; + + void Init(); + void Draw(); + void RenderView(void* ecx, const CViewSetup& pViewSetup); + void RenderCustomView(void* ecx, const CViewSetup& pViewSetup, ITexture* pTexture); +}; + +ADD_FEATURE(CCameraWindow, CameraWindow) \ No newline at end of file diff --git a/Amalgam/src/Features/CheaterDetection/CheaterDetection.cpp b/Amalgam/src/Features/CheaterDetection/CheaterDetection.cpp new file mode 100644 index 0000000..9ca343e --- /dev/null +++ b/Amalgam/src/Features/CheaterDetection/CheaterDetection.cpp @@ -0,0 +1,197 @@ +#include "CheaterDetection.h" + +#include "../Players/PlayerUtils.h" +#include "../Logs/Logs.h" + +bool CCheaterDetection::ShouldScan() +{ + if (!Vars::CheaterDetection::Methods.Value || I::EngineClient->IsPlayingTimeDemo()) + return false; + + static float flOldTime = I::GlobalVars->curtime; + const float flCurTime = I::GlobalVars->curtime; + const bool bShouldSkip = TIME_TO_TICKS(flCurTime - flOldTime) != 1; + flOldTime = flCurTime; + if (bShouldSkip) + return false; + + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (pNetChan && (pNetChan->GetTimeSinceLastReceived() > TICK_INTERVAL * 2 || pNetChan->IsTimingOut())) + return false; + + return true; +} + +bool CCheaterDetection::InvalidPitch(CTFPlayer* pEntity) +{ + return Vars::CheaterDetection::Methods.Value & (1 << 0) && fabsf(pEntity->m_angEyeAnglesX()) > 89.9f; +} + +bool CCheaterDetection::IsChoking(CTFPlayer* pEntity) +{ + const bool bReturn = mData[pEntity].bChoke; + mData[pEntity].bChoke = false; + + return Vars::CheaterDetection::Methods.Value & (1 << 1) && bReturn; +} + +bool CCheaterDetection::IsFlicking(CTFPlayer* pEntity) // this is aggravating +{ + auto& vAngles = mData[pEntity].vAngles; + if (!(Vars::CheaterDetection::Methods.Value & (1 << 2))) + { + vAngles.clear(); + return false; + } + + if (vAngles.size() != 3 || !vAngles[0].second && !vAngles[1].second && !vAngles[2].second) + return false; + + if (Math::CalcFov(vAngles[0].first, vAngles[1].first) < Vars::CheaterDetection::MinimumFlick.Value) + return false; + + if (Math::CalcFov(vAngles[0].first, vAngles[2].first) > Vars::CheaterDetection::MaximumNoise.Value * (TICK_INTERVAL / 0.015f)) + return false; + + vAngles.clear(); + return true; +} + +bool CCheaterDetection::IsDuckSpeed(CTFPlayer* pEntity) +{ + if (!(Vars::CheaterDetection::Methods.Value & (1 << 3)) + || !pEntity->IsDucking() || !pEntity->OnSolid() // this may break on movement sim + || pEntity->m_vecVelocity().Length2D() < pEntity->m_flMaxspeed() * 0.5f) + { + mData[pEntity].iDuckSpeed = 0; + return false; + } + + mData[pEntity].iDuckSpeed++; + if (mData[pEntity].iDuckSpeed > 20) + { + mData[pEntity].iDuckSpeed = 0; + return true; + } + + return false; +} + +void CCheaterDetection::Infract(CTFPlayer* pEntity, std::string sReason) +{ + mData[pEntity].iDetections++; + const bool bMark = mData[pEntity].iDetections >= Vars::CheaterDetection::DetectionsRequired.Value; + + F::Logs.CheatDetection(mData[pEntity].sName, bMark ? "marked" : "infracted", sReason); + if (bMark) + { + mData[pEntity].iDetections = 0; + F::PlayerUtils.AddTag(mData[pEntity].friendsID, "Cheater", true, mData[pEntity].sName); + } +} + +void CCheaterDetection::Run() +{ + if (!ShouldScan() || !I::EngineClient->IsConnected()) + return; + + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (!mData[pPlayer].bShouldScan) + continue; + + mData[pPlayer].bShouldScan = false; + + if (InvalidPitch(pPlayer)) + Infract(pPlayer, "invalid pitch"); + if (IsChoking(pPlayer)) + Infract(pPlayer, "choking packets"); + if (IsFlicking(pPlayer)) + Infract(pPlayer, "flicking"); + if (IsDuckSpeed(pPlayer)) + Infract(pPlayer, "duck speed"); + } +} + +void CCheaterDetection::Fill() // maybe just run here +{ + if (!Vars::CheaterDetection::Methods.Value || I::EngineClient->IsPlayingTimeDemo()) + return; + + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + mData[pPlayer].bShouldScan = false; + + PlayerInfo_t pi{}; + if (pPlayer->entindex() == I::EngineClient->GetLocalPlayer() || !pPlayer->IsAlive() || pPlayer->IsAGhost() || pPlayer->IsDormant() + || !I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) || pi.fakeplayer || F::PlayerUtils.HasTag(pi.friendsID, "Cheater")) + { + mData[pPlayer].vChokes.clear(); + mData[pPlayer].bChoke = false; + mData[pPlayer].vAngles.clear(); + mData[pPlayer].iDuckSpeed = 0; + continue; + } + + if (pPlayer->m_flSimulationTime() == pPlayer->m_flOldSimulationTime()) + continue; + + mData[pPlayer].bShouldScan = true; + mData[pPlayer].friendsID = pi.friendsID; + mData[pPlayer].sName = pi.name; + mData[pPlayer].vAngles.push_back({ pPlayer->GetEyeAngles(), mData[pPlayer].bDamage }); + mData[pPlayer].bDamage = false; + if (mData[pPlayer].vAngles.size() > 3) + mData[pPlayer].vAngles.pop_front(); + } +} + +void CCheaterDetection::Reset() +{ + mData.clear(); +} + +void CCheaterDetection::ReportChoke(CTFPlayer* pEntity, int iChoke) +{ + if (Vars::CheaterDetection::Methods.Value & (1 << 1)) + { + mData[pEntity].vChokes.push_back(iChoke); + if (mData[pEntity].vChokes.size() == 3) + { + mData[pEntity].bChoke = true; // check for last 3 choke amounts + for (auto& iChoke : mData[pEntity].vChokes) + { + if (iChoke < Vars::CheaterDetection::MinimumChoking.Value) + mData[pEntity].bChoke = false; + } + mData[pEntity].vChokes.clear(); + } + } + else + mData[pEntity].vChokes.clear(); +} + +void CCheaterDetection::ReportDamage(IGameEvent* pEvent) +{ + if (!(Vars::CheaterDetection::Methods.Value & (1 << 2))) + return; + + const int iIndex = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid")); + if (iIndex == I::EngineClient->GetLocalPlayer()) + return; + + auto pEntity = I::ClientEntityList->GetClientEntity(iIndex); + if (!pEntity || pEntity->IsDormant()) + return; + + switch (SDK::GetWeaponType(pEntity->As()->m_hActiveWeapon().Get()->As())) + { + case EWeaponType::UNKNOWN: + case EWeaponType::PROJECTILE: + return; + } + + mData[pEntity->As()].bDamage = true; +} \ No newline at end of file diff --git a/Amalgam/src/Features/CheaterDetection/CheaterDetection.h b/Amalgam/src/Features/CheaterDetection/CheaterDetection.h new file mode 100644 index 0000000..c7464b1 --- /dev/null +++ b/Amalgam/src/Features/CheaterDetection/CheaterDetection.h @@ -0,0 +1,42 @@ +#pragma once +#include "../../SDK/SDK.h" +#include "../Backtrack/Backtrack.h" + +struct PlayerInfo +{ + bool bShouldScan = false; + uint32_t friendsID = 0; + std::string sName = ""; + + int iDetections = 0; + + std::deque vChokes = {}; // store last 3 choke counts + bool bChoke = false; // infract the user for choking? + std::deque> vAngles = {}; // store last 3 angles & if damage was dealt + bool bDamage = false; + int iDuckSpeed = 0; // how many times in a row a user has been detected for duck speed +}; + +class CCheaterDetection +{ + bool ShouldScan(); + + bool InvalidPitch(CTFPlayer* pEntity); + bool IsChoking(CTFPlayer* pEntity); + bool IsFlicking(CTFPlayer* pEntity); + bool IsDuckSpeed(CTFPlayer* pEntity); + + void Infract(CTFPlayer* pEntity, std::string sReason); + + std::unordered_map mData; + +public: + void Run(); + void Fill(); + + void ReportChoke(CTFPlayer* pEntity, int iChoke); + void ReportDamage(IGameEvent* pEvent); + void Reset(); +}; + +ADD_FEATURE(CCheaterDetection, CheaterDetection) \ No newline at end of file diff --git a/Amalgam/src/Features/Commands/Commands.cpp b/Amalgam/src/Features/Commands/Commands.cpp new file mode 100644 index 0000000..cec9409 --- /dev/null +++ b/Amalgam/src/Features/Commands/Commands.cpp @@ -0,0 +1,83 @@ +#include "Commands.h" + +#include "../../Core/Core.h" +#include "../ImGui/Menu/Menu.h" +#include +#include +#include + +bool CCommands::Run(const std::string& cmd, std::deque& args) +{ + if (!CommandMap.contains(cmd)) + return false; + + CommandMap[cmd](args); + return true; +} + +void CCommands::Register(const std::string& name, CommandCallback callback) +{ + CommandMap[name] = std::move(callback); +} + +void CCommands::Initialize() +{ + Register("queue", [](const std::deque& args) + { + I::TFPartyClient->LoadSavedCasualCriteria(); + I::TFPartyClient->RequestQueueForMatch(k_eTFMatchGroup_Casual_Default); + }); + + Register("setcvar", [](std::deque args) + { + // Check if the user provided at least 2 args + if (args.size() < 2) + { + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Usage: setcvar \n"); + return; + } + + // Find the given CVar + const auto foundCVar = I::CVar->FindVar(args[0].c_str()); + const std::string cvarName = args[0]; + if (!foundCVar) + { + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Could not find %s\n", cvarName.c_str()); + return; + } + + // Set the CVar to the given value + args.pop_front(); + std::string newValue = boost::algorithm::join(args, " "); + boost::replace_all(newValue, "\"", ""); + foundCVar->SetValue(newValue.c_str()); + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Set %s to: %s\n", cvarName.c_str(), newValue.c_str()); + }); + + Register("getcvar", [](std::deque args) + { + // Check if the user provided 1 arg + if (args.size() != 1) + { + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Usage: getcvar \n"); + return; + } + + const auto foundCVar = I::CVar->FindVar(args[0].c_str()); + const std::string cvarName = args[0]; + if (!foundCVar) + { + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Could not find %s\n", cvarName.c_str()); + return; + } + + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "Value of %s is: %s\n", cvarName.c_str(), foundCVar->GetString()); + }); + + Register("unload", [](std::deque args) + { + if (F::Menu.IsOpen) + I::MatSystemSurface->SetCursorAlwaysVisible(F::Menu.IsOpen = false); + U::Core.bUnload = true; + }); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Commands/Commands.h b/Amalgam/src/Features/Commands/Commands.h new file mode 100644 index 0000000..aa69049 --- /dev/null +++ b/Amalgam/src/Features/Commands/Commands.h @@ -0,0 +1,18 @@ +#pragma once +#include "../../SDK/SDK.h" +#include + +using CommandCallback = std::function)>; + +class CCommands +{ +private: + std::unordered_map CommandMap; + +public: + void Initialize(); + bool Run(const std::string& cmd, std::deque& args); + void Register(const std::string& name, CommandCallback callback); +}; + +ADD_FEATURE(CCommands, Commands) \ No newline at end of file diff --git a/Amalgam/src/Features/Conditions/Conditions.cpp b/Amalgam/src/Features/Conditions/Conditions.cpp new file mode 100644 index 0000000..55cd73a --- /dev/null +++ b/Amalgam/src/Features/Conditions/Conditions.cpp @@ -0,0 +1,205 @@ +#include "Conditions.h" + +#include + +#define IsType(type) var->m_iType == typeid(type).hash_code() +#define SetType(type, cond)\ +{\ + if (var->GetVar()->Map.contains(cond))\ + var->GetVar()->Value = var->GetVar()->Map[cond];\ +} +#define SetT(type, cond) if (IsType(type)) SetType(type, cond) + +void CConditions::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (G::Unload) + return; + + auto setVars = [](std::string sCond) + { + const bool bDefault = FNV1A::Hash(sCond.c_str()) == FNV1A::HashConst("default"); + for (const auto var : g_Vars) + { + if (var->m_iFlags & (NOSAVE | NOCOND) && !bDefault) + continue; + + SetT(bool, sCond) + else SetT(int, sCond) + else SetT(float, sCond) + else SetT(IntRange_t, sCond) + else SetT(FloatRange_t, sCond) + else SetT(std::string, sCond) + else SetT(std::vector, sCond) + else SetT(Color_t, sCond) + else SetT(Gradient_t, sCond) + else SetT(Vec3, sCond) + else SetT(DragBox_t, sCond) + else SetT(WindowBox_t, sCond) + } + }; + setVars("default"); + + std::function getConds = [&](std::string sParent) + { + auto uHash = FNV1A::Hash(sParent.c_str()); + for (auto& sCond : vConditions) + { + auto& tCond = mConditions[sCond]; + if (uHash != FNV1A::Hash(tCond.Parent.c_str())) + continue; + + switch (tCond.Type) + { + // key + case 0: + { + bool bKey = false; + switch (tCond.Info) + { + case 0: bKey = U::KeyHandler.Down(tCond.Key, true, &tCond.Storage); break; + case 1: bKey = U::KeyHandler.Pressed(tCond.Key, true, &tCond.Storage); break; + case 2: bKey = U::KeyHandler.Double(tCond.Key, true, &tCond.Storage); break; + } + const bool bUIOpen = I::EngineVGui->IsGameUIVisible() || I::MatSystemSurface->IsCursorVisible(); + bKey = !bUIOpen && bKey; + if (tCond.Not) + bKey = !bKey; + + switch (tCond.Info) + { + case 0: tCond.Active = bKey; break; + case 1: + case 2: if (bKey) tCond.Active = !tCond.Active; + } + break; + } + // class + case 1: + { + const int iClass = pLocal ? pLocal->m_iClass() : 0; + switch (tCond.Info) + { + case 0: { tCond.Active = iClass == 1; break; } + case 1: { tCond.Active = iClass == 3; break; } + case 2: { tCond.Active = iClass == 7; break; } + case 3: { tCond.Active = iClass == 4; break; } + case 4: { tCond.Active = iClass == 6; break; } + case 5: { tCond.Active = iClass == 9; break; } + case 6: { tCond.Active = iClass == 5; break; } + case 7: { tCond.Active = iClass == 2; break; } + case 8: { tCond.Active = iClass == 8; break; } + } + if (tCond.Not) + tCond.Active = !tCond.Active; + break; + } + // weapon type + case 2: + { + tCond.Active = tCond.Info + 1 == int(SDK::GetWeaponType(pWeapon)); + if (tCond.Not) + tCond.Active = !tCond.Active; + } + } + + if (tCond.Active) + { + setVars(sCond); + getConds(sCond); + } + } + }; + getConds(""); +} + +bool CConditions::HasChildren(std::string sCondition) +{ + auto uHash = FNV1A::Hash(sCondition.c_str()); + auto it = std::ranges::find_if(vConditions, [this, uHash](const auto& sCond) { return uHash == FNV1A::Hash(mConditions[sCond].Parent.c_str()); }); + return it != vConditions.end(); +} + +std::string CConditions::GetParent(std::string sCondition) +{ + if (mConditions.contains(sCondition) && mConditions[sCondition].Parent.length()) + return mConditions[sCondition].Parent; + return "default"; +} + +void CConditions::AddCondition(std::string sCondition, Condition_t tCond) +{ + if (!mConditions.contains(sCondition)) + vConditions.push_back(sCondition); + mConditions[sCondition] = tCond; +} + +// fun! +#define RemoveType(type, cond)\ +{\ + if (var->GetVar()->Map.contains(cond))\ + {\ + auto uHash = FNV1A::Hash(cond.c_str());\ + for (auto it = var->GetVar()->Map.begin(); it != var->GetVar()->Map.end();)\ + {\ + if (uHash == FNV1A::Hash(it->first.c_str()))\ + it = var->GetVar()->Map.erase(it);\ + else\ + ++it;\ + }\ + }\ +} +#define RemoveT(type, cond) if (IsType(type)) RemoveType(type, cond) + +void CConditions::RemoveCondition(std::string sCondition) +{ + for (const auto var : g_Vars) + { + RemoveT(bool, sCondition) + else RemoveT(int, sCondition) + else RemoveT(float, sCondition) + else RemoveT(IntRange_t, sCondition) + else RemoveT(FloatRange_t, sCondition) + else RemoveT(std::string, sCondition) + else RemoveT(std::vector, sCondition) + else RemoveT(Color_t, sCondition) + else RemoveT(Gradient_t, sCondition) + else RemoveT(Vec3, sCondition) + else RemoveT(DragBox_t, sCondition) + else RemoveT(WindowBox_t, sCondition) + } + + auto removeCond = [&](std::string sCond) + { + auto uHash = FNV1A::Hash(sCond.c_str()); + for (auto it = vConditions.begin(); it != vConditions.end();) + { + if (uHash == FNV1A::Hash(it->c_str())) + it = vConditions.erase(it); + else + ++it; + } + for (auto it = mConditions.begin(); it != mConditions.end();) + { + if (uHash == FNV1A::Hash(it->first.c_str())) + it = mConditions.erase(it); + else + ++it; + } + }; + removeCond(sCondition); + + std::function removeChildren = [&](std::string sParent) + { + auto uHash = FNV1A::Hash(sParent.c_str()); + for (auto& sCond : vConditions) + { + auto& cCond = mConditions[sCond]; + if (uHash != FNV1A::Hash(cCond.Parent.c_str())) + continue; + + removeCond(sCond); + removeChildren(sCond); + } + }; + removeChildren(sCondition); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Conditions/Conditions.h b/Amalgam/src/Features/Conditions/Conditions.h new file mode 100644 index 0000000..0b2b916 --- /dev/null +++ b/Amalgam/src/Features/Conditions/Conditions.h @@ -0,0 +1,34 @@ +#pragma once +#include "../../SDK/SDK.h" + +struct Condition_t +{ + int Type = 0; // Key, Class, Weapon type + int Info = 0; // Key: Hold, Toggle, Double click + // Class: Scout, Soldier, Pyro, Demoman, Heavy, Engineer, Medic, Sniper, Spy + // Weapon type: Hitscan, Projectile, Melee + int Key = 0; + bool Not = false; + + bool Active = false; + bool Visible = true; + KeyStorage Storage = {}; + + std::string Parent = ""; +}; + +class CConditions +{ +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + + bool HasChildren(std::string sCondition); + std::string GetParent(std::string sCondition); + void AddCondition(std::string sCondition, Condition_t tCond); + void RemoveCondition(std::string sCondition); + + std::unordered_map mConditions = {}; + std::vector vConditions = {}; // retain order +}; + +ADD_FEATURE(CConditions, Conditions) \ No newline at end of file diff --git a/Amalgam/src/Features/Configs/Configs.cpp b/Amalgam/src/Features/Configs/Configs.cpp new file mode 100644 index 0000000..ce7f53b --- /dev/null +++ b/Amalgam/src/Features/Configs/Configs.cpp @@ -0,0 +1,540 @@ +#include "Configs.h" + +#include "../Conditions/Conditions.h" +#include "../Visuals/Notifications/Notifications.h" +#include "../Visuals/Materials/Materials.h" + +boost::property_tree::ptree CConfigs::ColorToTree(const Color_t& color) +{ + boost::property_tree::ptree colorTree; + colorTree.put("r", color.r); + colorTree.put("g", color.g); + colorTree.put("b", color.b); + colorTree.put("a", color.a); + + return colorTree; +} + +void CConfigs::TreeToColor(const boost::property_tree::ptree& tree, Color_t& out) +{ + if (auto v = tree.get_optional("r")) { out.r = *v; } + if (auto v = tree.get_optional("g")) { out.g = *v; } + if (auto v = tree.get_optional("b")) { out.b = *v; } + if (auto v = tree.get_optional("a")) { out.a = *v; } +} + + + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, bool val) +{ + mapTree.put(name, val); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, int val) +{ + mapTree.put(name, val); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, float val) +{ + mapTree.put(name, val); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const IntRange_t& val) +{ + boost::property_tree::ptree rangeTree; + rangeTree.put("Min", val.Min); + rangeTree.put("Max", val.Max); + + mapTree.put_child(name, rangeTree); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const FloatRange_t& val) +{ + boost::property_tree::ptree rangeTree; + rangeTree.put("Min", val.Min); + rangeTree.put("Max", val.Max); + + mapTree.put_child(name, rangeTree); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::string& val) +{ + mapTree.put(name, val); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::vector& val) +{ + boost::property_tree::ptree vectorTree; + for (const auto& sMat : val) + { + boost::property_tree::ptree child; child.put("", sMat); + vectorTree.push_back(std::make_pair("", child)); + } + mapTree.put_child(name, vectorTree); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Color_t& val) +{ + mapTree.put_child(name, ColorToTree(val)); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Gradient_t& val) +{ + boost::property_tree::ptree gradientTree; + gradientTree.put_child("StartColor", ColorToTree(val.StartColor)); + gradientTree.put_child("EndColor", ColorToTree(val.EndColor)); + + mapTree.put_child(name, gradientTree); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const DragBox_t& val) +{ + boost::property_tree::ptree dragBoxTree; + dragBoxTree.put("x", val.x); + dragBoxTree.put("y", val.y); + + mapTree.put_child(name, dragBoxTree); +} + +void CConfigs::SaveJson(boost::property_tree::ptree& mapTree, const char* name, const WindowBox_t& val) +{ + boost::property_tree::ptree dragBoxTree; + dragBoxTree.put("x", val.x); + dragBoxTree.put("y", val.y); + dragBoxTree.put("w", val.w); + dragBoxTree.put("h", val.h); + + mapTree.put_child(name, dragBoxTree); +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, bool& val) +{ + if (auto getValue = mapTree.get_optional(name)) + { + val = *getValue; + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, int& val) +{ + if (auto getValue = mapTree.get_optional(name)) + { + val = *getValue; + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, float& val) +{ + if (auto getValue = mapTree.get_optional(name)) + { + val = *getValue; + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, IntRange_t& val) +{ + if (const auto getChild = mapTree.get_child_optional(name)) + { + if (auto getValue = getChild->get_optional("Min")) { val.Min = *getValue; } + if (auto getValue = getChild->get_optional("Max")) { val.Max = *getValue; } + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, FloatRange_t& val) +{ + if (const auto getChild = mapTree.get_child_optional(name)) + { + if (auto getValue = getChild->get_optional("Min")) { val.Min = *getValue; } + if (auto getValue = getChild->get_optional("Max")) { val.Max = *getValue; } + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::string& val) +{ + if (auto getValue = mapTree.get_optional(name)) + { + val = *getValue; + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::vector& val) +{ + auto getMaterials = [](std::vector& val, const boost::optional getVector) + { + if (!getVector) + return; + + val.clear(); + for (auto& [_, mat] : *getVector) + { + std::string sMat = mat.data(); + + bool bFound = false; // ensure no duplicates are assigned + for (auto& str : val) + { + if (str == sMat) + { + bFound = true; + break; + } + } + + if (!bFound) + val.push_back(mat.data()); + } + + // remove invalid materials + for (auto it = val.begin(); it != val.end();) + { + if (FNV1A::Hash(it->c_str()) == FNV1A::HashConst("None") || FNV1A::Hash(it->c_str()) != FNV1A::HashConst("Original") && !F::Materials.mChamMaterials.contains(*it)) + it = val.erase(it); + else + ++it; + } + }; + + getMaterials(val, mapTree.get_child_optional(name)); +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, Color_t& val) +{ + if (const auto getChild = mapTree.get_child_optional(name)) + { + TreeToColor(*getChild, val); + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, Gradient_t& val) +{ + if (const auto getChild = mapTree.get_child_optional(name)) + { + if (const auto getStartColor = getChild->get_child_optional("StartColor")) + TreeToColor(*getStartColor, val.StartColor); + if (const auto endColor = getChild->get_child_optional("EndColor")) + TreeToColor(*endColor, val.EndColor); + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, DragBox_t& val) +{ + if (const auto getChild = mapTree.get_child_optional(name)) + { + if (auto getValue = getChild->get_optional("x")) { val.x = *getValue; } + if (auto getValue = getChild->get_optional("y")) { val.y = *getValue; } + } +} + +void CConfigs::LoadJson(boost::property_tree::ptree& mapTree, const char* name, WindowBox_t& val) +{ + if (const auto getChild = mapTree.get_child_optional(name)) + { + if (auto getValue = getChild->get_optional("x")) { val.x = *getValue; } + if (auto getValue = getChild->get_optional("y")) { val.y = *getValue; } + if (auto getValue = getChild->get_optional("w")) { val.w = *getValue; } + if (auto getValue = getChild->get_optional("h")) { val.h = *getValue; } + } +} + +CConfigs::CConfigs() +{ + sConfigPath = std::filesystem::current_path().string() + "\\Amalgam"; + sVisualsPath = sConfigPath + "\\Visuals"; + + if (!std::filesystem::exists(sConfigPath)) + std::filesystem::create_directory(sConfigPath); + + if (!std::filesystem::exists(sVisualsPath)) + std::filesystem::create_directory(sVisualsPath); + + // Create 'Core' folder for Attribute-Changer & Playerlist + if (!std::filesystem::exists(sConfigPath + "\\Core")) + std::filesystem::create_directory(sConfigPath + "\\Core"); + + // Create 'Materials' folder for custom materials + if (!std::filesystem::exists(sConfigPath + "\\Materials")) + std::filesystem::create_directory(sConfigPath + "\\Materials"); +} + +#define IsType(type) var->m_iType == typeid(type).hash_code() +#define SaveType(type, tree)\ +{\ + boost::property_tree::ptree mapTree;\ + for (const auto& [cond, value] : var->GetVar()->Map)\ + SaveJson(mapTree, cond.c_str(), value);\ + tree.put_child(var->m_sName.c_str(), mapTree);\ +} +#define SaveT(type, tree) if (IsType(type)) SaveType(type, tree) +#define LoadType(type, tree)\ +{\ + var->GetVar()->Map = { { "default", var->GetVar()->Default } };\ + if (const auto mapTree = tree.get_child_optional(var->m_sName.c_str()))\ + {\ + for (auto& it : *mapTree)\ + {\ + if ((!F::Conditions.mConditions.contains(it.first) || var->GetVar()->m_iFlags & NOCOND) && FNV1A::Hash(it.first.c_str()) != FNV1A::HashConst("default"))\ + continue;\ + LoadJson(*mapTree, it.first.c_str(), var->GetVar()->Map[it.first]);\ + }\ + }\ +} +#define LoadT(type, tree) if (IsType(type)) LoadType(type, tree) + +bool CConfigs::SaveConfig(const std::string& configName, bool bNotify) +{ + try + { + boost::property_tree::ptree writeTree; + + boost::property_tree::ptree condTree; + for (const auto& sCond : F::Conditions.vConditions) + { + auto& tCond = F::Conditions.mConditions[sCond]; + + boost::property_tree::ptree condTree2; + condTree2.put("Type", tCond.Type); + condTree2.put("Info", tCond.Info); + condTree2.put("Key", tCond.Key); + condTree2.put("Not", tCond.Not); + condTree2.put("Active", tCond.Active); + condTree2.put("Visible", tCond.Visible); + condTree2.put("Parent", tCond.Parent); + + condTree.put_child(sCond, condTree2); + } + writeTree.put_child("Conditions", condTree); + + boost::property_tree::ptree varTree; + for (const auto var : g_Vars) + { + if (var->m_iFlags & NOSAVE) + continue; + + SaveT(bool, varTree) + else SaveT(int, varTree) + else SaveT(float, varTree) + else SaveT(IntRange_t, varTree) + else SaveT(FloatRange_t, varTree) + else SaveT(std::string, varTree) + else SaveT(std::vector, varTree) + else SaveT(Color_t, varTree) + else SaveT(Gradient_t, varTree) + else SaveT(DragBox_t, varTree) + else SaveT(WindowBox_t, varTree) + } + writeTree.put_child("ConVars", varTree); + + write_json(sConfigPath + "\\" + configName + sConfigExtension, writeTree); + sCurrentConfig = configName; sCurrentVisuals = ""; + if (bNotify) + F::Notifications.Add("Config " + configName + " saved"); + } + catch (...) + { + SDK::Output("F::Configs::SaveConfig()", "Failed", { 175, 150, 255, 255 }); + return false; + } + + return true; +} + +bool CConfigs::LoadConfig(const std::string& configName, bool bNotify) +{ + // Check if the config exists + if (!std::filesystem::exists(sConfigPath + "\\" + configName + sConfigExtension)) + { + // Save default config if one doesn't yet exist + if (configName == std::string("default")) + SaveConfig("default", false); + + return false; + } + + // Read ptree from json + try + { + boost::property_tree::ptree readTree; + read_json(sConfigPath + "\\" + configName + sConfigExtension, readTree); + + if (const auto condTree = readTree.get_child_optional("Conditions")) + { + F::Conditions.mConditions.clear(); + F::Conditions.vConditions.clear(); + + for (auto& it : *condTree) + { + if (FNV1A::Hash(it.first.c_str()) == FNV1A::HashConst("default")) + continue; + + Condition_t tCond = {}; + if (auto getValue = it.second.get_optional("Type")) { tCond.Type = *getValue; } + if (auto getValue = it.second.get_optional("Info")) { tCond.Info = *getValue; } + if (auto getValue = it.second.get_optional("Key")) { tCond.Key = *getValue; } + if (auto getValue = it.second.get_optional("Not")) { tCond.Not = *getValue; } + if (auto getValue = it.second.get_optional("Active")) { tCond.Active = *getValue; } + if (auto getValue = it.second.get_optional("Visible")) { tCond.Visible = *getValue; } + if (auto getValue = it.second.get_optional("Parent")) { tCond.Parent = *getValue; } + + F::Conditions.mConditions[it.first] = tCond; + F::Conditions.vConditions.push_back(it.first); + } + } + + if (const auto conVars = readTree.get_child_optional("ConVars")) + { + auto& varTree = *conVars; + for (const auto var : g_Vars) + { + if (var->m_iFlags & NOSAVE) + continue; + + LoadT(bool, varTree) + else LoadT(int, varTree) + else LoadT(float, varTree) + else LoadT(IntRange_t, varTree) + else LoadT(FloatRange_t, varTree) + else LoadT(std::string, varTree) + else LoadT(std::vector, varTree) + else LoadT(Color_t, varTree) + else LoadT(Gradient_t, varTree) + else LoadT(DragBox_t, varTree) + else LoadT(WindowBox_t, varTree) + } + } + + H::Fonts.Reload(); + + sCurrentConfig = configName; sCurrentVisuals = ""; + if (bNotify) + F::Notifications.Add("Config " + configName + " loaded"); + } + catch (...) + { + SDK::Output("F::Configs::LoadConfig()", "Failed", { 175, 150, 255, 255 }); + return false; + } + + return true; +} + +bool CConfigs::SaveVisual(const std::string& configName, bool bNotify) +{ + try + { + boost::property_tree::ptree writeTree; + + for (const auto var : g_Vars) + { + if (!(var->m_iFlags & VISUAL) || var->m_iFlags & NOSAVE) + continue; + + SaveT(bool, writeTree) + else SaveT(int, writeTree) + else SaveT(float, writeTree) + else SaveT(IntRange_t, writeTree) + else SaveT(FloatRange_t, writeTree) + else SaveT(std::string, writeTree) + else SaveT(std::vector, writeTree) + else SaveT(Color_t, writeTree) + else SaveT(Gradient_t, writeTree) + else SaveT(DragBox_t, writeTree) + else SaveT(WindowBox_t, writeTree) + } + + write_json(sConfigPath + "\\Visuals\\" + configName + sConfigExtension, writeTree); + if (bNotify) + F::Notifications.Add("Visual config " + configName + " saved"); + } + catch (...) + { + SDK::Output("F::Configs::SaveVisual()", "Failed", { 175, 150, 255, 255 }); + return false; + } + return true; +} + +bool CConfigs::LoadVisual(const std::string& configName, bool bNotify) +{ + // Check if the visual config exists + if (!std::filesystem::exists(sVisualsPath + "\\" + configName + sConfigExtension)) + { + //if (configName == std::string("default")) + // SaveVisual("default"); + return false; + } + + try + { + boost::property_tree::ptree readTree; + read_json(sConfigPath + "\\Visuals\\" + configName + sConfigExtension, readTree); + + for (const auto var : g_Vars) + { + if (!(var->m_iFlags & VISUAL) || var->m_iFlags & NOSAVE) + continue; + + LoadT(bool, readTree) + else LoadT(int, readTree) + else LoadT(float, readTree) + else LoadT(IntRange_t, readTree) + else LoadT(FloatRange_t, readTree) + else LoadT(std::string, readTree) + else LoadT(std::vector, readTree) + else LoadT(Color_t, readTree) + else LoadT(Gradient_t, readTree) + else LoadT(DragBox_t, readTree) + else LoadT(WindowBox_t, readTree) + } + + H::Fonts.Reload(); + + sCurrentVisuals = configName; + if (bNotify) + F::Notifications.Add("Visual config " + configName + " loaded"); + } + catch (...) + { + SDK::Output("F::Configs::LoadVisual()", "Failed", { 175, 150, 255, 255 }); + return false; + } + return true; +} + +#define ResetType(type) var->GetVar()->Map = { { "default", var->GetVar()->Default } }; +#define ResetT(type) if (IsType(type)) ResetType(type) + +void CConfigs::RemoveConfig(const std::string& configName) +{ + if (FNV1A::Hash(configName.c_str()) != FNV1A::HashConst("default")) + std::filesystem::remove(sConfigPath + "\\" + configName + sConfigExtension); + else + { + F::Conditions.mConditions.clear(); + F::Conditions.vConditions.clear(); + + for (const auto var : g_Vars) + { + if (var->m_iFlags & NOSAVE) + continue; + + ResetT(bool) + else ResetT(int) + else ResetT(float) + else ResetT(IntRange_t) + else ResetT(FloatRange_t) + else ResetT(std::string) + else ResetT(std::vector) + else ResetT(Color_t) + else ResetT(Gradient_t) + else ResetT(DragBox_t) + else ResetT(WindowBox_t) + } + + SaveConfig("default", false); + } +} + +void CConfigs::RemoveVisual(const std::string& configName) +{ + std::filesystem::remove(sVisualsPath + "\\" + configName + sConfigExtension); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Configs/Configs.h b/Amalgam/src/Features/Configs/Configs.h new file mode 100644 index 0000000..d8d0586 --- /dev/null +++ b/Amalgam/src/Features/Configs/Configs.h @@ -0,0 +1,54 @@ +#pragma once +#include "../../SDK/SDK.h" + +#include +#include +#include + +class CConfigs +{ + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, bool val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, int val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, float val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const IntRange_t& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const FloatRange_t& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::string& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const std::vector& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Color_t& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const Gradient_t& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const DragBox_t& val); + void SaveJson(boost::property_tree::ptree& mapTree, const char* name, const WindowBox_t& val); + + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, bool& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, int& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, float& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, IntRange_t& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, FloatRange_t& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::string& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, std::vector& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, Color_t& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, Gradient_t& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, DragBox_t& val); + void LoadJson(boost::property_tree::ptree& mapTree, const char* name, WindowBox_t& val); + +public: + CConfigs(); + + bool SaveConfig(const std::string& configName, bool bNotify = true); + bool LoadConfig(const std::string& configName, bool bNotify = true); + bool SaveVisual(const std::string& configName, bool bNotify = true); + bool LoadVisual(const std::string& configName, bool bNotify = true); + void RemoveConfig(const std::string& configName); + void RemoveVisual(const std::string& configName); + + boost::property_tree::ptree ColorToTree(const Color_t& color); + void TreeToColor(const boost::property_tree::ptree& tree, Color_t& out); + + std::string sCurrentConfig = "default"; + std::string sCurrentVisuals = "default"; + std::string sConfigPath; + std::string sVisualsPath; + const std::string sConfigExtension = ".json"; +}; + +ADD_FEATURE(CConfigs, Configs); \ No newline at end of file diff --git a/Amalgam/src/Features/CritHack/CritHack.cpp b/Amalgam/src/Features/CritHack/CritHack.cpp new file mode 100644 index 0000000..5a3464b --- /dev/null +++ b/Amalgam/src/Features/CritHack/CritHack.cpp @@ -0,0 +1,530 @@ +#include "CritHack.h" + +#include "../Aimbot/AutoRocketJump/AutoRocketJump.h" + +#define WEAPON_RANDOM_RANGE 10000 +#define TF_DAMAGE_CRIT_MULTIPLIER 3.0f +#define TF_DAMAGE_CRIT_CHANCE 0.02f +#define TF_DAMAGE_CRIT_CHANCE_RAPID 0.02f +#define TF_DAMAGE_CRIT_CHANCE_MELEE 0.15f +#define TF_DAMAGE_CRIT_DURATION_RAPID 2.0f + +void CCritHack::Fill(const CUserCmd* pCmd, int n) +{ + static int iStart = pCmd->command_number; + + for (auto& [iSlot, tStorage] : Storage) + { + for (auto it = tStorage.CritCommands.begin(); it != tStorage.CritCommands.end();) + { + if (*it <= pCmd->command_number) + it = tStorage.CritCommands.erase(it); + else + ++it; + } + for (auto it = tStorage.SkipCommands.begin(); it != tStorage.SkipCommands.end();) + { + if (*it <= pCmd->command_number) + it = tStorage.SkipCommands.erase(it); + else + ++it; + } + + for (int i = 0; i < n; i++) + { + if (tStorage.CritCommands.size() >= unsigned(n)) + break; + + const int iCmdNum = iStart + i; + if (IsCritCommand(iSlot, tStorage.EntIndex, iCmdNum)) + tStorage.CritCommands.push_back(iCmdNum); + } + for (int i = 0; i < n; i++) + { + if (tStorage.SkipCommands.size() >= unsigned(n)) + break; + + const int iCmdNum = iStart + i; + if (IsCritCommand(iSlot, tStorage.EntIndex, iCmdNum, false)) + tStorage.SkipCommands.push_back(iCmdNum); + } + } + + iStart += n; +} + + + +bool CCritHack::IsCritCommand(int iSlot, int iIndex, const i32 command_number, const bool bCrit, const bool bSafe) +{ + const auto uSeed = MD5_PseudoRandom(command_number) & 0x7FFFFFFF; + SDK::RandomSeed(DecryptOrEncryptSeed(iSlot, iIndex, uSeed)); + const int iRandom = SDK::RandomInt(0, WEAPON_RANDOM_RANGE - 1); + + if (bSafe) + return bCrit ? iRandom < 100 : !(iRandom < 6000); + else + { + const int iRange = (CritChance - 0.1f) * WEAPON_RANDOM_RANGE; + return bCrit ? iRandom < iRange : !(iRandom < iRange); + } +} + +u32 CCritHack::DecryptOrEncryptSeed(int iSlot, int iIndex, u32 uSeed) +{ + int iLeft = iSlot == SLOT_MELEE ? 8 : 0; + unsigned int iMask = iIndex << (iLeft + 8) | I::EngineClient->GetLocalPlayer() << iLeft; + return iMask ^ uSeed; +} + + + +void CCritHack::GetTotalCrits(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + const int iSlot = pWeapon->m_iSlot(); + + static float flOldBucket = 0.f; static int iOldID = 0, iOldCritChecks = 0, iOldCritSeedRequests = 0; + const float flBucket = pWeapon->m_flCritTokenBucket(); const int iID = pWeapon->m_iWeaponID(), iCritChecks = pWeapon->m_nCritChecks(), iCritSeedRequests = pWeapon->m_nCritSeedRequests(); + const bool bMatch = Storage[iSlot].Damage > 0 && flOldBucket == flBucket && iOldID == iID && iOldCritChecks == iCritChecks && iOldCritSeedRequests == iCritSeedRequests; + + auto tfWeaponInfo = pWeapon->GetWeaponInfo(); + if (bMatch || !tfWeaponInfo) + return; + flOldBucket = flBucket; iOldID = iID, iOldCritChecks = iCritChecks, iOldCritSeedRequests = iCritSeedRequests; + + static auto bucketCap = U::ConVars.FindVar("tf_weapon_criticals_bucket_cap"); + const float flBucketCap = bucketCap ? bucketCap->GetFloat() : 1000.f; + + auto& tWeaponData = tfWeaponInfo->GetWeaponData(0); + + float flDamage = tWeaponData.m_nDamage; + flDamage = SDK::AttribHookValue(flDamage, "mult_dmg", pWeapon); + int nProjectilesPerShot = tWeaponData.m_nBulletsPerShot; + if (nProjectilesPerShot >= 1) + nProjectilesPerShot = SDK::AttribHookValue(nProjectilesPerShot, "mult_bullets_per_shot", pWeapon); + else + nProjectilesPerShot = 1; + Storage[iSlot].Damage = flDamage *= nProjectilesPerShot; + + if (pWeapon->IsStreamingWeapon()) + { + flDamage *= TF_DAMAGE_CRIT_DURATION_RAPID / tWeaponData.m_flTimeFireDelay; + if (flDamage * TF_DAMAGE_CRIT_MULTIPLIER > flBucketCap) + flDamage = flBucketCap / TF_DAMAGE_CRIT_MULTIPLIER; + } + + float flMult = iSlot == SLOT_MELEE ? 0.5f : Math::RemapValClamped(float(iCritSeedRequests + 1) / (iCritChecks + 1), 0.1f, 1.f, 1.f, 3.f); + Storage[iSlot].Cost = flDamage * TF_DAMAGE_CRIT_MULTIPLIER * flMult; + + if (flBucketCap) + Storage[iSlot].PotentialCrits = (flBucketCap - Storage[iSlot].Damage) / (3 * flDamage / (iSlot == SLOT_MELEE ? 2 : 1) - Storage[iSlot].Damage); + + int iCrits = 0; + { + int shots = iCritChecks, crits = iCritSeedRequests; + float bucket = flBucket, flCost = flDamage * TF_DAMAGE_CRIT_MULTIPLIER; + const int iAttempts = std::min(Storage[iSlot].PotentialCrits + 1, 100); + for (int i = 0; i < iAttempts; i++) + { + shots++; crits++; + + flMult = iSlot == SLOT_MELEE ? 0.5f : Math::RemapValClamped(float(crits) / shots, 0.1f, 1.f, 1.f, 3.f); + bucket = std::min(bucket + Storage[iSlot].Damage, flBucketCap) - flCost * flMult; + if (bucket < 0.f) + break; + + iCrits++; + } + } + + if (!iCrits) + { + int shots = iCritChecks + 1, crits = iCritSeedRequests + 1; + float bucket = std::min(flBucket + Storage[iSlot].Damage, flBucketCap), flCost = flDamage * TF_DAMAGE_CRIT_MULTIPLIER; + for (int i = 0; i < 100; i++) + { + iCrits--; + if (!pWeapon->IsStreamingWeapon() || !(i % int(tWeaponData.m_flTimeFireDelay / TICK_INTERVAL))) + shots++; + + flMult = iSlot == SLOT_MELEE ? 0.5f : Math::RemapValClamped(float(crits) / shots, 0.1f, 1.f, 1.f, 3.f); + bucket = std::min(bucket + Storage[iSlot].Damage, flBucketCap); + if (bucket >= flCost * flMult) + break; + } + } + + Storage[iSlot].AvailableCrits = iCrits; +} + +void CCritHack::CanFireCritical(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + CritBanned = false; + DamageTilUnban = 0; + + if (pWeapon->m_iSlot() == SLOT_MELEE) + CritChance = TF_DAMAGE_CRIT_CHANCE_MELEE * pLocal->GetCritMult(); + else if (pWeapon->IsStreamingWeapon()) + { + CritChance = TF_DAMAGE_CRIT_CHANCE_RAPID * pLocal->GetCritMult(); + float flNonCritDuration = (TF_DAMAGE_CRIT_DURATION_RAPID / CritChance) - TF_DAMAGE_CRIT_DURATION_RAPID; + CritChance = 1.f / flNonCritDuration; + } + else + CritChance = TF_DAMAGE_CRIT_CHANCE * pLocal->GetCritMult(); + CritChance = SDK::AttribHookValue(CritChance, "mult_crit_chance", pWeapon) + 0.1f; + + if (!AllDamage || !CritDamage || pWeapon->m_iSlot() == SLOT_MELEE) + return; + + const float flNormalizedDamage = (float)CritDamage / TF_DAMAGE_CRIT_MULTIPLIER; + const float flObservedCritChance = flNormalizedDamage / (flNormalizedDamage + AllDamage - CritDamage); + if (CritBanned = flObservedCritChance > CritChance) + DamageTilUnban = flNormalizedDamage / CritChance + CritDamage - flNormalizedDamage - AllDamage; +} + +bool CCritHack::WeaponCanCrit(CTFWeaponBase* pWeapon) +{ + static auto tf_weapon_criticals = U::ConVars.FindVar("tf_weapon_criticals"); + if (!tf_weapon_criticals || !tf_weapon_criticals->GetBool()) + return false; + + if (SDK::AttribHookValue(1.f, "mult_crit_chance", pWeapon) <= 0.f) + return false; + + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_PDA: + case TF_WEAPON_PDA_ENGINEER_BUILD: + case TF_WEAPON_PDA_ENGINEER_DESTROY: + case TF_WEAPON_PDA_SPY: + case TF_WEAPON_PDA_SPY_BUILD: + case TF_WEAPON_BUILDER: + case TF_WEAPON_INVIS: + case TF_WEAPON_GRAPPLINGHOOK: + case TF_WEAPON_JAR_MILK: + case TF_WEAPON_LUNCHBOX: + case TF_WEAPON_BUFF_ITEM: + case TF_WEAPON_FLAME_BALL: + case TF_WEAPON_ROCKETPACK: + case TF_WEAPON_JAR_GAS: + case TF_WEAPON_LASER_POINTER: + case TF_WEAPON_MEDIGUN: + case TF_WEAPON_SNIPERRIFLE: + case TF_WEAPON_SNIPERRIFLE_DECAP: + case TF_WEAPON_SNIPERRIFLE_CLASSIC: + case TF_WEAPON_COMPOUND_BOW: + case TF_WEAPON_JAR: + case TF_WEAPON_KNIFE: + return false; + } + + return true; +} + + + +void CCritHack::ResetWeapons(CTFPlayer* pLocal) +{ + std::unordered_map mWeapons = {}; + auto hWeapons = pLocal->GetMyWeapons(); + if (!hWeapons) + return; + + for (size_t i = 0; hWeapons[i]; i++) + { + if (SDK::HandleToIDX(unsigned(hWeapons[i])) < 0 || SDK::HandleToIDX(unsigned(hWeapons[i])) >= 2048) + continue; + + if (const auto pWeapon = I::ClientEntityList->GetClientEntityFromHandle(unsigned(hWeapons[i]))->As()) + { + const int iSlot = pWeapon->m_iSlot(); + const int iDefIndex = pWeapon->m_iItemDefinitionIndex(); + mWeapons[iSlot] = true; + + if (Storage[iSlot].DefIndex == iDefIndex) + continue; + + Storage[iSlot] = {}; + Storage[iSlot].EntIndex = pWeapon->entindex(); + Storage[iSlot].DefIndex = iDefIndex; + + SDK::Output("Crithack", std::format("Resetting weapon {}", iDefIndex).c_str(), { 0, 255, 255, 255 }, Vars::Debug::Logging.Value); + } + } + + for (auto& [iSlot, _] : Storage) + { + if (!mWeapons[iSlot]) + Storage[iSlot] = {}; + } +} + +void CCritHack::Reset() +{ + Storage = {}; + + CritDamage = 0; + AllDamage = 0; + + CritBanned = false; + DamageTilUnban = 0; + CritChance = 0.f; + + SDK::Output("Crithack", "Resetting all", { 0, 255, 255, 255 }, Vars::Debug::Logging.Value); +} + + + +void CCritHack::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (!pLocal || !pWeapon || !pLocal->IsAlive() || !I::EngineClient->IsInGame()) + return; + + ResetWeapons(pLocal); + Fill(pCmd, 15); + GetTotalCrits(pLocal, pWeapon); + CanFireCritical(pLocal, pWeapon); + if (pLocal->IsCritBoosted() || !WeaponCanCrit(pWeapon)) + return; + + if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN && pCmd->buttons & IN_ATTACK) + pCmd->buttons &= ~IN_ATTACK2; + + bool bAttacking = G::IsAttacking; + if (G::WeaponType == EWeaponType::MELEE) + { + bAttacking = G::CanPrimaryAttack && pCmd->buttons & IN_ATTACK; + if (!bAttacking && pWeapon->m_iWeaponID() == TF_WEAPON_FISTS) + bAttacking = G::CanPrimaryAttack && pCmd->buttons & IN_ATTACK2; + } + if (pWeapon->m_iWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER || pWeapon->m_iWeaponID() == TF_WEAPON_STICKY_BALL_LAUNCHER || pWeapon->m_iWeaponID() == TF_WEAPON_GRENADE_STICKY_BALL + || pWeapon->m_iWeaponID() == TF_WEAPON_CANNON) + { + static float flBegin = -1.f; + if (pCmd->buttons& IN_ATTACK&& flBegin < 0.f && G::CanPrimaryAttack) + flBegin = I::GlobalVars->curtime; + + const float flCharge = flBegin > 0.f ? I::GlobalVars->curtime - flBegin : 0.f; + const float flAmount = pWeapon->m_iWeaponID() != TF_WEAPON_CANNON + ? Math::RemapValClamped(flCharge, 0.f, SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon), 0.f, 1.f) + : Math::RemapValClamped(flCharge, 0.f, SDK::AttribHookValue(0.f, "grenade_launcher_mortar_mode", pWeapon), 0.f, 1.f); + + const bool bUnheld = !(pCmd->buttons & IN_ATTACK) && flAmount > 0.f; + const bool bSwapping = pCmd->weaponselect; + const bool bFull = flAmount == 1.f; // possibly add exception to skip when full with cannon + + bAttacking = (bUnheld || bFull) && !bSwapping; + if (bAttacking || !G::CanPrimaryAttack || bSwapping) + flBegin = -1.f; + } + if ((pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN || pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER) && !(G::LastUserCmd->buttons & IN_ATTACK)) // silly + bAttacking = false; + + const int iSlot = pWeapon->m_iSlot(); + if (Storage[iSlot].StreamWait <= I::GlobalVars->tickcount - 1) + Storage[pWeapon->m_iSlot()].StreamWait = -1; + + const bool bRapidFire = pWeapon->IsStreamingWeapon(); + const bool bStreamWait = Storage[iSlot].StreamWait > 0; + //const bool bStreamWait = pWeapon->IsStreamingWeapon() && pWeapon->LastRapidfireCritCheckTime() + 1.f > TICK_INTERVAL * pLocal->m_nTickBase(); + + const int closestCrit = !Storage[iSlot].CritCommands.empty() ? Storage[iSlot].CritCommands.front() : 0; + const int closestSkip = !Storage[iSlot].SkipCommands.empty() ? Storage[iSlot].SkipCommands.front() : 0; + + static bool bFirstTimePredicted = false; + if (!I::ClientState->chokedcommands) + bFirstTimePredicted = false; + if (bAttacking && !pWeapon->IsInReload() && !bFirstTimePredicted) + { + bFirstTimePredicted = true; + + const bool bCanCrit = Storage[pWeapon->m_iSlot()].AvailableCrits > 0 && (!CritBanned || pWeapon->m_iSlot() == SLOT_MELEE) && !bStreamWait; + const bool bPressed = Vars::CritHack::ForceCrits.Value || pWeapon->m_iSlot() == SLOT_MELEE && Vars::CritHack::AlwaysMelee.Value; + if (bCanCrit && bPressed && closestCrit) + pCmd->command_number = closestCrit; + else if (Vars::CritHack::AvoidRandom.Value && closestSkip) + pCmd->command_number = closestSkip; + + if (bRapidFire && !bStreamWait) + Storage[pWeapon->m_iSlot()].StreamWait = I::GlobalVars->tickcount + 1 / TICK_INTERVAL; + } + //else if (Vars::CritHack::AvoidRandom.Value && closestSkip) + // pCmd->command_number = closestSkip; + + //if (pCmd->command_number == closestCrit || pCmd->command_number == closestSkip) + WishRandomSeed = MD5_PseudoRandom(pCmd->command_number) & 0x7FFFFFFF; + + if (pCmd->command_number == closestCrit) + Storage[iSlot].CritCommands.pop_front(); + else if (pCmd->command_number == closestSkip) + Storage[iSlot].SkipCommands.pop_front(); +} + +bool CCritHack::CalcIsAttackCriticalHandler(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (!I::Prediction->m_bFirstTimePredicted || !pLocal || !pWeapon) + return false; + + if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN || pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER) + { + static int iOldAmmo = pLocal->GetAmmoCount(pWeapon->m_iPrimaryAmmoType()); + const int iNewAmmo = pLocal->GetAmmoCount(pWeapon->m_iPrimaryAmmoType()); + + const bool bFired = iOldAmmo != iNewAmmo; + + iOldAmmo = iNewAmmo; + + if (!bFired) + return false; + } + + if (WishRandomSeed) + { + *G::RandomSeed() = WishRandomSeed; + WishRandomSeed = 0; + } + + return true; +} + +void CCritHack::Event(IGameEvent* pEvent, FNV1A_t uHash, CTFPlayer* pLocal) +{ + switch (uHash) + { + case FNV1A::HashConst("player_hurt"): + { + auto pWeapon = H::Entities.GetWeapon(); + if (!pLocal || !pWeapon) + return; + + const int iVictim = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid")); + const int iAttacker = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("attacker")); + + const bool bCrit = pEvent->GetBool("crit") || pEvent->GetBool("minicrit"); + int iDamage = pEvent->GetInt("damageamount"); + if (mHealthStorage.contains(iVictim)) + iDamage = std::min(iDamage, mHealthStorage[iVictim]); + const auto iWeaponID = pEvent->GetInt("weaponid"); + + if (iVictim == iAttacker || iAttacker != pLocal->entindex() || iWeaponID != pWeapon->m_iWeaponID() || pWeapon->m_iSlot() == SLOT_MELEE) // weapon id stuff is dumb simplification + return; + + AllDamage += iDamage; + if (bCrit && !pLocal->IsCritBoosted()) + CritDamage += iDamage; + + return; + } + case FNV1A::HashConst("teamplay_round_start"): + AllDamage = CritDamage = 0; + return; + case FNV1A::HashConst("client_beginconnect"): + case FNV1A::HashConst("client_disconnect"): + case FNV1A::HashConst("game_newmap"): + Reset(); + } +} + +void CCritHack::Store() +{ + auto pResource = H::Entities.GetPR(); + if (!pResource) + return; + + for (auto it = mHealthStorage.begin(); it != mHealthStorage.end();) + { + if (I::ClientEntityList->GetClientEntity(it->first)) + ++it; + else + it = mHealthStorage.erase(it); + } + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (pPlayer->IsAlive() && !pPlayer->IsAGhost()) + mHealthStorage[pPlayer->entindex()] = pPlayer->IsDormant() ? pResource->GetHealth(pPlayer->entindex()) : pPlayer->m_iHealth(); + } +} + +void CCritHack::Draw(CTFPlayer* pLocal) +{ + static auto tf_weapon_criticals = U::ConVars.FindVar("tf_weapon_criticals"); + const bool bWeaponCriticals = tf_weapon_criticals ? tf_weapon_criticals->GetBool() : true; + if (!(Vars::Menu::Indicators.Value & (1 << 1)) || !I::EngineClient->IsInGame() || !bWeaponCriticals || !G::CurrentUserCmd) + return; + + auto pWeapon = H::Entities.GetWeapon(); + if (!pWeapon || !pLocal->IsAlive() || pLocal->IsAGhost()) + return; + + int x = Vars::Menu::CritsDisplay.Value.x; + int y = Vars::Menu::CritsDisplay.Value.y + 8; + + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + EAlign align = ALIGN_TOP; + if (x <= (100 + 50 * Vars::Menu::DPI.Value)) + { + x -= 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPLEFT; + } + else if (x >= H::Draw.m_nScreenW - (100 + 50 * Vars::Menu::DPI.Value)) + { + x += 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPRIGHT; + } + + if (WeaponCanCrit(pWeapon)) + { + const auto iSlot = pWeapon->m_iSlot(); + const auto bRapidFire = pWeapon->IsStreamingWeapon(); + + if (Storage[iSlot].Damage > 0) + { + if (pLocal->IsCritBoosted()) + H::Draw.String(fFont, x, y, { 100, 255, 255, 255 }, align, "Crit Boosted"); + else if (pWeapon->m_flCritTime() > TICK_INTERVAL * pLocal->m_nTickBase()) + { + const float flTime = pWeapon->m_flCritTime() - TICK_INTERVAL * pLocal->m_nTickBase(); + H::Draw.String(fFont, x, y, { 100, 255, 255, 255 }, align, std::format("Streaming crits {:.1f}s", flTime).c_str()); + } + else if (!CritBanned) + { + if (Storage[iSlot].AvailableCrits > 0) + { + if (bRapidFire && Storage[iSlot].StreamWait > 0) + { + //const float flTime = std::max((TICKS_TO_TIME(Storage[iSlot].StreamWait - pLocal->m_nTickBase())), 0.f); + const float flTime = pWeapon->m_flLastRapidFireCritCheckTime() + 1.f - TICK_INTERVAL * pLocal->m_nTickBase(); + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, std::format("Wait {:.1f}s", flTime).c_str()); + } + else + H::Draw.String(fFont, x, y, { 150, 255, 150, 255 }, align, "Crit Ready"); + } + else + { + const int shots = -Storage[iSlot].AvailableCrits; + H::Draw.String(fFont, x, y, { 255, 150, 150, 255 }, align, shots == 1 ? std::format("Crit in {} shot", shots).c_str() : std::format("Crit in {}{} shots", shots, shots == 100 ? "+" : "").c_str()); + } + } + else + H::Draw.String(fFont, x, y, { 255, 150, 150, 255 }, align, std::format("Deal {} damage", DamageTilUnban).c_str()); + + H::Draw.String(fFont, x, y + fFont.m_nTall + 1, Vars::Menu::Theme::Active.Value, align, std::format("{} / {} potential crits", std::max(Storage[iSlot].AvailableCrits, 0), Storage[iSlot].PotentialCrits).c_str()); + } + else + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "Calculating"); + + if (Vars::Debug::Info.Value) + { + H::Draw.String(fFont, x, y + fFont.m_nTall * 3, { 255, 255, 255, 255 }, align, std::format("AllDamage: {}, CritDamage: {}", AllDamage, CritDamage).c_str()); + H::Draw.String(fFont, x, y + fFont.m_nTall * 4, { 255, 255, 255, 255 }, align, std::format("Bucket: {}", pWeapon->m_flCritTokenBucket()).c_str()); + H::Draw.String(fFont, x, y + fFont.m_nTall * 5, { 255, 255, 255, 255 }, align, std::format("Damage: {}, Cost: {}", Storage[iSlot].Damage, Storage[iSlot].Cost).c_str()); + H::Draw.String(fFont, x, y + fFont.m_nTall * 6, { 255, 255, 255, 255 }, align, std::format("Shots: {}, Crits: {}", pWeapon->m_nCritChecks(), pWeapon->m_nCritSeedRequests()).c_str()); + H::Draw.String(fFont, x, y + fFont.m_nTall * 7, { 255, 255, 255, 255 }, align, std::format("CritBanned: {}, DamageTilUnban: {}", CritBanned, DamageTilUnban).c_str()); + H::Draw.String(fFont, x, y + fFont.m_nTall * 8, { 255, 255, 255, 255 }, align, std::format("CritChance: {:.2f} ({:.2f})", CritChance, CritChance - 0.1f).c_str()); + H::Draw.String(fFont, x, y + fFont.m_nTall * 9, { 255, 255, 255, 255 }, align, std::format("Force: {}, Skip: {}", Storage[iSlot].CritCommands.size(), Storage[iSlot].SkipCommands.size()).c_str()); + } + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/CritHack/CritHack.h b/Amalgam/src/Features/CritHack/CritHack.h new file mode 100644 index 0000000..09efd7c --- /dev/null +++ b/Amalgam/src/Features/CritHack/CritHack.h @@ -0,0 +1,56 @@ +#pragma once +#include "../../SDK/SDK.h" + +typedef int i32; +typedef unsigned int u32; + +struct WeaponStorage +{ + float Damage = 0.f; + float Cost = 0.f; + int AvailableCrits = 0; + int PotentialCrits = 0; + int StreamWait = -1; + + int EntIndex = -1; + int DefIndex = -1; + + std::deque CritCommands = {}; + std::deque SkipCommands = {}; +}; + +class CCritHack +{ +private: + void Fill(const CUserCmd* pCmd, int n = 10); + + bool IsCritCommand(int iSlot, int iIndex, const i32 command_number, const bool bCrit = true, const bool bSafe = true); + u32 DecryptOrEncryptSeed(int iSlot, int iIndex, const u32 uSeed); + + void GetTotalCrits(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + void CanFireCritical(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + bool WeaponCanCrit(CTFWeaponBase* pWeapon); + + void ResetWeapons(CTFPlayer* pLocal); + void Reset(); + + int CritDamage = 0.f; + int AllDamage = 0.f; + std::unordered_map mHealthStorage = {}; + + bool CritBanned = false; + int DamageTilUnban = 0; + float CritChance = 0.f; + int WishRandomSeed = 0; + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + bool CalcIsAttackCriticalHandler(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + void Event(IGameEvent* pEvent, FNV1A_t uHash, CTFPlayer* pLocal); + void Store(); + void Draw(CTFPlayer* pLocal); + + std::unordered_map Storage = {}; +}; + +ADD_FEATURE(CCritHack, CritHack) \ No newline at end of file diff --git a/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp b/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp new file mode 100644 index 0000000..9565fca --- /dev/null +++ b/Amalgam/src/Features/EnginePrediction/EnginePrediction.cpp @@ -0,0 +1,85 @@ +#include "EnginePrediction.h" + +#include "../TickHandler/TickHandler.h" + +int CEnginePrediction::GetTickbase(CUserCmd* pCmd, CTFPlayer* pLocal) +{ + static int nTick = 0; + static CUserCmd* pLastCmd = nullptr; + + if (pCmd) + { + if (!pLastCmd || pLastCmd->hasbeenpredicted) + nTick = pLocal->m_nTickBase(); + else + nTick++; + pLastCmd = pCmd; + } + + return nTick; +} + +void CEnginePrediction::Simulate(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!pLocal || !pLocal->IsAlive() || !I::MoveHelper) + return; + + pLocal->SetCurrentCmd(pCmd); + + *G::RandomSeed() = MD5_PseudoRandom(pCmd->command_number) & std::numeric_limits::max(); + + const int nOldTickBase = pLocal->m_nTickBase(); + const bool bOldIsFirstPrediction = I::Prediction->m_bFirstTimePredicted; + const bool bOldInPrediction = I::Prediction->m_bInPrediction; + + I::Prediction->m_bFirstTimePredicted = false; + I::Prediction->m_bInPrediction = true; + + I::Prediction->SetLocalViewAngles(pCmd->viewangles); + + I::Prediction->SetupMove(pLocal, pCmd, I::MoveHelper, &m_MoveData); + I::GameMovement->ProcessMovement(pLocal, &m_MoveData); + I::Prediction->FinishMove(pLocal, pCmd, &m_MoveData); + + pLocal->m_nTickBase() = nOldTickBase; + I::Prediction->m_bFirstTimePredicted = bOldIsFirstPrediction; + I::Prediction->m_bInPrediction = bOldInPrediction; +} + +void CEnginePrediction::Start(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!pLocal || !pLocal->IsAlive()) + return; + + m_nOldTickCount = I::GlobalVars->tickcount; + m_fOldCurrentTime = I::GlobalVars->curtime; + m_fOldFrameTime = I::GlobalVars->frametime; + + I::GlobalVars->tickcount = GetTickbase(pCmd, pLocal); + I::GlobalVars->curtime = TICKS_TO_TIME(I::GlobalVars->tickcount); + I::GlobalVars->frametime = I::Prediction->m_bEnginePaused ? 0.0f : TICK_INTERVAL; + + bSimulated = false; + if (F::Ticks.GetTicks(pLocal) && Vars::CL_Move::Doubletap::AntiWarp.Value && pLocal->OnSolid()) + return; // hopefully more accurate eyepos while dting + + bSimulated = true; + Simulate(pLocal, pCmd); +} + +void CEnginePrediction::End(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!pLocal || !pLocal->IsAlive()) + return; + + I::GlobalVars->tickcount = m_nOldTickCount; + I::GlobalVars->curtime = m_fOldCurrentTime; + I::GlobalVars->frametime = m_fOldFrameTime; + + pLocal->SetCurrentCmd(nullptr); + + *G::RandomSeed() = -1; + + if (!bSimulated) + Simulate(pLocal, pCmd); +} \ No newline at end of file diff --git a/Amalgam/src/Features/EnginePrediction/EnginePrediction.h b/Amalgam/src/Features/EnginePrediction/EnginePrediction.h new file mode 100644 index 0000000..c58a3ed --- /dev/null +++ b/Amalgam/src/Features/EnginePrediction/EnginePrediction.h @@ -0,0 +1,24 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CEnginePrediction +{ +private: + CMoveData m_MoveData = {}; + +private: + int GetTickbase(CUserCmd* pCmd, CTFPlayer* pLocal); + void Simulate(CTFPlayer* pLocal, CUserCmd* pCmd); + + int m_nOldTickCount = 0; + float m_fOldCurrentTime = 0.f; + float m_fOldFrameTime = 0.f; + + bool bSimulated = false; + +public: + void Start(CTFPlayer* pLocal, CUserCmd* pCmd); + void End(CTFPlayer* pLocal, CUserCmd* pCmd); +}; + +ADD_FEATURE(CEnginePrediction, EnginePrediction) \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/MaterialDesign/IconDefinitions.h b/Amalgam/src/Features/ImGui/MaterialDesign/IconDefinitions.h new file mode 100644 index 0000000..6798a02 --- /dev/null +++ b/Amalgam/src/Features/ImGui/MaterialDesign/IconDefinitions.h @@ -0,0 +1,2244 @@ +// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++ +// from https://github.com/google/material-design-icons/raw/master/font/MaterialIcons-Regular.codepoints +// for use with https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf +#pragma once + +#define FONT_ICON_FILE_NAME_MD "MaterialIcons-Regular.ttf" + +#define ICON_MIN_MD 0xe000 +#define ICON_MAX_16_MD 0xf8ff +#define ICON_MAX_MD 0x10fffd +#define ICON_MD_10K "\xee\xa5\x91" // U+e951 +#define ICON_MD_10MP "\xee\xa5\x92" // U+e952 +#define ICON_MD_11MP "\xee\xa5\x93" // U+e953 +#define ICON_MD_123 "\xee\xae\x8d" // U+eb8d +#define ICON_MD_12MP "\xee\xa5\x94" // U+e954 +#define ICON_MD_13MP "\xee\xa5\x95" // U+e955 +#define ICON_MD_14MP "\xee\xa5\x96" // U+e956 +#define ICON_MD_15MP "\xee\xa5\x97" // U+e957 +#define ICON_MD_16MP "\xee\xa5\x98" // U+e958 +#define ICON_MD_17MP "\xee\xa5\x99" // U+e959 +#define ICON_MD_18_UP_RATING "\xef\xa3\xbd" // U+f8fd +#define ICON_MD_18MP "\xee\xa5\x9a" // U+e95a +#define ICON_MD_19MP "\xee\xa5\x9b" // U+e95b +#define ICON_MD_1K "\xee\xa5\x9c" // U+e95c +#define ICON_MD_1K_PLUS "\xee\xa5\x9d" // U+e95d +#define ICON_MD_1X_MOBILEDATA "\xee\xbf\x8d" // U+efcd +#define ICON_MD_20MP "\xee\xa5\x9e" // U+e95e +#define ICON_MD_21MP "\xee\xa5\x9f" // U+e95f +#define ICON_MD_22MP "\xee\xa5\xa0" // U+e960 +#define ICON_MD_23MP "\xee\xa5\xa1" // U+e961 +#define ICON_MD_24MP "\xee\xa5\xa2" // U+e962 +#define ICON_MD_2K "\xee\xa5\xa3" // U+e963 +#define ICON_MD_2K_PLUS "\xee\xa5\xa4" // U+e964 +#define ICON_MD_2MP "\xee\xa5\xa5" // U+e965 +#define ICON_MD_30FPS "\xee\xbf\x8e" // U+efce +#define ICON_MD_30FPS_SELECT "\xee\xbf\x8f" // U+efcf +#define ICON_MD_360 "\xee\x95\xb7" // U+e577 +#define ICON_MD_3D_ROTATION "\xee\xa1\x8d" // U+e84d +#define ICON_MD_3G_MOBILEDATA "\xee\xbf\x90" // U+efd0 +#define ICON_MD_3K "\xee\xa5\xa6" // U+e966 +#define ICON_MD_3K_PLUS "\xee\xa5\xa7" // U+e967 +#define ICON_MD_3MP "\xee\xa5\xa8" // U+e968 +#define ICON_MD_3P "\xee\xbf\x91" // U+efd1 +#define ICON_MD_4G_MOBILEDATA "\xee\xbf\x92" // U+efd2 +#define ICON_MD_4G_PLUS_MOBILEDATA "\xee\xbf\x93" // U+efd3 +#define ICON_MD_4K "\xee\x81\xb2" // U+e072 +#define ICON_MD_4K_PLUS "\xee\xa5\xa9" // U+e969 +#define ICON_MD_4MP "\xee\xa5\xaa" // U+e96a +#define ICON_MD_5G "\xee\xbc\xb8" // U+ef38 +#define ICON_MD_5K "\xee\xa5\xab" // U+e96b +#define ICON_MD_5K_PLUS "\xee\xa5\xac" // U+e96c +#define ICON_MD_5MP "\xee\xa5\xad" // U+e96d +#define ICON_MD_60FPS "\xee\xbf\x94" // U+efd4 +#define ICON_MD_60FPS_SELECT "\xee\xbf\x95" // U+efd5 +#define ICON_MD_6_FT_APART "\xef\x88\x9e" // U+f21e +#define ICON_MD_6K "\xee\xa5\xae" // U+e96e +#define ICON_MD_6K_PLUS "\xee\xa5\xaf" // U+e96f +#define ICON_MD_6MP "\xee\xa5\xb0" // U+e970 +#define ICON_MD_7K "\xee\xa5\xb1" // U+e971 +#define ICON_MD_7K_PLUS "\xee\xa5\xb2" // U+e972 +#define ICON_MD_7MP "\xee\xa5\xb3" // U+e973 +#define ICON_MD_8K "\xee\xa5\xb4" // U+e974 +#define ICON_MD_8K_PLUS "\xee\xa5\xb5" // U+e975 +#define ICON_MD_8MP "\xee\xa5\xb6" // U+e976 +#define ICON_MD_9K "\xee\xa5\xb7" // U+e977 +#define ICON_MD_9K_PLUS "\xee\xa5\xb8" // U+e978 +#define ICON_MD_9MP "\xee\xa5\xb9" // U+e979 +#define ICON_MD_ABC "\xee\xae\x94" // U+eb94 +#define ICON_MD_AC_UNIT "\xee\xac\xbb" // U+eb3b +#define ICON_MD_ACCESS_ALARM "\xee\x86\x90" // U+e190 +#define ICON_MD_ACCESS_ALARMS "\xee\x86\x91" // U+e191 +#define ICON_MD_ACCESS_TIME "\xee\x86\x92" // U+e192 +#define ICON_MD_ACCESS_TIME_FILLED "\xee\xbf\x96" // U+efd6 +#define ICON_MD_ACCESSIBILITY "\xee\xa1\x8e" // U+e84e +#define ICON_MD_ACCESSIBILITY_NEW "\xee\xa4\xac" // U+e92c +#define ICON_MD_ACCESSIBLE "\xee\xa4\x94" // U+e914 +#define ICON_MD_ACCESSIBLE_FORWARD "\xee\xa4\xb4" // U+e934 +#define ICON_MD_ACCOUNT_BALANCE "\xee\xa1\x8f" // U+e84f +#define ICON_MD_ACCOUNT_BALANCE_WALLET "\xee\xa1\x90" // U+e850 +#define ICON_MD_ACCOUNT_BOX "\xee\xa1\x91" // U+e851 +#define ICON_MD_ACCOUNT_CIRCLE "\xee\xa1\x93" // U+e853 +#define ICON_MD_ACCOUNT_TREE "\xee\xa5\xba" // U+e97a +#define ICON_MD_AD_UNITS "\xee\xbc\xb9" // U+ef39 +#define ICON_MD_ADB "\xee\x98\x8e" // U+e60e +#define ICON_MD_ADD "\xee\x85\x85" // U+e145 +#define ICON_MD_ADD_A_PHOTO "\xee\x90\xb9" // U+e439 +#define ICON_MD_ADD_ALARM "\xee\x86\x93" // U+e193 +#define ICON_MD_ADD_ALERT "\xee\x80\x83" // U+e003 +#define ICON_MD_ADD_BOX "\xee\x85\x86" // U+e146 +#define ICON_MD_ADD_BUSINESS "\xee\x9c\xa9" // U+e729 +#define ICON_MD_ADD_CALL "\xee\x83\xa8" // U+e0e8 +#define ICON_MD_ADD_CARD "\xee\xae\x86" // U+eb86 +#define ICON_MD_ADD_CHART "\xee\xa5\xbb" // U+e97b +#define ICON_MD_ADD_CIRCLE "\xee\x85\x87" // U+e147 +#define ICON_MD_ADD_CIRCLE_OUTLINE "\xee\x85\x88" // U+e148 +#define ICON_MD_ADD_COMMENT "\xee\x89\xa6" // U+e266 +#define ICON_MD_ADD_HOME "\xef\xa3\xab" // U+f8eb +#define ICON_MD_ADD_HOME_WORK "\xef\xa3\xad" // U+f8ed +#define ICON_MD_ADD_IC_CALL "\xee\xa5\xbc" // U+e97c +#define ICON_MD_ADD_LINK "\xee\x85\xb8" // U+e178 +#define ICON_MD_ADD_LOCATION "\xee\x95\xa7" // U+e567 +#define ICON_MD_ADD_LOCATION_ALT "\xee\xbc\xba" // U+ef3a +#define ICON_MD_ADD_MODERATOR "\xee\xa5\xbd" // U+e97d +#define ICON_MD_ADD_PHOTO_ALTERNATE "\xee\x90\xbe" // U+e43e +#define ICON_MD_ADD_REACTION "\xee\x87\x93" // U+e1d3 +#define ICON_MD_ADD_ROAD "\xee\xbc\xbb" // U+ef3b +#define ICON_MD_ADD_SHOPPING_CART "\xee\xa1\x94" // U+e854 +#define ICON_MD_ADD_TASK "\xef\x88\xba" // U+f23a +#define ICON_MD_ADD_TO_DRIVE "\xee\x99\x9c" // U+e65c +#define ICON_MD_ADD_TO_HOME_SCREEN "\xee\x87\xbe" // U+e1fe +#define ICON_MD_ADD_TO_PHOTOS "\xee\x8e\x9d" // U+e39d +#define ICON_MD_ADD_TO_QUEUE "\xee\x81\x9c" // U+e05c +#define ICON_MD_ADDCHART "\xee\xbc\xbc" // U+ef3c +#define ICON_MD_ADF_SCANNER "\xee\xab\x9a" // U+eada +#define ICON_MD_ADJUST "\xee\x8e\x9e" // U+e39e +#define ICON_MD_ADMIN_PANEL_SETTINGS "\xee\xbc\xbd" // U+ef3d +#define ICON_MD_ADOBE "\xee\xaa\x96" // U+ea96 +#define ICON_MD_ADS_CLICK "\xee\x9d\xa2" // U+e762 +#define ICON_MD_AGRICULTURE "\xee\xa9\xb9" // U+ea79 +#define ICON_MD_AIR "\xee\xbf\x98" // U+efd8 +#define ICON_MD_AIRLINE_SEAT_FLAT "\xee\x98\xb0" // U+e630 +#define ICON_MD_AIRLINE_SEAT_FLAT_ANGLED "\xee\x98\xb1" // U+e631 +#define ICON_MD_AIRLINE_SEAT_INDIVIDUAL_SUITE "\xee\x98\xb2" // U+e632 +#define ICON_MD_AIRLINE_SEAT_LEGROOM_EXTRA "\xee\x98\xb3" // U+e633 +#define ICON_MD_AIRLINE_SEAT_LEGROOM_NORMAL "\xee\x98\xb4" // U+e634 +#define ICON_MD_AIRLINE_SEAT_LEGROOM_REDUCED "\xee\x98\xb5" // U+e635 +#define ICON_MD_AIRLINE_SEAT_RECLINE_EXTRA "\xee\x98\xb6" // U+e636 +#define ICON_MD_AIRLINE_SEAT_RECLINE_NORMAL "\xee\x98\xb7" // U+e637 +#define ICON_MD_AIRLINE_STOPS "\xee\x9f\x90" // U+e7d0 +#define ICON_MD_AIRLINES "\xee\x9f\x8a" // U+e7ca +#define ICON_MD_AIRPLANE_TICKET "\xee\xbf\x99" // U+efd9 +#define ICON_MD_AIRPLANEMODE_ACTIVE "\xee\x86\x95" // U+e195 +#define ICON_MD_AIRPLANEMODE_INACTIVE "\xee\x86\x94" // U+e194 +#define ICON_MD_AIRPLANEMODE_OFF "\xee\x86\x94" // U+e194 +#define ICON_MD_AIRPLANEMODE_ON "\xee\x86\x95" // U+e195 +#define ICON_MD_AIRPLAY "\xee\x81\x95" // U+e055 +#define ICON_MD_AIRPORT_SHUTTLE "\xee\xac\xbc" // U+eb3c +#define ICON_MD_ALARM "\xee\xa1\x95" // U+e855 +#define ICON_MD_ALARM_ADD "\xee\xa1\x96" // U+e856 +#define ICON_MD_ALARM_OFF "\xee\xa1\x97" // U+e857 +#define ICON_MD_ALARM_ON "\xee\xa1\x98" // U+e858 +#define ICON_MD_ALBUM "\xee\x80\x99" // U+e019 +#define ICON_MD_ALIGN_HORIZONTAL_CENTER "\xee\x80\x8f" // U+e00f +#define ICON_MD_ALIGN_HORIZONTAL_LEFT "\xee\x80\x8d" // U+e00d +#define ICON_MD_ALIGN_HORIZONTAL_RIGHT "\xee\x80\x90" // U+e010 +#define ICON_MD_ALIGN_VERTICAL_BOTTOM "\xee\x80\x95" // U+e015 +#define ICON_MD_ALIGN_VERTICAL_CENTER "\xee\x80\x91" // U+e011 +#define ICON_MD_ALIGN_VERTICAL_TOP "\xee\x80\x8c" // U+e00c +#define ICON_MD_ALL_INBOX "\xee\xa5\xbf" // U+e97f +#define ICON_MD_ALL_INCLUSIVE "\xee\xac\xbd" // U+eb3d +#define ICON_MD_ALL_OUT "\xee\xa4\x8b" // U+e90b +#define ICON_MD_ALT_ROUTE "\xef\x86\x84" // U+f184 +#define ICON_MD_ALTERNATE_EMAIL "\xee\x83\xa6" // U+e0e6 +#define ICON_MD_AMP_STORIES "\xee\xa8\x93" // U+ea13 +#define ICON_MD_ANALYTICS "\xee\xbc\xbe" // U+ef3e +#define ICON_MD_ANCHOR "\xef\x87\x8d" // U+f1cd +#define ICON_MD_ANDROID "\xee\xa1\x99" // U+e859 +#define ICON_MD_ANIMATION "\xee\x9c\x9c" // U+e71c +#define ICON_MD_ANNOUNCEMENT "\xee\xa1\x9a" // U+e85a +#define ICON_MD_AOD "\xee\xbf\x9a" // U+efda +#define ICON_MD_APARTMENT "\xee\xa9\x80" // U+ea40 +#define ICON_MD_API "\xef\x86\xb7" // U+f1b7 +#define ICON_MD_APP_BLOCKING "\xee\xbc\xbf" // U+ef3f +#define ICON_MD_APP_REGISTRATION "\xee\xbd\x80" // U+ef40 +#define ICON_MD_APP_SETTINGS_ALT "\xee\xbd\x81" // U+ef41 +#define ICON_MD_APP_SHORTCUT "\xee\xab\xa4" // U+eae4 +#define ICON_MD_APPLE "\xee\xaa\x80" // U+ea80 +#define ICON_MD_APPROVAL "\xee\xa6\x82" // U+e982 +#define ICON_MD_APPS "\xee\x97\x83" // U+e5c3 +#define ICON_MD_APPS_OUTAGE "\xee\x9f\x8c" // U+e7cc +#define ICON_MD_ARCHITECTURE "\xee\xa8\xbb" // U+ea3b +#define ICON_MD_ARCHIVE "\xee\x85\x89" // U+e149 +#define ICON_MD_AREA_CHART "\xee\x9d\xb0" // U+e770 +#define ICON_MD_ARROW_BACK "\xee\x97\x84" // U+e5c4 +#define ICON_MD_ARROW_BACK_IOS "\xee\x97\xa0" // U+e5e0 +#define ICON_MD_ARROW_BACK_IOS_NEW "\xee\x8b\xaa" // U+e2ea +#define ICON_MD_ARROW_CIRCLE_DOWN "\xef\x86\x81" // U+f181 +#define ICON_MD_ARROW_CIRCLE_LEFT "\xee\xaa\xa7" // U+eaa7 +#define ICON_MD_ARROW_CIRCLE_RIGHT "\xee\xaa\xaa" // U+eaaa +#define ICON_MD_ARROW_CIRCLE_UP "\xef\x86\x82" // U+f182 +#define ICON_MD_ARROW_DOWNWARD "\xee\x97\x9b" // U+e5db +#define ICON_MD_ARROW_DROP_DOWN "\xee\x97\x85" // U+e5c5 +#define ICON_MD_ARROW_DROP_DOWN_CIRCLE "\xee\x97\x86" // U+e5c6 +#define ICON_MD_ARROW_DROP_UP "\xee\x97\x87" // U+e5c7 +#define ICON_MD_ARROW_FORWARD "\xee\x97\x88" // U+e5c8 +#define ICON_MD_ARROW_FORWARD_IOS "\xee\x97\xa1" // U+e5e1 +#define ICON_MD_ARROW_LEFT "\xee\x97\x9e" // U+e5de +#define ICON_MD_ARROW_OUTWARD "\xef\xa3\x8e" // U+f8ce +#define ICON_MD_ARROW_RIGHT "\xee\x97\x9f" // U+e5df +#define ICON_MD_ARROW_RIGHT_ALT "\xee\xa5\x81" // U+e941 +#define ICON_MD_ARROW_UPWARD "\xee\x97\x98" // U+e5d8 +#define ICON_MD_ART_TRACK "\xee\x81\xa0" // U+e060 +#define ICON_MD_ARTICLE "\xee\xbd\x82" // U+ef42 +#define ICON_MD_ASPECT_RATIO "\xee\xa1\x9b" // U+e85b +#define ICON_MD_ASSESSMENT "\xee\xa1\x9c" // U+e85c +#define ICON_MD_ASSIGNMENT "\xee\xa1\x9d" // U+e85d +#define ICON_MD_ASSIGNMENT_ADD "\xef\xa1\x88" // U+f848 +#define ICON_MD_ASSIGNMENT_IND "\xee\xa1\x9e" // U+e85e +#define ICON_MD_ASSIGNMENT_LATE "\xee\xa1\x9f" // U+e85f +#define ICON_MD_ASSIGNMENT_RETURN "\xee\xa1\xa0" // U+e860 +#define ICON_MD_ASSIGNMENT_RETURNED "\xee\xa1\xa1" // U+e861 +#define ICON_MD_ASSIGNMENT_TURNED_IN "\xee\xa1\xa2" // U+e862 +#define ICON_MD_ASSIST_WALKER "\xef\xa3\x95" // U+f8d5 +#define ICON_MD_ASSISTANT "\xee\x8e\x9f" // U+e39f +#define ICON_MD_ASSISTANT_DIRECTION "\xee\xa6\x88" // U+e988 +#define ICON_MD_ASSISTANT_NAVIGATION "\xee\xa6\x89" // U+e989 +#define ICON_MD_ASSISTANT_PHOTO "\xee\x8e\xa0" // U+e3a0 +#define ICON_MD_ASSURED_WORKLOAD "\xee\xad\xaf" // U+eb6f +#define ICON_MD_ATM "\xee\x95\xb3" // U+e573 +#define ICON_MD_ATTACH_EMAIL "\xee\xa9\x9e" // U+ea5e +#define ICON_MD_ATTACH_FILE "\xee\x88\xa6" // U+e226 +#define ICON_MD_ATTACH_MONEY "\xee\x88\xa7" // U+e227 +#define ICON_MD_ATTACHMENT "\xee\x8a\xbc" // U+e2bc +#define ICON_MD_ATTRACTIONS "\xee\xa9\x92" // U+ea52 +#define ICON_MD_ATTRIBUTION "\xee\xbf\x9b" // U+efdb +#define ICON_MD_AUDIO_FILE "\xee\xae\x82" // U+eb82 +#define ICON_MD_AUDIOTRACK "\xee\x8e\xa1" // U+e3a1 +#define ICON_MD_AUTO_AWESOME "\xee\x99\x9f" // U+e65f +#define ICON_MD_AUTO_AWESOME_MOSAIC "\xee\x99\xa0" // U+e660 +#define ICON_MD_AUTO_AWESOME_MOTION "\xee\x99\xa1" // U+e661 +#define ICON_MD_AUTO_DELETE "\xee\xa9\x8c" // U+ea4c +#define ICON_MD_AUTO_FIX_HIGH "\xee\x99\xa3" // U+e663 +#define ICON_MD_AUTO_FIX_NORMAL "\xee\x99\xa4" // U+e664 +#define ICON_MD_AUTO_FIX_OFF "\xee\x99\xa5" // U+e665 +#define ICON_MD_AUTO_GRAPH "\xee\x93\xbb" // U+e4fb +#define ICON_MD_AUTO_MODE "\xee\xb0\xa0" // U+ec20 +#define ICON_MD_AUTO_STORIES "\xee\x99\xa6" // U+e666 +#define ICON_MD_AUTOFPS_SELECT "\xee\xbf\x9c" // U+efdc +#define ICON_MD_AUTORENEW "\xee\xa1\xa3" // U+e863 +#define ICON_MD_AV_TIMER "\xee\x80\x9b" // U+e01b +#define ICON_MD_BABY_CHANGING_STATION "\xef\x86\x9b" // U+f19b +#define ICON_MD_BACK_HAND "\xee\x9d\xa4" // U+e764 +#define ICON_MD_BACKPACK "\xef\x86\x9c" // U+f19c +#define ICON_MD_BACKSPACE "\xee\x85\x8a" // U+e14a +#define ICON_MD_BACKUP "\xee\xa1\xa4" // U+e864 +#define ICON_MD_BACKUP_TABLE "\xee\xbd\x83" // U+ef43 +#define ICON_MD_BADGE "\xee\xa9\xa7" // U+ea67 +#define ICON_MD_BAKERY_DINING "\xee\xa9\x93" // U+ea53 +#define ICON_MD_BALANCE "\xee\xab\xb6" // U+eaf6 +#define ICON_MD_BALCONY "\xee\x96\x8f" // U+e58f +#define ICON_MD_BALLOT "\xee\x85\xb2" // U+e172 +#define ICON_MD_BAR_CHART "\xee\x89\xab" // U+e26b +#define ICON_MD_BARCODE_READER "\xef\xa1\x9c" // U+f85c +#define ICON_MD_BATCH_PREDICTION "\xef\x83\xb5" // U+f0f5 +#define ICON_MD_BATHROOM "\xee\xbf\x9d" // U+efdd +#define ICON_MD_BATHTUB "\xee\xa9\x81" // U+ea41 +#define ICON_MD_BATTERY_0_BAR "\xee\xaf\x9c" // U+ebdc +#define ICON_MD_BATTERY_1_BAR "\xee\xaf\x99" // U+ebd9 +#define ICON_MD_BATTERY_2_BAR "\xee\xaf\xa0" // U+ebe0 +#define ICON_MD_BATTERY_3_BAR "\xee\xaf\x9d" // U+ebdd +#define ICON_MD_BATTERY_4_BAR "\xee\xaf\xa2" // U+ebe2 +#define ICON_MD_BATTERY_5_BAR "\xee\xaf\x94" // U+ebd4 +#define ICON_MD_BATTERY_6_BAR "\xee\xaf\x92" // U+ebd2 +#define ICON_MD_BATTERY_ALERT "\xee\x86\x9c" // U+e19c +#define ICON_MD_BATTERY_CHARGING_FULL "\xee\x86\xa3" // U+e1a3 +#define ICON_MD_BATTERY_FULL "\xee\x86\xa4" // U+e1a4 +#define ICON_MD_BATTERY_SAVER "\xee\xbf\x9e" // U+efde +#define ICON_MD_BATTERY_STD "\xee\x86\xa5" // U+e1a5 +#define ICON_MD_BATTERY_UNKNOWN "\xee\x86\xa6" // U+e1a6 +#define ICON_MD_BEACH_ACCESS "\xee\xac\xbe" // U+eb3e +#define ICON_MD_BED "\xee\xbf\x9f" // U+efdf +#define ICON_MD_BEDROOM_BABY "\xee\xbf\xa0" // U+efe0 +#define ICON_MD_BEDROOM_CHILD "\xee\xbf\xa1" // U+efe1 +#define ICON_MD_BEDROOM_PARENT "\xee\xbf\xa2" // U+efe2 +#define ICON_MD_BEDTIME "\xee\xbd\x84" // U+ef44 +#define ICON_MD_BEDTIME_OFF "\xee\xad\xb6" // U+eb76 +#define ICON_MD_BEENHERE "\xee\x94\xad" // U+e52d +#define ICON_MD_BENTO "\xef\x87\xb4" // U+f1f4 +#define ICON_MD_BIKE_SCOOTER "\xee\xbd\x85" // U+ef45 +#define ICON_MD_BIOTECH "\xee\xa8\xba" // U+ea3a +#define ICON_MD_BLENDER "\xee\xbf\xa3" // U+efe3 +#define ICON_MD_BLIND "\xef\xa3\x96" // U+f8d6 +#define ICON_MD_BLINDS "\xee\x8a\x86" // U+e286 +#define ICON_MD_BLINDS_CLOSED "\xee\xb0\x9f" // U+ec1f +#define ICON_MD_BLOCK "\xee\x85\x8b" // U+e14b +#define ICON_MD_BLOCK_FLIPPED "\xee\xbd\x86" // U+ef46 +#define ICON_MD_BLOODTYPE "\xee\xbf\xa4" // U+efe4 +#define ICON_MD_BLUETOOTH "\xee\x86\xa7" // U+e1a7 +#define ICON_MD_BLUETOOTH_AUDIO "\xee\x98\x8f" // U+e60f +#define ICON_MD_BLUETOOTH_CONNECTED "\xee\x86\xa8" // U+e1a8 +#define ICON_MD_BLUETOOTH_DISABLED "\xee\x86\xa9" // U+e1a9 +#define ICON_MD_BLUETOOTH_DRIVE "\xee\xbf\xa5" // U+efe5 +#define ICON_MD_BLUETOOTH_SEARCHING "\xee\x86\xaa" // U+e1aa +#define ICON_MD_BLUR_CIRCULAR "\xee\x8e\xa2" // U+e3a2 +#define ICON_MD_BLUR_LINEAR "\xee\x8e\xa3" // U+e3a3 +#define ICON_MD_BLUR_OFF "\xee\x8e\xa4" // U+e3a4 +#define ICON_MD_BLUR_ON "\xee\x8e\xa5" // U+e3a5 +#define ICON_MD_BOLT "\xee\xa8\x8b" // U+ea0b +#define ICON_MD_BOOK "\xee\xa1\xa5" // U+e865 +#define ICON_MD_BOOK_ONLINE "\xef\x88\x97" // U+f217 +#define ICON_MD_BOOKMARK "\xee\xa1\xa6" // U+e866 +#define ICON_MD_BOOKMARK_ADD "\xee\x96\x98" // U+e598 +#define ICON_MD_BOOKMARK_ADDED "\xee\x96\x99" // U+e599 +#define ICON_MD_BOOKMARK_BORDER "\xee\xa1\xa7" // U+e867 +#define ICON_MD_BOOKMARK_OUTLINE "\xee\xa1\xa7" // U+e867 +#define ICON_MD_BOOKMARK_REMOVE "\xee\x96\x9a" // U+e59a +#define ICON_MD_BOOKMARKS "\xee\xa6\x8b" // U+e98b +#define ICON_MD_BORDER_ALL "\xee\x88\xa8" // U+e228 +#define ICON_MD_BORDER_BOTTOM "\xee\x88\xa9" // U+e229 +#define ICON_MD_BORDER_CLEAR "\xee\x88\xaa" // U+e22a +#define ICON_MD_BORDER_COLOR "\xee\x88\xab" // U+e22b +#define ICON_MD_BORDER_HORIZONTAL "\xee\x88\xac" // U+e22c +#define ICON_MD_BORDER_INNER "\xee\x88\xad" // U+e22d +#define ICON_MD_BORDER_LEFT "\xee\x88\xae" // U+e22e +#define ICON_MD_BORDER_OUTER "\xee\x88\xaf" // U+e22f +#define ICON_MD_BORDER_RIGHT "\xee\x88\xb0" // U+e230 +#define ICON_MD_BORDER_STYLE "\xee\x88\xb1" // U+e231 +#define ICON_MD_BORDER_TOP "\xee\x88\xb2" // U+e232 +#define ICON_MD_BORDER_VERTICAL "\xee\x88\xb3" // U+e233 +#define ICON_MD_BOY "\xee\xad\xa7" // U+eb67 +#define ICON_MD_BRANDING_WATERMARK "\xee\x81\xab" // U+e06b +#define ICON_MD_BREAKFAST_DINING "\xee\xa9\x94" // U+ea54 +#define ICON_MD_BRIGHTNESS_1 "\xee\x8e\xa6" // U+e3a6 +#define ICON_MD_BRIGHTNESS_2 "\xee\x8e\xa7" // U+e3a7 +#define ICON_MD_BRIGHTNESS_3 "\xee\x8e\xa8" // U+e3a8 +#define ICON_MD_BRIGHTNESS_4 "\xee\x8e\xa9" // U+e3a9 +#define ICON_MD_BRIGHTNESS_5 "\xee\x8e\xaa" // U+e3aa +#define ICON_MD_BRIGHTNESS_6 "\xee\x8e\xab" // U+e3ab +#define ICON_MD_BRIGHTNESS_7 "\xee\x8e\xac" // U+e3ac +#define ICON_MD_BRIGHTNESS_AUTO "\xee\x86\xab" // U+e1ab +#define ICON_MD_BRIGHTNESS_HIGH "\xee\x86\xac" // U+e1ac +#define ICON_MD_BRIGHTNESS_LOW "\xee\x86\xad" // U+e1ad +#define ICON_MD_BRIGHTNESS_MEDIUM "\xee\x86\xae" // U+e1ae +#define ICON_MD_BROADCAST_ON_HOME "\xef\xa3\xb8" // U+f8f8 +#define ICON_MD_BROADCAST_ON_PERSONAL "\xef\xa3\xb9" // U+f8f9 +#define ICON_MD_BROKEN_IMAGE "\xee\x8e\xad" // U+e3ad +#define ICON_MD_BROWSE_GALLERY "\xee\xaf\x91" // U+ebd1 +#define ICON_MD_BROWSER_NOT_SUPPORTED "\xee\xbd\x87" // U+ef47 +#define ICON_MD_BROWSER_UPDATED "\xee\x9f\x8f" // U+e7cf +#define ICON_MD_BRUNCH_DINING "\xee\xa9\xb3" // U+ea73 +#define ICON_MD_BRUSH "\xee\x8e\xae" // U+e3ae +#define ICON_MD_BUBBLE_CHART "\xee\x9b\x9d" // U+e6dd +#define ICON_MD_BUG_REPORT "\xee\xa1\xa8" // U+e868 +#define ICON_MD_BUILD "\xee\xa1\xa9" // U+e869 +#define ICON_MD_BUILD_CIRCLE "\xee\xbd\x88" // U+ef48 +#define ICON_MD_BUNGALOW "\xee\x96\x91" // U+e591 +#define ICON_MD_BURST_MODE "\xee\x90\xbc" // U+e43c +#define ICON_MD_BUS_ALERT "\xee\xa6\x8f" // U+e98f +#define ICON_MD_BUSINESS "\xee\x82\xaf" // U+e0af +#define ICON_MD_BUSINESS_CENTER "\xee\xac\xbf" // U+eb3f +#define ICON_MD_CABIN "\xee\x96\x89" // U+e589 +#define ICON_MD_CABLE "\xee\xbf\xa6" // U+efe6 +#define ICON_MD_CACHED "\xee\xa1\xaa" // U+e86a +#define ICON_MD_CAKE "\xee\x9f\xa9" // U+e7e9 +#define ICON_MD_CALCULATE "\xee\xa9\x9f" // U+ea5f +#define ICON_MD_CALENDAR_MONTH "\xee\xaf\x8c" // U+ebcc +#define ICON_MD_CALENDAR_TODAY "\xee\xa4\xb5" // U+e935 +#define ICON_MD_CALENDAR_VIEW_DAY "\xee\xa4\xb6" // U+e936 +#define ICON_MD_CALENDAR_VIEW_MONTH "\xee\xbf\xa7" // U+efe7 +#define ICON_MD_CALENDAR_VIEW_WEEK "\xee\xbf\xa8" // U+efe8 +#define ICON_MD_CALL "\xee\x82\xb0" // U+e0b0 +#define ICON_MD_CALL_END "\xee\x82\xb1" // U+e0b1 +#define ICON_MD_CALL_MADE "\xee\x82\xb2" // U+e0b2 +#define ICON_MD_CALL_MERGE "\xee\x82\xb3" // U+e0b3 +#define ICON_MD_CALL_MISSED "\xee\x82\xb4" // U+e0b4 +#define ICON_MD_CALL_MISSED_OUTGOING "\xee\x83\xa4" // U+e0e4 +#define ICON_MD_CALL_RECEIVED "\xee\x82\xb5" // U+e0b5 +#define ICON_MD_CALL_SPLIT "\xee\x82\xb6" // U+e0b6 +#define ICON_MD_CALL_TO_ACTION "\xee\x81\xac" // U+e06c +#define ICON_MD_CAMERA "\xee\x8e\xaf" // U+e3af +#define ICON_MD_CAMERA_ALT "\xee\x8e\xb0" // U+e3b0 +#define ICON_MD_CAMERA_ENHANCE "\xee\xa3\xbc" // U+e8fc +#define ICON_MD_CAMERA_FRONT "\xee\x8e\xb1" // U+e3b1 +#define ICON_MD_CAMERA_INDOOR "\xee\xbf\xa9" // U+efe9 +#define ICON_MD_CAMERA_OUTDOOR "\xee\xbf\xaa" // U+efea +#define ICON_MD_CAMERA_REAR "\xee\x8e\xb2" // U+e3b2 +#define ICON_MD_CAMERA_ROLL "\xee\x8e\xb3" // U+e3b3 +#define ICON_MD_CAMERASWITCH "\xee\xbf\xab" // U+efeb +#define ICON_MD_CAMPAIGN "\xee\xbd\x89" // U+ef49 +#define ICON_MD_CANCEL "\xee\x97\x89" // U+e5c9 +#define ICON_MD_CANCEL_PRESENTATION "\xee\x83\xa9" // U+e0e9 +#define ICON_MD_CANCEL_SCHEDULE_SEND "\xee\xa8\xb9" // U+ea39 +#define ICON_MD_CANDLESTICK_CHART "\xee\xab\x94" // U+ead4 +#define ICON_MD_CAR_CRASH "\xee\xaf\xb2" // U+ebf2 +#define ICON_MD_CAR_RENTAL "\xee\xa9\x95" // U+ea55 +#define ICON_MD_CAR_REPAIR "\xee\xa9\x96" // U+ea56 +#define ICON_MD_CARD_GIFTCARD "\xee\xa3\xb6" // U+e8f6 +#define ICON_MD_CARD_MEMBERSHIP "\xee\xa3\xb7" // U+e8f7 +#define ICON_MD_CARD_TRAVEL "\xee\xa3\xb8" // U+e8f8 +#define ICON_MD_CARPENTER "\xef\x87\xb8" // U+f1f8 +#define ICON_MD_CASES "\xee\xa6\x92" // U+e992 +#define ICON_MD_CASINO "\xee\xad\x80" // U+eb40 +#define ICON_MD_CAST "\xee\x8c\x87" // U+e307 +#define ICON_MD_CAST_CONNECTED "\xee\x8c\x88" // U+e308 +#define ICON_MD_CAST_FOR_EDUCATION "\xee\xbf\xac" // U+efec +#define ICON_MD_CASTLE "\xee\xaa\xb1" // U+eab1 +#define ICON_MD_CATCHING_POKEMON "\xee\x94\x88" // U+e508 +#define ICON_MD_CATEGORY "\xee\x95\xb4" // U+e574 +#define ICON_MD_CELEBRATION "\xee\xa9\xa5" // U+ea65 +#define ICON_MD_CELL_TOWER "\xee\xae\xba" // U+ebba +#define ICON_MD_CELL_WIFI "\xee\x83\xac" // U+e0ec +#define ICON_MD_CENTER_FOCUS_STRONG "\xee\x8e\xb4" // U+e3b4 +#define ICON_MD_CENTER_FOCUS_WEAK "\xee\x8e\xb5" // U+e3b5 +#define ICON_MD_CHAIR "\xee\xbf\xad" // U+efed +#define ICON_MD_CHAIR_ALT "\xee\xbf\xae" // U+efee +#define ICON_MD_CHALET "\xee\x96\x85" // U+e585 +#define ICON_MD_CHANGE_CIRCLE "\xee\x8b\xa7" // U+e2e7 +#define ICON_MD_CHANGE_HISTORY "\xee\xa1\xab" // U+e86b +#define ICON_MD_CHARGING_STATION "\xef\x86\x9d" // U+f19d +#define ICON_MD_CHAT "\xee\x82\xb7" // U+e0b7 +#define ICON_MD_CHAT_BUBBLE "\xee\x83\x8a" // U+e0ca +#define ICON_MD_CHAT_BUBBLE_OUTLINE "\xee\x83\x8b" // U+e0cb +#define ICON_MD_CHECK "\xee\x97\x8a" // U+e5ca +#define ICON_MD_CHECK_BOX "\xee\xa0\xb4" // U+e834 +#define ICON_MD_CHECK_BOX_OUTLINE_BLANK "\xee\xa0\xb5" // U+e835 +#define ICON_MD_CHECK_CIRCLE "\xee\xa1\xac" // U+e86c +#define ICON_MD_CHECK_CIRCLE_OUTLINE "\xee\xa4\xad" // U+e92d +#define ICON_MD_CHECKLIST "\xee\x9a\xb1" // U+e6b1 +#define ICON_MD_CHECKLIST_RTL "\xee\x9a\xb3" // U+e6b3 +#define ICON_MD_CHECKROOM "\xef\x86\x9e" // U+f19e +#define ICON_MD_CHEVRON_LEFT "\xee\x97\x8b" // U+e5cb +#define ICON_MD_CHEVRON_RIGHT "\xee\x97\x8c" // U+e5cc +#define ICON_MD_CHILD_CARE "\xee\xad\x81" // U+eb41 +#define ICON_MD_CHILD_FRIENDLY "\xee\xad\x82" // U+eb42 +#define ICON_MD_CHROME_READER_MODE "\xee\xa1\xad" // U+e86d +#define ICON_MD_CHURCH "\xee\xaa\xae" // U+eaae +#define ICON_MD_CIRCLE "\xee\xbd\x8a" // U+ef4a +#define ICON_MD_CIRCLE_NOTIFICATIONS "\xee\xa6\x94" // U+e994 +#define ICON_MD_CLASS "\xee\xa1\xae" // U+e86e +#define ICON_MD_CLEAN_HANDS "\xef\x88\x9f" // U+f21f +#define ICON_MD_CLEANING_SERVICES "\xef\x83\xbf" // U+f0ff +#define ICON_MD_CLEAR "\xee\x85\x8c" // U+e14c +#define ICON_MD_CLEAR_ALL "\xee\x82\xb8" // U+e0b8 +#define ICON_MD_CLOSE "\xee\x97\x8d" // U+e5cd +#define ICON_MD_CLOSE_FULLSCREEN "\xef\x87\x8f" // U+f1cf +#define ICON_MD_CLOSED_CAPTION "\xee\x80\x9c" // U+e01c +#define ICON_MD_CLOSED_CAPTION_DISABLED "\xef\x87\x9c" // U+f1dc +#define ICON_MD_CLOSED_CAPTION_OFF "\xee\xa6\x96" // U+e996 +#define ICON_MD_CLOUD "\xee\x8a\xbd" // U+e2bd +#define ICON_MD_CLOUD_CIRCLE "\xee\x8a\xbe" // U+e2be +#define ICON_MD_CLOUD_DONE "\xee\x8a\xbf" // U+e2bf +#define ICON_MD_CLOUD_DOWNLOAD "\xee\x8b\x80" // U+e2c0 +#define ICON_MD_CLOUD_OFF "\xee\x8b\x81" // U+e2c1 +#define ICON_MD_CLOUD_QUEUE "\xee\x8b\x82" // U+e2c2 +#define ICON_MD_CLOUD_SYNC "\xee\xad\x9a" // U+eb5a +#define ICON_MD_CLOUD_UPLOAD "\xee\x8b\x83" // U+e2c3 +#define ICON_MD_CLOUDY_SNOWING "\xee\xa0\x90" // U+e810 +#define ICON_MD_CO2 "\xee\x9e\xb0" // U+e7b0 +#define ICON_MD_CO_PRESENT "\xee\xab\xb0" // U+eaf0 +#define ICON_MD_CODE "\xee\xa1\xaf" // U+e86f +#define ICON_MD_CODE_OFF "\xee\x93\xb3" // U+e4f3 +#define ICON_MD_COFFEE "\xee\xbf\xaf" // U+efef +#define ICON_MD_COFFEE_MAKER "\xee\xbf\xb0" // U+eff0 +#define ICON_MD_COLLECTIONS "\xee\x8e\xb6" // U+e3b6 +#define ICON_MD_COLLECTIONS_BOOKMARK "\xee\x90\xb1" // U+e431 +#define ICON_MD_COLOR_LENS "\xee\x8e\xb7" // U+e3b7 +#define ICON_MD_COLORIZE "\xee\x8e\xb8" // U+e3b8 +#define ICON_MD_COMMENT "\xee\x82\xb9" // U+e0b9 +#define ICON_MD_COMMENT_BANK "\xee\xa9\x8e" // U+ea4e +#define ICON_MD_COMMENTS_DISABLED "\xee\x9e\xa2" // U+e7a2 +#define ICON_MD_COMMIT "\xee\xab\xb5" // U+eaf5 +#define ICON_MD_COMMUTE "\xee\xa5\x80" // U+e940 +#define ICON_MD_COMPARE "\xee\x8e\xb9" // U+e3b9 +#define ICON_MD_COMPARE_ARROWS "\xee\xa4\x95" // U+e915 +#define ICON_MD_COMPASS_CALIBRATION "\xee\x95\xbc" // U+e57c +#define ICON_MD_COMPOST "\xee\x9d\xa1" // U+e761 +#define ICON_MD_COMPRESS "\xee\xa5\x8d" // U+e94d +#define ICON_MD_COMPUTER "\xee\x8c\x8a" // U+e30a +#define ICON_MD_CONFIRMATION_NUM "\xee\x98\xb8" // U+e638 +#define ICON_MD_CONFIRMATION_NUMBER "\xee\x98\xb8" // U+e638 +#define ICON_MD_CONNECT_WITHOUT_CONTACT "\xef\x88\xa3" // U+f223 +#define ICON_MD_CONNECTED_TV "\xee\xa6\x98" // U+e998 +#define ICON_MD_CONNECTING_AIRPORTS "\xee\x9f\x89" // U+e7c9 +#define ICON_MD_CONSTRUCTION "\xee\xa8\xbc" // U+ea3c +#define ICON_MD_CONTACT_EMERGENCY "\xef\xa3\x91" // U+f8d1 +#define ICON_MD_CONTACT_MAIL "\xee\x83\x90" // U+e0d0 +#define ICON_MD_CONTACT_PAGE "\xef\x88\xae" // U+f22e +#define ICON_MD_CONTACT_PHONE "\xee\x83\x8f" // U+e0cf +#define ICON_MD_CONTACT_SUPPORT "\xee\xa5\x8c" // U+e94c +#define ICON_MD_CONTACTLESS "\xee\xa9\xb1" // U+ea71 +#define ICON_MD_CONTACTS "\xee\x82\xba" // U+e0ba +#define ICON_MD_CONTENT_COPY "\xee\x85\x8d" // U+e14d +#define ICON_MD_CONTENT_CUT "\xee\x85\x8e" // U+e14e +#define ICON_MD_CONTENT_PASTE "\xee\x85\x8f" // U+e14f +#define ICON_MD_CONTENT_PASTE_GO "\xee\xaa\x8e" // U+ea8e +#define ICON_MD_CONTENT_PASTE_OFF "\xee\x93\xb8" // U+e4f8 +#define ICON_MD_CONTENT_PASTE_SEARCH "\xee\xaa\x9b" // U+ea9b +#define ICON_MD_CONTRAST "\xee\xac\xb7" // U+eb37 +#define ICON_MD_CONTROL_CAMERA "\xee\x81\xb4" // U+e074 +#define ICON_MD_CONTROL_POINT "\xee\x8e\xba" // U+e3ba +#define ICON_MD_CONTROL_POINT_DUPLICATE "\xee\x8e\xbb" // U+e3bb +#define ICON_MD_CONVEYOR_BELT "\xef\xa1\xa7" // U+f867 +#define ICON_MD_COOKIE "\xee\xaa\xac" // U+eaac +#define ICON_MD_COPY_ALL "\xee\x8b\xac" // U+e2ec +#define ICON_MD_COPYRIGHT "\xee\xa4\x8c" // U+e90c +#define ICON_MD_CORONAVIRUS "\xef\x88\xa1" // U+f221 +#define ICON_MD_CORPORATE_FARE "\xef\x87\x90" // U+f1d0 +#define ICON_MD_COTTAGE "\xee\x96\x87" // U+e587 +#define ICON_MD_COUNTERTOPS "\xef\x87\xb7" // U+f1f7 +#define ICON_MD_CREATE "\xee\x85\x90" // U+e150 +#define ICON_MD_CREATE_NEW_FOLDER "\xee\x8b\x8c" // U+e2cc +#define ICON_MD_CREDIT_CARD "\xee\xa1\xb0" // U+e870 +#define ICON_MD_CREDIT_CARD_OFF "\xee\x93\xb4" // U+e4f4 +#define ICON_MD_CREDIT_SCORE "\xee\xbf\xb1" // U+eff1 +#define ICON_MD_CRIB "\xee\x96\x88" // U+e588 +#define ICON_MD_CRISIS_ALERT "\xee\xaf\xa9" // U+ebe9 +#define ICON_MD_CROP "\xee\x8e\xbe" // U+e3be +#define ICON_MD_CROP_16_9 "\xee\x8e\xbc" // U+e3bc +#define ICON_MD_CROP_3_2 "\xee\x8e\xbd" // U+e3bd +#define ICON_MD_CROP_5_4 "\xee\x8e\xbf" // U+e3bf +#define ICON_MD_CROP_7_5 "\xee\x8f\x80" // U+e3c0 +#define ICON_MD_CROP_DIN "\xee\x8f\x81" // U+e3c1 +#define ICON_MD_CROP_FREE "\xee\x8f\x82" // U+e3c2 +#define ICON_MD_CROP_LANDSCAPE "\xee\x8f\x83" // U+e3c3 +#define ICON_MD_CROP_ORIGINAL "\xee\x8f\x84" // U+e3c4 +#define ICON_MD_CROP_PORTRAIT "\xee\x8f\x85" // U+e3c5 +#define ICON_MD_CROP_ROTATE "\xee\x90\xb7" // U+e437 +#define ICON_MD_CROP_SQUARE "\xee\x8f\x86" // U+e3c6 +#define ICON_MD_CRUELTY_FREE "\xee\x9e\x99" // U+e799 +#define ICON_MD_CSS "\xee\xae\x93" // U+eb93 +#define ICON_MD_CURRENCY_BITCOIN "\xee\xaf\x85" // U+ebc5 +#define ICON_MD_CURRENCY_EXCHANGE "\xee\xad\xb0" // U+eb70 +#define ICON_MD_CURRENCY_FRANC "\xee\xab\xba" // U+eafa +#define ICON_MD_CURRENCY_LIRA "\xee\xab\xaf" // U+eaef +#define ICON_MD_CURRENCY_POUND "\xee\xab\xb1" // U+eaf1 +#define ICON_MD_CURRENCY_RUBLE "\xee\xab\xac" // U+eaec +#define ICON_MD_CURRENCY_RUPEE "\xee\xab\xb7" // U+eaf7 +#define ICON_MD_CURRENCY_YEN "\xee\xab\xbb" // U+eafb +#define ICON_MD_CURRENCY_YUAN "\xee\xab\xb9" // U+eaf9 +#define ICON_MD_CURTAINS "\xee\xb0\x9e" // U+ec1e +#define ICON_MD_CURTAINS_CLOSED "\xee\xb0\x9d" // U+ec1d +#define ICON_MD_CYCLONE "\xee\xaf\x95" // U+ebd5 +#define ICON_MD_DANGEROUS "\xee\xa6\x9a" // U+e99a +#define ICON_MD_DARK_MODE "\xee\x94\x9c" // U+e51c +#define ICON_MD_DASHBOARD "\xee\xa1\xb1" // U+e871 +#define ICON_MD_DASHBOARD_CUSTOMIZE "\xee\xa6\x9b" // U+e99b +#define ICON_MD_DATA_ARRAY "\xee\xab\x91" // U+ead1 +#define ICON_MD_DATA_EXPLORATION "\xee\x9d\xaf" // U+e76f +#define ICON_MD_DATA_OBJECT "\xee\xab\x93" // U+ead3 +#define ICON_MD_DATA_SAVER_OFF "\xee\xbf\xb2" // U+eff2 +#define ICON_MD_DATA_SAVER_ON "\xee\xbf\xb3" // U+eff3 +#define ICON_MD_DATA_THRESHOLDING "\xee\xae\x9f" // U+eb9f +#define ICON_MD_DATA_USAGE "\xee\x86\xaf" // U+e1af +#define ICON_MD_DATASET "\xef\xa3\xae" // U+f8ee +#define ICON_MD_DATASET_LINKED "\xef\xa3\xaf" // U+f8ef +#define ICON_MD_DATE_RANGE "\xee\xa4\x96" // U+e916 +#define ICON_MD_DEBLUR "\xee\xad\xb7" // U+eb77 +#define ICON_MD_DECK "\xee\xa9\x82" // U+ea42 +#define ICON_MD_DEHAZE "\xee\x8f\x87" // U+e3c7 +#define ICON_MD_DELETE "\xee\xa1\xb2" // U+e872 +#define ICON_MD_DELETE_FOREVER "\xee\xa4\xab" // U+e92b +#define ICON_MD_DELETE_OUTLINE "\xee\xa4\xae" // U+e92e +#define ICON_MD_DELETE_SWEEP "\xee\x85\xac" // U+e16c +#define ICON_MD_DELIVERY_DINING "\xee\xa9\xb2" // U+ea72 +#define ICON_MD_DENSITY_LARGE "\xee\xae\xa9" // U+eba9 +#define ICON_MD_DENSITY_MEDIUM "\xee\xae\x9e" // U+eb9e +#define ICON_MD_DENSITY_SMALL "\xee\xae\xa8" // U+eba8 +#define ICON_MD_DEPARTURE_BOARD "\xee\x95\xb6" // U+e576 +#define ICON_MD_DESCRIPTION "\xee\xa1\xb3" // U+e873 +#define ICON_MD_DESELECT "\xee\xae\xb6" // U+ebb6 +#define ICON_MD_DESIGN_SERVICES "\xef\x84\x8a" // U+f10a +#define ICON_MD_DESK "\xef\xa3\xb4" // U+f8f4 +#define ICON_MD_DESKTOP_ACCESS_DISABLED "\xee\xa6\x9d" // U+e99d +#define ICON_MD_DESKTOP_MAC "\xee\x8c\x8b" // U+e30b +#define ICON_MD_DESKTOP_WINDOWS "\xee\x8c\x8c" // U+e30c +#define ICON_MD_DETAILS "\xee\x8f\x88" // U+e3c8 +#define ICON_MD_DEVELOPER_BOARD "\xee\x8c\x8d" // U+e30d +#define ICON_MD_DEVELOPER_BOARD_OFF "\xee\x93\xbf" // U+e4ff +#define ICON_MD_DEVELOPER_MODE "\xee\x86\xb0" // U+e1b0 +#define ICON_MD_DEVICE_HUB "\xee\x8c\xb5" // U+e335 +#define ICON_MD_DEVICE_THERMOSTAT "\xee\x87\xbf" // U+e1ff +#define ICON_MD_DEVICE_UNKNOWN "\xee\x8c\xb9" // U+e339 +#define ICON_MD_DEVICES "\xee\x86\xb1" // U+e1b1 +#define ICON_MD_DEVICES_FOLD "\xee\xaf\x9e" // U+ebde +#define ICON_MD_DEVICES_OTHER "\xee\x8c\xb7" // U+e337 +#define ICON_MD_DEW_POINT "\xef\xa1\xb9" // U+f879 +#define ICON_MD_DIALER_SIP "\xee\x82\xbb" // U+e0bb +#define ICON_MD_DIALPAD "\xee\x82\xbc" // U+e0bc +#define ICON_MD_DIAMOND "\xee\xab\x95" // U+ead5 +#define ICON_MD_DIFFERENCE "\xee\xad\xbd" // U+eb7d +#define ICON_MD_DINING "\xee\xbf\xb4" // U+eff4 +#define ICON_MD_DINNER_DINING "\xee\xa9\x97" // U+ea57 +#define ICON_MD_DIRECTIONS "\xee\x94\xae" // U+e52e +#define ICON_MD_DIRECTIONS_BIKE "\xee\x94\xaf" // U+e52f +#define ICON_MD_DIRECTIONS_BOAT "\xee\x94\xb2" // U+e532 +#define ICON_MD_DIRECTIONS_BOAT_FILLED "\xee\xbf\xb5" // U+eff5 +#define ICON_MD_DIRECTIONS_BUS "\xee\x94\xb0" // U+e530 +#define ICON_MD_DIRECTIONS_BUS_FILLED "\xee\xbf\xb6" // U+eff6 +#define ICON_MD_DIRECTIONS_CAR "\xee\x94\xb1" // U+e531 +#define ICON_MD_DIRECTIONS_CAR_FILLED "\xee\xbf\xb7" // U+eff7 +#define ICON_MD_DIRECTIONS_FERRY "\xee\x94\xb2" // U+e532 +#define ICON_MD_DIRECTIONS_OFF "\xef\x84\x8f" // U+f10f +#define ICON_MD_DIRECTIONS_RAILWAY "\xee\x94\xb4" // U+e534 +#define ICON_MD_DIRECTIONS_RAILWAY_FILLED "\xee\xbf\xb8" // U+eff8 +#define ICON_MD_DIRECTIONS_RUN "\xee\x95\xa6" // U+e566 +#define ICON_MD_DIRECTIONS_SUBWAY "\xee\x94\xb3" // U+e533 +#define ICON_MD_DIRECTIONS_SUBWAY_FILLED "\xee\xbf\xb9" // U+eff9 +#define ICON_MD_DIRECTIONS_TRAIN "\xee\x94\xb4" // U+e534 +#define ICON_MD_DIRECTIONS_TRANSIT "\xee\x94\xb5" // U+e535 +#define ICON_MD_DIRECTIONS_TRANSIT_FILLED "\xee\xbf\xba" // U+effa +#define ICON_MD_DIRECTIONS_WALK "\xee\x94\xb6" // U+e536 +#define ICON_MD_DIRTY_LENS "\xee\xbd\x8b" // U+ef4b +#define ICON_MD_DISABLED_BY_DEFAULT "\xef\x88\xb0" // U+f230 +#define ICON_MD_DISABLED_VISIBLE "\xee\x9d\xae" // U+e76e +#define ICON_MD_DISC_FULL "\xee\x98\x90" // U+e610 +#define ICON_MD_DISCORD "\xee\xa9\xac" // U+ea6c +#define ICON_MD_DISCOUNT "\xee\xaf\x89" // U+ebc9 +#define ICON_MD_DISPLAY_SETTINGS "\xee\xae\x97" // U+eb97 +#define ICON_MD_DIVERSITY_1 "\xef\xa3\x97" // U+f8d7 +#define ICON_MD_DIVERSITY_2 "\xef\xa3\x98" // U+f8d8 +#define ICON_MD_DIVERSITY_3 "\xef\xa3\x99" // U+f8d9 +#define ICON_MD_DND_FORWARDSLASH "\xee\x98\x91" // U+e611 +#define ICON_MD_DNS "\xee\xa1\xb5" // U+e875 +#define ICON_MD_DO_DISTURB "\xef\x82\x8c" // U+f08c +#define ICON_MD_DO_DISTURB_ALT "\xef\x82\x8d" // U+f08d +#define ICON_MD_DO_DISTURB_OFF "\xef\x82\x8e" // U+f08e +#define ICON_MD_DO_DISTURB_ON "\xef\x82\x8f" // U+f08f +#define ICON_MD_DO_NOT_DISTURB "\xee\x98\x92" // U+e612 +#define ICON_MD_DO_NOT_DISTURB_ALT "\xee\x98\x91" // U+e611 +#define ICON_MD_DO_NOT_DISTURB_OFF "\xee\x99\x83" // U+e643 +#define ICON_MD_DO_NOT_DISTURB_ON "\xee\x99\x84" // U+e644 +#define ICON_MD_DO_NOT_DISTURB_ON_TOTAL_SILENCE "\xee\xbf\xbb" // U+effb +#define ICON_MD_DO_NOT_STEP "\xef\x86\x9f" // U+f19f +#define ICON_MD_DO_NOT_TOUCH "\xef\x86\xb0" // U+f1b0 +#define ICON_MD_DOCK "\xee\x8c\x8e" // U+e30e +#define ICON_MD_DOCUMENT_SCANNER "\xee\x97\xba" // U+e5fa +#define ICON_MD_DOMAIN "\xee\x9f\xae" // U+e7ee +#define ICON_MD_DOMAIN_ADD "\xee\xad\xa2" // U+eb62 +#define ICON_MD_DOMAIN_DISABLED "\xee\x83\xaf" // U+e0ef +#define ICON_MD_DOMAIN_VERIFICATION "\xee\xbd\x8c" // U+ef4c +#define ICON_MD_DONE "\xee\xa1\xb6" // U+e876 +#define ICON_MD_DONE_ALL "\xee\xa1\xb7" // U+e877 +#define ICON_MD_DONE_OUTLINE "\xee\xa4\xaf" // U+e92f +#define ICON_MD_DONUT_LARGE "\xee\xa4\x97" // U+e917 +#define ICON_MD_DONUT_SMALL "\xee\xa4\x98" // U+e918 +#define ICON_MD_DOOR_BACK "\xee\xbf\xbc" // U+effc +#define ICON_MD_DOOR_FRONT "\xee\xbf\xbd" // U+effd +#define ICON_MD_DOOR_SLIDING "\xee\xbf\xbe" // U+effe +#define ICON_MD_DOORBELL "\xee\xbf\xbf" // U+efff +#define ICON_MD_DOUBLE_ARROW "\xee\xa9\x90" // U+ea50 +#define ICON_MD_DOWNHILL_SKIING "\xee\x94\x89" // U+e509 +#define ICON_MD_DOWNLOAD "\xef\x82\x90" // U+f090 +#define ICON_MD_DOWNLOAD_DONE "\xef\x82\x91" // U+f091 +#define ICON_MD_DOWNLOAD_FOR_OFFLINE "\xef\x80\x80" // U+f000 +#define ICON_MD_DOWNLOADING "\xef\x80\x81" // U+f001 +#define ICON_MD_DRAFTS "\xee\x85\x91" // U+e151 +#define ICON_MD_DRAG_HANDLE "\xee\x89\x9d" // U+e25d +#define ICON_MD_DRAG_INDICATOR "\xee\xa5\x85" // U+e945 +#define ICON_MD_DRAW "\xee\x9d\x86" // U+e746 +#define ICON_MD_DRIVE_ETA "\xee\x98\x93" // U+e613 +#define ICON_MD_DRIVE_FILE_MOVE "\xee\x99\xb5" // U+e675 +#define ICON_MD_DRIVE_FILE_MOVE_OUTLINE "\xee\xa6\xa1" // U+e9a1 +#define ICON_MD_DRIVE_FILE_MOVE_RTL "\xee\x9d\xad" // U+e76d +#define ICON_MD_DRIVE_FILE_RENAME_OUTLINE "\xee\xa6\xa2" // U+e9a2 +#define ICON_MD_DRIVE_FOLDER_UPLOAD "\xee\xa6\xa3" // U+e9a3 +#define ICON_MD_DRY "\xef\x86\xb3" // U+f1b3 +#define ICON_MD_DRY_CLEANING "\xee\xa9\x98" // U+ea58 +#define ICON_MD_DUO "\xee\xa6\xa5" // U+e9a5 +#define ICON_MD_DVR "\xee\x86\xb2" // U+e1b2 +#define ICON_MD_DYNAMIC_FEED "\xee\xa8\x94" // U+ea14 +#define ICON_MD_DYNAMIC_FORM "\xef\x86\xbf" // U+f1bf +#define ICON_MD_E_MOBILEDATA "\xef\x80\x82" // U+f002 +#define ICON_MD_EARBUDS "\xef\x80\x83" // U+f003 +#define ICON_MD_EARBUDS_BATTERY "\xef\x80\x84" // U+f004 +#define ICON_MD_EAST "\xef\x87\x9f" // U+f1df +#define ICON_MD_ECO "\xee\xa8\xb5" // U+ea35 +#define ICON_MD_EDGESENSOR_HIGH "\xef\x80\x85" // U+f005 +#define ICON_MD_EDGESENSOR_LOW "\xef\x80\x86" // U+f006 +#define ICON_MD_EDIT "\xee\x8f\x89" // U+e3c9 +#define ICON_MD_EDIT_ATTRIBUTES "\xee\x95\xb8" // U+e578 +#define ICON_MD_EDIT_CALENDAR "\xee\x9d\x82" // U+e742 +#define ICON_MD_EDIT_DOCUMENT "\xef\xa2\x8c" // U+f88c +#define ICON_MD_EDIT_LOCATION "\xee\x95\xa8" // U+e568 +#define ICON_MD_EDIT_LOCATION_ALT "\xee\x87\x85" // U+e1c5 +#define ICON_MD_EDIT_NOTE "\xee\x9d\x85" // U+e745 +#define ICON_MD_EDIT_NOTIFICATIONS "\xee\x94\xa5" // U+e525 +#define ICON_MD_EDIT_OFF "\xee\xa5\x90" // U+e950 +#define ICON_MD_EDIT_ROAD "\xee\xbd\x8d" // U+ef4d +#define ICON_MD_EDIT_SQUARE "\xef\xa2\x8d" // U+f88d +#define ICON_MD_EGG "\xee\xab\x8c" // U+eacc +#define ICON_MD_EGG_ALT "\xee\xab\x88" // U+eac8 +#define ICON_MD_EJECT "\xee\xa3\xbb" // U+e8fb +#define ICON_MD_ELDERLY "\xef\x88\x9a" // U+f21a +#define ICON_MD_ELDERLY_WOMAN "\xee\xad\xa9" // U+eb69 +#define ICON_MD_ELECTRIC_BIKE "\xee\xac\x9b" // U+eb1b +#define ICON_MD_ELECTRIC_BOLT "\xee\xb0\x9c" // U+ec1c +#define ICON_MD_ELECTRIC_CAR "\xee\xac\x9c" // U+eb1c +#define ICON_MD_ELECTRIC_METER "\xee\xb0\x9b" // U+ec1b +#define ICON_MD_ELECTRIC_MOPED "\xee\xac\x9d" // U+eb1d +#define ICON_MD_ELECTRIC_RICKSHAW "\xee\xac\x9e" // U+eb1e +#define ICON_MD_ELECTRIC_SCOOTER "\xee\xac\x9f" // U+eb1f +#define ICON_MD_ELECTRICAL_SERVICES "\xef\x84\x82" // U+f102 +#define ICON_MD_ELEVATOR "\xef\x86\xa0" // U+f1a0 +#define ICON_MD_EMAIL "\xee\x82\xbe" // U+e0be +#define ICON_MD_EMERGENCY "\xee\x87\xab" // U+e1eb +#define ICON_MD_EMERGENCY_RECORDING "\xee\xaf\xb4" // U+ebf4 +#define ICON_MD_EMERGENCY_SHARE "\xee\xaf\xb6" // U+ebf6 +#define ICON_MD_EMOJI_EMOTIONS "\xee\xa8\xa2" // U+ea22 +#define ICON_MD_EMOJI_EVENTS "\xee\xa8\xa3" // U+ea23 +#define ICON_MD_EMOJI_FLAGS "\xee\xa8\x9a" // U+ea1a +#define ICON_MD_EMOJI_FOOD_BEVERAGE "\xee\xa8\x9b" // U+ea1b +#define ICON_MD_EMOJI_NATURE "\xee\xa8\x9c" // U+ea1c +#define ICON_MD_EMOJI_OBJECTS "\xee\xa8\xa4" // U+ea24 +#define ICON_MD_EMOJI_PEOPLE "\xee\xa8\x9d" // U+ea1d +#define ICON_MD_EMOJI_SYMBOLS "\xee\xa8\x9e" // U+ea1e +#define ICON_MD_EMOJI_TRANSPORTATION "\xee\xa8\x9f" // U+ea1f +#define ICON_MD_ENERGY_SAVINGS_LEAF "\xee\xb0\x9a" // U+ec1a +#define ICON_MD_ENGINEERING "\xee\xa8\xbd" // U+ea3d +#define ICON_MD_ENHANCE_PHOTO_TRANSLATE "\xee\xa3\xbc" // U+e8fc +#define ICON_MD_ENHANCED_ENCRYPTION "\xee\x98\xbf" // U+e63f +#define ICON_MD_EQUALIZER "\xee\x80\x9d" // U+e01d +#define ICON_MD_ERROR "\xee\x80\x80" // U+e000 +#define ICON_MD_ERROR_OUTLINE "\xee\x80\x81" // U+e001 +#define ICON_MD_ESCALATOR "\xef\x86\xa1" // U+f1a1 +#define ICON_MD_ESCALATOR_WARNING "\xef\x86\xac" // U+f1ac +#define ICON_MD_EURO "\xee\xa8\x95" // U+ea15 +#define ICON_MD_EURO_SYMBOL "\xee\xa4\xa6" // U+e926 +#define ICON_MD_EV_STATION "\xee\x95\xad" // U+e56d +#define ICON_MD_EVENT "\xee\xa1\xb8" // U+e878 +#define ICON_MD_EVENT_AVAILABLE "\xee\x98\x94" // U+e614 +#define ICON_MD_EVENT_BUSY "\xee\x98\x95" // U+e615 +#define ICON_MD_EVENT_NOTE "\xee\x98\x96" // U+e616 +#define ICON_MD_EVENT_REPEAT "\xee\xad\xbb" // U+eb7b +#define ICON_MD_EVENT_SEAT "\xee\xa4\x83" // U+e903 +#define ICON_MD_EXIT_TO_APP "\xee\xa1\xb9" // U+e879 +#define ICON_MD_EXPAND "\xee\xa5\x8f" // U+e94f +#define ICON_MD_EXPAND_CIRCLE_DOWN "\xee\x9f\x8d" // U+e7cd +#define ICON_MD_EXPAND_LESS "\xee\x97\x8e" // U+e5ce +#define ICON_MD_EXPAND_MORE "\xee\x97\x8f" // U+e5cf +#define ICON_MD_EXPLICIT "\xee\x80\x9e" // U+e01e +#define ICON_MD_EXPLORE "\xee\xa1\xba" // U+e87a +#define ICON_MD_EXPLORE_OFF "\xee\xa6\xa8" // U+e9a8 +#define ICON_MD_EXPOSURE "\xee\x8f\x8a" // U+e3ca +#define ICON_MD_EXPOSURE_MINUS_1 "\xee\x8f\x8b" // U+e3cb +#define ICON_MD_EXPOSURE_MINUS_2 "\xee\x8f\x8c" // U+e3cc +#define ICON_MD_EXPOSURE_NEG_1 "\xee\x8f\x8b" // U+e3cb +#define ICON_MD_EXPOSURE_NEG_2 "\xee\x8f\x8c" // U+e3cc +#define ICON_MD_EXPOSURE_PLUS_1 "\xee\x8f\x8d" // U+e3cd +#define ICON_MD_EXPOSURE_PLUS_2 "\xee\x8f\x8e" // U+e3ce +#define ICON_MD_EXPOSURE_ZERO "\xee\x8f\x8f" // U+e3cf +#define ICON_MD_EXTENSION "\xee\xa1\xbb" // U+e87b +#define ICON_MD_EXTENSION_OFF "\xee\x93\xb5" // U+e4f5 +#define ICON_MD_FACE "\xee\xa1\xbc" // U+e87c +#define ICON_MD_FACE_2 "\xef\xa3\x9a" // U+f8da +#define ICON_MD_FACE_3 "\xef\xa3\x9b" // U+f8db +#define ICON_MD_FACE_4 "\xef\xa3\x9c" // U+f8dc +#define ICON_MD_FACE_5 "\xef\xa3\x9d" // U+f8dd +#define ICON_MD_FACE_6 "\xef\xa3\x9e" // U+f8de +#define ICON_MD_FACE_RETOUCHING_NATURAL "\xee\xbd\x8e" // U+ef4e +#define ICON_MD_FACE_RETOUCHING_OFF "\xef\x80\x87" // U+f007 +#define ICON_MD_FACEBOOK "\xef\x88\xb4" // U+f234 +#define ICON_MD_FACT_CHECK "\xef\x83\x85" // U+f0c5 +#define ICON_MD_FACTORY "\xee\xae\xbc" // U+ebbc +#define ICON_MD_FAMILY_RESTROOM "\xef\x86\xa2" // U+f1a2 +#define ICON_MD_FAST_FORWARD "\xee\x80\x9f" // U+e01f +#define ICON_MD_FAST_REWIND "\xee\x80\xa0" // U+e020 +#define ICON_MD_FASTFOOD "\xee\x95\xba" // U+e57a +#define ICON_MD_FAVORITE "\xee\xa1\xbd" // U+e87d +#define ICON_MD_FAVORITE_BORDER "\xee\xa1\xbe" // U+e87e +#define ICON_MD_FAVORITE_OUTLINE "\xee\xa1\xbe" // U+e87e +#define ICON_MD_FAX "\xee\xab\x98" // U+ead8 +#define ICON_MD_FEATURED_PLAY_LIST "\xee\x81\xad" // U+e06d +#define ICON_MD_FEATURED_VIDEO "\xee\x81\xae" // U+e06e +#define ICON_MD_FEED "\xef\x80\x89" // U+f009 +#define ICON_MD_FEEDBACK "\xee\xa1\xbf" // U+e87f +#define ICON_MD_FEMALE "\xee\x96\x90" // U+e590 +#define ICON_MD_FENCE "\xef\x87\xb6" // U+f1f6 +#define ICON_MD_FESTIVAL "\xee\xa9\xa8" // U+ea68 +#define ICON_MD_FIBER_DVR "\xee\x81\x9d" // U+e05d +#define ICON_MD_FIBER_MANUAL_RECORD "\xee\x81\xa1" // U+e061 +#define ICON_MD_FIBER_NEW "\xee\x81\x9e" // U+e05e +#define ICON_MD_FIBER_PIN "\xee\x81\xaa" // U+e06a +#define ICON_MD_FIBER_SMART_RECORD "\xee\x81\xa2" // U+e062 +#define ICON_MD_FILE_COPY "\xee\x85\xb3" // U+e173 +#define ICON_MD_FILE_DOWNLOAD "\xee\x8b\x84" // U+e2c4 +#define ICON_MD_FILE_DOWNLOAD_DONE "\xee\xa6\xaa" // U+e9aa +#define ICON_MD_FILE_DOWNLOAD_OFF "\xee\x93\xbe" // U+e4fe +#define ICON_MD_FILE_OPEN "\xee\xab\xb3" // U+eaf3 +#define ICON_MD_FILE_PRESENT "\xee\xa8\x8e" // U+ea0e +#define ICON_MD_FILE_UPLOAD "\xee\x8b\x86" // U+e2c6 +#define ICON_MD_FILE_UPLOAD_OFF "\xef\xa2\x86" // U+f886 +#define ICON_MD_FILTER "\xee\x8f\x93" // U+e3d3 +#define ICON_MD_FILTER_1 "\xee\x8f\x90" // U+e3d0 +#define ICON_MD_FILTER_2 "\xee\x8f\x91" // U+e3d1 +#define ICON_MD_FILTER_3 "\xee\x8f\x92" // U+e3d2 +#define ICON_MD_FILTER_4 "\xee\x8f\x94" // U+e3d4 +#define ICON_MD_FILTER_5 "\xee\x8f\x95" // U+e3d5 +#define ICON_MD_FILTER_6 "\xee\x8f\x96" // U+e3d6 +#define ICON_MD_FILTER_7 "\xee\x8f\x97" // U+e3d7 +#define ICON_MD_FILTER_8 "\xee\x8f\x98" // U+e3d8 +#define ICON_MD_FILTER_9 "\xee\x8f\x99" // U+e3d9 +#define ICON_MD_FILTER_9_PLUS "\xee\x8f\x9a" // U+e3da +#define ICON_MD_FILTER_ALT "\xee\xbd\x8f" // U+ef4f +#define ICON_MD_FILTER_ALT_OFF "\xee\xac\xb2" // U+eb32 +#define ICON_MD_FILTER_B_AND_W "\xee\x8f\x9b" // U+e3db +#define ICON_MD_FILTER_CENTER_FOCUS "\xee\x8f\x9c" // U+e3dc +#define ICON_MD_FILTER_DRAMA "\xee\x8f\x9d" // U+e3dd +#define ICON_MD_FILTER_FRAMES "\xee\x8f\x9e" // U+e3de +#define ICON_MD_FILTER_HDR "\xee\x8f\x9f" // U+e3df +#define ICON_MD_FILTER_LIST "\xee\x85\x92" // U+e152 +#define ICON_MD_FILTER_LIST_ALT "\xee\xa5\x8e" // U+e94e +#define ICON_MD_FILTER_LIST_OFF "\xee\xad\x97" // U+eb57 +#define ICON_MD_FILTER_NONE "\xee\x8f\xa0" // U+e3e0 +#define ICON_MD_FILTER_TILT_SHIFT "\xee\x8f\xa2" // U+e3e2 +#define ICON_MD_FILTER_VINTAGE "\xee\x8f\xa3" // U+e3e3 +#define ICON_MD_FIND_IN_PAGE "\xee\xa2\x80" // U+e880 +#define ICON_MD_FIND_REPLACE "\xee\xa2\x81" // U+e881 +#define ICON_MD_FINGERPRINT "\xee\xa4\x8d" // U+e90d +#define ICON_MD_FIRE_EXTINGUISHER "\xef\x87\x98" // U+f1d8 +#define ICON_MD_FIRE_HYDRANT "\xef\x86\xa3" // U+f1a3 +#define ICON_MD_FIRE_HYDRANT_ALT "\xef\xa3\xb1" // U+f8f1 +#define ICON_MD_FIRE_TRUCK "\xef\xa3\xb2" // U+f8f2 +#define ICON_MD_FIREPLACE "\xee\xa9\x83" // U+ea43 +#define ICON_MD_FIRST_PAGE "\xee\x97\x9c" // U+e5dc +#define ICON_MD_FIT_SCREEN "\xee\xa8\x90" // U+ea10 +#define ICON_MD_FITBIT "\xee\xa0\xab" // U+e82b +#define ICON_MD_FITNESS_CENTER "\xee\xad\x83" // U+eb43 +#define ICON_MD_FLAG "\xee\x85\x93" // U+e153 +#define ICON_MD_FLAG_CIRCLE "\xee\xab\xb8" // U+eaf8 +#define ICON_MD_FLAKY "\xee\xbd\x90" // U+ef50 +#define ICON_MD_FLARE "\xee\x8f\xa4" // U+e3e4 +#define ICON_MD_FLASH_AUTO "\xee\x8f\xa5" // U+e3e5 +#define ICON_MD_FLASH_OFF "\xee\x8f\xa6" // U+e3e6 +#define ICON_MD_FLASH_ON "\xee\x8f\xa7" // U+e3e7 +#define ICON_MD_FLASHLIGHT_OFF "\xef\x80\x8a" // U+f00a +#define ICON_MD_FLASHLIGHT_ON "\xef\x80\x8b" // U+f00b +#define ICON_MD_FLATWARE "\xef\x80\x8c" // U+f00c +#define ICON_MD_FLIGHT "\xee\x94\xb9" // U+e539 +#define ICON_MD_FLIGHT_CLASS "\xee\x9f\x8b" // U+e7cb +#define ICON_MD_FLIGHT_LAND "\xee\xa4\x84" // U+e904 +#define ICON_MD_FLIGHT_TAKEOFF "\xee\xa4\x85" // U+e905 +#define ICON_MD_FLIP "\xee\x8f\xa8" // U+e3e8 +#define ICON_MD_FLIP_CAMERA_ANDROID "\xee\xa8\xb7" // U+ea37 +#define ICON_MD_FLIP_CAMERA_IOS "\xee\xa8\xb8" // U+ea38 +#define ICON_MD_FLIP_TO_BACK "\xee\xa2\x82" // U+e882 +#define ICON_MD_FLIP_TO_FRONT "\xee\xa2\x83" // U+e883 +#define ICON_MD_FLOOD "\xee\xaf\xa6" // U+ebe6 +#define ICON_MD_FLOURESCENT "\xef\x80\x8d" // U+f00d +#define ICON_MD_FLUORESCENT "\xee\xb0\xb1" // U+ec31 +#define ICON_MD_FLUTTER_DASH "\xee\x80\x8b" // U+e00b +#define ICON_MD_FMD_BAD "\xef\x80\x8e" // U+f00e +#define ICON_MD_FMD_GOOD "\xef\x80\x8f" // U+f00f +#define ICON_MD_FOGGY "\xee\xa0\x98" // U+e818 +#define ICON_MD_FOLDER "\xee\x8b\x87" // U+e2c7 +#define ICON_MD_FOLDER_COPY "\xee\xae\xbd" // U+ebbd +#define ICON_MD_FOLDER_DELETE "\xee\xac\xb4" // U+eb34 +#define ICON_MD_FOLDER_OFF "\xee\xae\x83" // U+eb83 +#define ICON_MD_FOLDER_OPEN "\xee\x8b\x88" // U+e2c8 +#define ICON_MD_FOLDER_SHARED "\xee\x8b\x89" // U+e2c9 +#define ICON_MD_FOLDER_SPECIAL "\xee\x98\x97" // U+e617 +#define ICON_MD_FOLDER_ZIP "\xee\xac\xac" // U+eb2c +#define ICON_MD_FOLLOW_THE_SIGNS "\xef\x88\xa2" // U+f222 +#define ICON_MD_FONT_DOWNLOAD "\xee\x85\xa7" // U+e167 +#define ICON_MD_FONT_DOWNLOAD_OFF "\xee\x93\xb9" // U+e4f9 +#define ICON_MD_FOOD_BANK "\xef\x87\xb2" // U+f1f2 +#define ICON_MD_FOREST "\xee\xaa\x99" // U+ea99 +#define ICON_MD_FORK_LEFT "\xee\xae\xa0" // U+eba0 +#define ICON_MD_FORK_RIGHT "\xee\xae\xac" // U+ebac +#define ICON_MD_FORKLIFT "\xef\xa1\xa8" // U+f868 +#define ICON_MD_FORMAT_ALIGN_CENTER "\xee\x88\xb4" // U+e234 +#define ICON_MD_FORMAT_ALIGN_JUSTIFY "\xee\x88\xb5" // U+e235 +#define ICON_MD_FORMAT_ALIGN_LEFT "\xee\x88\xb6" // U+e236 +#define ICON_MD_FORMAT_ALIGN_RIGHT "\xee\x88\xb7" // U+e237 +#define ICON_MD_FORMAT_BOLD "\xee\x88\xb8" // U+e238 +#define ICON_MD_FORMAT_CLEAR "\xee\x88\xb9" // U+e239 +#define ICON_MD_FORMAT_COLOR_FILL "\xee\x88\xba" // U+e23a +#define ICON_MD_FORMAT_COLOR_RESET "\xee\x88\xbb" // U+e23b +#define ICON_MD_FORMAT_COLOR_TEXT "\xee\x88\xbc" // U+e23c +#define ICON_MD_FORMAT_INDENT_DECREASE "\xee\x88\xbd" // U+e23d +#define ICON_MD_FORMAT_INDENT_INCREASE "\xee\x88\xbe" // U+e23e +#define ICON_MD_FORMAT_ITALIC "\xee\x88\xbf" // U+e23f +#define ICON_MD_FORMAT_LINE_SPACING "\xee\x89\x80" // U+e240 +#define ICON_MD_FORMAT_LIST_BULLETED "\xee\x89\x81" // U+e241 +#define ICON_MD_FORMAT_LIST_BULLETED_ADD "\xef\xa1\x89" // U+f849 +#define ICON_MD_FORMAT_LIST_NUMBERED "\xee\x89\x82" // U+e242 +#define ICON_MD_FORMAT_LIST_NUMBERED_RTL "\xee\x89\xa7" // U+e267 +#define ICON_MD_FORMAT_OVERLINE "\xee\xad\xa5" // U+eb65 +#define ICON_MD_FORMAT_PAINT "\xee\x89\x83" // U+e243 +#define ICON_MD_FORMAT_QUOTE "\xee\x89\x84" // U+e244 +#define ICON_MD_FORMAT_SHAPES "\xee\x89\x9e" // U+e25e +#define ICON_MD_FORMAT_SIZE "\xee\x89\x85" // U+e245 +#define ICON_MD_FORMAT_STRIKETHROUGH "\xee\x89\x86" // U+e246 +#define ICON_MD_FORMAT_TEXTDIRECTION_L_TO_R "\xee\x89\x87" // U+e247 +#define ICON_MD_FORMAT_TEXTDIRECTION_R_TO_L "\xee\x89\x88" // U+e248 +#define ICON_MD_FORMAT_UNDERLINE "\xee\x89\x89" // U+e249 +#define ICON_MD_FORMAT_UNDERLINED "\xee\x89\x89" // U+e249 +#define ICON_MD_FORT "\xee\xaa\xad" // U+eaad +#define ICON_MD_FORUM "\xee\x82\xbf" // U+e0bf +#define ICON_MD_FORWARD "\xee\x85\x94" // U+e154 +#define ICON_MD_FORWARD_10 "\xee\x81\x96" // U+e056 +#define ICON_MD_FORWARD_30 "\xee\x81\x97" // U+e057 +#define ICON_MD_FORWARD_5 "\xee\x81\x98" // U+e058 +#define ICON_MD_FORWARD_TO_INBOX "\xef\x86\x87" // U+f187 +#define ICON_MD_FOUNDATION "\xef\x88\x80" // U+f200 +#define ICON_MD_FREE_BREAKFAST "\xee\xad\x84" // U+eb44 +#define ICON_MD_FREE_CANCELLATION "\xee\x9d\x88" // U+e748 +#define ICON_MD_FRONT_HAND "\xee\x9d\xa9" // U+e769 +#define ICON_MD_FRONT_LOADER "\xef\xa1\xa9" // U+f869 +#define ICON_MD_FULLSCREEN "\xee\x97\x90" // U+e5d0 +#define ICON_MD_FULLSCREEN_EXIT "\xee\x97\x91" // U+e5d1 +#define ICON_MD_FUNCTIONS "\xee\x89\x8a" // U+e24a +#define ICON_MD_G_MOBILEDATA "\xef\x80\x90" // U+f010 +#define ICON_MD_G_TRANSLATE "\xee\xa4\xa7" // U+e927 +#define ICON_MD_GAMEPAD "\xee\x8c\x8f" // U+e30f +#define ICON_MD_GAMES "\xee\x80\xa1" // U+e021 +#define ICON_MD_GARAGE "\xef\x80\x91" // U+f011 +#define ICON_MD_GAS_METER "\xee\xb0\x99" // U+ec19 +#define ICON_MD_GAVEL "\xee\xa4\x8e" // U+e90e +#define ICON_MD_GENERATING_TOKENS "\xee\x9d\x89" // U+e749 +#define ICON_MD_GESTURE "\xee\x85\x95" // U+e155 +#define ICON_MD_GET_APP "\xee\xa2\x84" // U+e884 +#define ICON_MD_GIF "\xee\xa4\x88" // U+e908 +#define ICON_MD_GIF_BOX "\xee\x9e\xa3" // U+e7a3 +#define ICON_MD_GIRL "\xee\xad\xa8" // U+eb68 +#define ICON_MD_GITE "\xee\x96\x8b" // U+e58b +#define ICON_MD_GOAT "\xf4\x8f\xbf\xbd" // U+10fffd +#define ICON_MD_GOLF_COURSE "\xee\xad\x85" // U+eb45 +#define ICON_MD_GPP_BAD "\xef\x80\x92" // U+f012 +#define ICON_MD_GPP_GOOD "\xef\x80\x93" // U+f013 +#define ICON_MD_GPP_MAYBE "\xef\x80\x94" // U+f014 +#define ICON_MD_GPS_FIXED "\xee\x86\xb3" // U+e1b3 +#define ICON_MD_GPS_NOT_FIXED "\xee\x86\xb4" // U+e1b4 +#define ICON_MD_GPS_OFF "\xee\x86\xb5" // U+e1b5 +#define ICON_MD_GRADE "\xee\xa2\x85" // U+e885 +#define ICON_MD_GRADIENT "\xee\x8f\xa9" // U+e3e9 +#define ICON_MD_GRADING "\xee\xa9\x8f" // U+ea4f +#define ICON_MD_GRAIN "\xee\x8f\xaa" // U+e3ea +#define ICON_MD_GRAPHIC_EQ "\xee\x86\xb8" // U+e1b8 +#define ICON_MD_GRASS "\xef\x88\x85" // U+f205 +#define ICON_MD_GRID_3X3 "\xef\x80\x95" // U+f015 +#define ICON_MD_GRID_4X4 "\xef\x80\x96" // U+f016 +#define ICON_MD_GRID_GOLDENRATIO "\xef\x80\x97" // U+f017 +#define ICON_MD_GRID_OFF "\xee\x8f\xab" // U+e3eb +#define ICON_MD_GRID_ON "\xee\x8f\xac" // U+e3ec +#define ICON_MD_GRID_VIEW "\xee\xa6\xb0" // U+e9b0 +#define ICON_MD_GROUP "\xee\x9f\xaf" // U+e7ef +#define ICON_MD_GROUP_ADD "\xee\x9f\xb0" // U+e7f0 +#define ICON_MD_GROUP_OFF "\xee\x9d\x87" // U+e747 +#define ICON_MD_GROUP_REMOVE "\xee\x9e\xad" // U+e7ad +#define ICON_MD_GROUP_WORK "\xee\xa2\x86" // U+e886 +#define ICON_MD_GROUPS "\xef\x88\xb3" // U+f233 +#define ICON_MD_GROUPS_2 "\xef\xa3\x9f" // U+f8df +#define ICON_MD_GROUPS_3 "\xef\xa3\xa0" // U+f8e0 +#define ICON_MD_H_MOBILEDATA "\xef\x80\x98" // U+f018 +#define ICON_MD_H_PLUS_MOBILEDATA "\xef\x80\x99" // U+f019 +#define ICON_MD_HAIL "\xee\xa6\xb1" // U+e9b1 +#define ICON_MD_HANDSHAKE "\xee\xaf\x8b" // U+ebcb +#define ICON_MD_HANDYMAN "\xef\x84\x8b" // U+f10b +#define ICON_MD_HARDWARE "\xee\xa9\x99" // U+ea59 +#define ICON_MD_HD "\xee\x81\x92" // U+e052 +#define ICON_MD_HDR_AUTO "\xef\x80\x9a" // U+f01a +#define ICON_MD_HDR_AUTO_SELECT "\xef\x80\x9b" // U+f01b +#define ICON_MD_HDR_ENHANCED_SELECT "\xee\xbd\x91" // U+ef51 +#define ICON_MD_HDR_OFF "\xee\x8f\xad" // U+e3ed +#define ICON_MD_HDR_OFF_SELECT "\xef\x80\x9c" // U+f01c +#define ICON_MD_HDR_ON "\xee\x8f\xae" // U+e3ee +#define ICON_MD_HDR_ON_SELECT "\xef\x80\x9d" // U+f01d +#define ICON_MD_HDR_PLUS "\xef\x80\x9e" // U+f01e +#define ICON_MD_HDR_STRONG "\xee\x8f\xb1" // U+e3f1 +#define ICON_MD_HDR_WEAK "\xee\x8f\xb2" // U+e3f2 +#define ICON_MD_HEADPHONES "\xef\x80\x9f" // U+f01f +#define ICON_MD_HEADPHONES_BATTERY "\xef\x80\xa0" // U+f020 +#define ICON_MD_HEADSET "\xee\x8c\x90" // U+e310 +#define ICON_MD_HEADSET_MIC "\xee\x8c\x91" // U+e311 +#define ICON_MD_HEADSET_OFF "\xee\x8c\xba" // U+e33a +#define ICON_MD_HEALING "\xee\x8f\xb3" // U+e3f3 +#define ICON_MD_HEALTH_AND_SAFETY "\xee\x87\x95" // U+e1d5 +#define ICON_MD_HEARING "\xee\x80\xa3" // U+e023 +#define ICON_MD_HEARING_DISABLED "\xef\x84\x84" // U+f104 +#define ICON_MD_HEART_BROKEN "\xee\xab\x82" // U+eac2 +#define ICON_MD_HEAT_PUMP "\xee\xb0\x98" // U+ec18 +#define ICON_MD_HEIGHT "\xee\xa8\x96" // U+ea16 +#define ICON_MD_HELP "\xee\xa2\x87" // U+e887 +#define ICON_MD_HELP_CENTER "\xef\x87\x80" // U+f1c0 +#define ICON_MD_HELP_OUTLINE "\xee\xa3\xbd" // U+e8fd +#define ICON_MD_HEVC "\xef\x80\xa1" // U+f021 +#define ICON_MD_HEXAGON "\xee\xac\xb9" // U+eb39 +#define ICON_MD_HIDE_IMAGE "\xef\x80\xa2" // U+f022 +#define ICON_MD_HIDE_SOURCE "\xef\x80\xa3" // U+f023 +#define ICON_MD_HIGH_QUALITY "\xee\x80\xa4" // U+e024 +#define ICON_MD_HIGHLIGHT "\xee\x89\x9f" // U+e25f +#define ICON_MD_HIGHLIGHT_ALT "\xee\xbd\x92" // U+ef52 +#define ICON_MD_HIGHLIGHT_OFF "\xee\xa2\x88" // U+e888 +#define ICON_MD_HIGHLIGHT_REMOVE "\xee\xa2\x88" // U+e888 +#define ICON_MD_HIKING "\xee\x94\x8a" // U+e50a +#define ICON_MD_HISTORY "\xee\xa2\x89" // U+e889 +#define ICON_MD_HISTORY_EDU "\xee\xa8\xbe" // U+ea3e +#define ICON_MD_HISTORY_TOGGLE_OFF "\xef\x85\xbd" // U+f17d +#define ICON_MD_HIVE "\xee\xaa\xa6" // U+eaa6 +#define ICON_MD_HLS "\xee\xae\x8a" // U+eb8a +#define ICON_MD_HLS_OFF "\xee\xae\x8c" // U+eb8c +#define ICON_MD_HOLIDAY_VILLAGE "\xee\x96\x8a" // U+e58a +#define ICON_MD_HOME "\xee\xa2\x8a" // U+e88a +#define ICON_MD_HOME_FILLED "\xee\xa6\xb2" // U+e9b2 +#define ICON_MD_HOME_MAX "\xef\x80\xa4" // U+f024 +#define ICON_MD_HOME_MINI "\xef\x80\xa5" // U+f025 +#define ICON_MD_HOME_REPAIR_SERVICE "\xef\x84\x80" // U+f100 +#define ICON_MD_HOME_WORK "\xee\xa8\x89" // U+ea09 +#define ICON_MD_HORIZONTAL_DISTRIBUTE "\xee\x80\x94" // U+e014 +#define ICON_MD_HORIZONTAL_RULE "\xef\x84\x88" // U+f108 +#define ICON_MD_HORIZONTAL_SPLIT "\xee\xa5\x87" // U+e947 +#define ICON_MD_HOT_TUB "\xee\xad\x86" // U+eb46 +#define ICON_MD_HOTEL "\xee\x94\xba" // U+e53a +#define ICON_MD_HOTEL_CLASS "\xee\x9d\x83" // U+e743 +#define ICON_MD_HOURGLASS_BOTTOM "\xee\xa9\x9c" // U+ea5c +#define ICON_MD_HOURGLASS_DISABLED "\xee\xbd\x93" // U+ef53 +#define ICON_MD_HOURGLASS_EMPTY "\xee\xa2\x8b" // U+e88b +#define ICON_MD_HOURGLASS_FULL "\xee\xa2\x8c" // U+e88c +#define ICON_MD_HOURGLASS_TOP "\xee\xa9\x9b" // U+ea5b +#define ICON_MD_HOUSE "\xee\xa9\x84" // U+ea44 +#define ICON_MD_HOUSE_SIDING "\xef\x88\x82" // U+f202 +#define ICON_MD_HOUSEBOAT "\xee\x96\x84" // U+e584 +#define ICON_MD_HOW_TO_REG "\xee\x85\xb4" // U+e174 +#define ICON_MD_HOW_TO_VOTE "\xee\x85\xb5" // U+e175 +#define ICON_MD_HTML "\xee\xad\xbe" // U+eb7e +#define ICON_MD_HTTP "\xee\xa4\x82" // U+e902 +#define ICON_MD_HTTPS "\xee\xa2\x8d" // U+e88d +#define ICON_MD_HUB "\xee\xa7\xb4" // U+e9f4 +#define ICON_MD_HVAC "\xef\x84\x8e" // U+f10e +#define ICON_MD_ICE_SKATING "\xee\x94\x8b" // U+e50b +#define ICON_MD_ICECREAM "\xee\xa9\xa9" // U+ea69 +#define ICON_MD_IMAGE "\xee\x8f\xb4" // U+e3f4 +#define ICON_MD_IMAGE_ASPECT_RATIO "\xee\x8f\xb5" // U+e3f5 +#define ICON_MD_IMAGE_NOT_SUPPORTED "\xef\x84\x96" // U+f116 +#define ICON_MD_IMAGE_SEARCH "\xee\x90\xbf" // U+e43f +#define ICON_MD_IMAGESEARCH_ROLLER "\xee\xa6\xb4" // U+e9b4 +#define ICON_MD_IMPORT_CONTACTS "\xee\x83\xa0" // U+e0e0 +#define ICON_MD_IMPORT_EXPORT "\xee\x83\x83" // U+e0c3 +#define ICON_MD_IMPORTANT_DEVICES "\xee\xa4\x92" // U+e912 +#define ICON_MD_INBOX "\xee\x85\x96" // U+e156 +#define ICON_MD_INCOMPLETE_CIRCLE "\xee\x9e\x9b" // U+e79b +#define ICON_MD_INDETERMINATE_CHECK_BOX "\xee\xa4\x89" // U+e909 +#define ICON_MD_INFO "\xee\xa2\x8e" // U+e88e +#define ICON_MD_INFO_OUTLINE "\xee\xa2\x8f" // U+e88f +#define ICON_MD_INPUT "\xee\xa2\x90" // U+e890 +#define ICON_MD_INSERT_CHART "\xee\x89\x8b" // U+e24b +#define ICON_MD_INSERT_CHART_OUTLINED "\xee\x89\xaa" // U+e26a +#define ICON_MD_INSERT_COMMENT "\xee\x89\x8c" // U+e24c +#define ICON_MD_INSERT_DRIVE_FILE "\xee\x89\x8d" // U+e24d +#define ICON_MD_INSERT_EMOTICON "\xee\x89\x8e" // U+e24e +#define ICON_MD_INSERT_INVITATION "\xee\x89\x8f" // U+e24f +#define ICON_MD_INSERT_LINK "\xee\x89\x90" // U+e250 +#define ICON_MD_INSERT_PAGE_BREAK "\xee\xab\x8a" // U+eaca +#define ICON_MD_INSERT_PHOTO "\xee\x89\x91" // U+e251 +#define ICON_MD_INSIGHTS "\xef\x82\x92" // U+f092 +#define ICON_MD_INSTALL_DESKTOP "\xee\xad\xb1" // U+eb71 +#define ICON_MD_INSTALL_MOBILE "\xee\xad\xb2" // U+eb72 +#define ICON_MD_INTEGRATION_INSTRUCTIONS "\xee\xbd\x94" // U+ef54 +#define ICON_MD_INTERESTS "\xee\x9f\x88" // U+e7c8 +#define ICON_MD_INTERPRETER_MODE "\xee\xa0\xbb" // U+e83b +#define ICON_MD_INVENTORY "\xee\x85\xb9" // U+e179 +#define ICON_MD_INVENTORY_2 "\xee\x86\xa1" // U+e1a1 +#define ICON_MD_INVERT_COLORS "\xee\xa2\x91" // U+e891 +#define ICON_MD_INVERT_COLORS_OFF "\xee\x83\x84" // U+e0c4 +#define ICON_MD_INVERT_COLORS_ON "\xee\xa2\x91" // U+e891 +#define ICON_MD_IOS_SHARE "\xee\x9a\xb8" // U+e6b8 +#define ICON_MD_IRON "\xee\x96\x83" // U+e583 +#define ICON_MD_ISO "\xee\x8f\xb6" // U+e3f6 +#define ICON_MD_JAVASCRIPT "\xee\xad\xbc" // U+eb7c +#define ICON_MD_JOIN_FULL "\xee\xab\xab" // U+eaeb +#define ICON_MD_JOIN_INNER "\xee\xab\xb4" // U+eaf4 +#define ICON_MD_JOIN_LEFT "\xee\xab\xb2" // U+eaf2 +#define ICON_MD_JOIN_RIGHT "\xee\xab\xaa" // U+eaea +#define ICON_MD_KAYAKING "\xee\x94\x8c" // U+e50c +#define ICON_MD_KEBAB_DINING "\xee\xa1\x82" // U+e842 +#define ICON_MD_KEY "\xee\x9c\xbc" // U+e73c +#define ICON_MD_KEY_OFF "\xee\xae\x84" // U+eb84 +#define ICON_MD_KEYBOARD "\xee\x8c\x92" // U+e312 +#define ICON_MD_KEYBOARD_ALT "\xef\x80\xa8" // U+f028 +#define ICON_MD_KEYBOARD_ARROW_DOWN "\xee\x8c\x93" // U+e313 +#define ICON_MD_KEYBOARD_ARROW_LEFT "\xee\x8c\x94" // U+e314 +#define ICON_MD_KEYBOARD_ARROW_RIGHT "\xee\x8c\x95" // U+e315 +#define ICON_MD_KEYBOARD_ARROW_UP "\xee\x8c\x96" // U+e316 +#define ICON_MD_KEYBOARD_BACKSPACE "\xee\x8c\x97" // U+e317 +#define ICON_MD_KEYBOARD_CAPSLOCK "\xee\x8c\x98" // U+e318 +#define ICON_MD_KEYBOARD_COMMAND "\xee\xab\xa0" // U+eae0 +#define ICON_MD_KEYBOARD_COMMAND_KEY "\xee\xab\xa7" // U+eae7 +#define ICON_MD_KEYBOARD_CONTROL "\xee\x97\x93" // U+e5d3 +#define ICON_MD_KEYBOARD_CONTROL_KEY "\xee\xab\xa6" // U+eae6 +#define ICON_MD_KEYBOARD_DOUBLE_ARROW_DOWN "\xee\xab\x90" // U+ead0 +#define ICON_MD_KEYBOARD_DOUBLE_ARROW_LEFT "\xee\xab\x83" // U+eac3 +#define ICON_MD_KEYBOARD_DOUBLE_ARROW_RIGHT "\xee\xab\x89" // U+eac9 +#define ICON_MD_KEYBOARD_DOUBLE_ARROW_UP "\xee\xab\x8f" // U+eacf +#define ICON_MD_KEYBOARD_HIDE "\xee\x8c\x9a" // U+e31a +#define ICON_MD_KEYBOARD_OPTION "\xee\xab\x9f" // U+eadf +#define ICON_MD_KEYBOARD_OPTION_KEY "\xee\xab\xa8" // U+eae8 +#define ICON_MD_KEYBOARD_RETURN "\xee\x8c\x9b" // U+e31b +#define ICON_MD_KEYBOARD_TAB "\xee\x8c\x9c" // U+e31c +#define ICON_MD_KEYBOARD_VOICE "\xee\x8c\x9d" // U+e31d +#define ICON_MD_KING_BED "\xee\xa9\x85" // U+ea45 +#define ICON_MD_KITCHEN "\xee\xad\x87" // U+eb47 +#define ICON_MD_KITESURFING "\xee\x94\x8d" // U+e50d +#define ICON_MD_LABEL "\xee\xa2\x92" // U+e892 +#define ICON_MD_LABEL_IMPORTANT "\xee\xa4\xb7" // U+e937 +#define ICON_MD_LABEL_IMPORTANT_OUTLINE "\xee\xa5\x88" // U+e948 +#define ICON_MD_LABEL_OFF "\xee\xa6\xb6" // U+e9b6 +#define ICON_MD_LABEL_OUTLINE "\xee\xa2\x93" // U+e893 +#define ICON_MD_LAN "\xee\xac\xaf" // U+eb2f +#define ICON_MD_LANDSCAPE "\xee\x8f\xb7" // U+e3f7 +#define ICON_MD_LANDSLIDE "\xee\xaf\x97" // U+ebd7 +#define ICON_MD_LANGUAGE "\xee\xa2\x94" // U+e894 +#define ICON_MD_LAPTOP "\xee\x8c\x9e" // U+e31e +#define ICON_MD_LAPTOP_CHROMEBOOK "\xee\x8c\x9f" // U+e31f +#define ICON_MD_LAPTOP_MAC "\xee\x8c\xa0" // U+e320 +#define ICON_MD_LAPTOP_WINDOWS "\xee\x8c\xa1" // U+e321 +#define ICON_MD_LAST_PAGE "\xee\x97\x9d" // U+e5dd +#define ICON_MD_LAUNCH "\xee\xa2\x95" // U+e895 +#define ICON_MD_LAYERS "\xee\x94\xbb" // U+e53b +#define ICON_MD_LAYERS_CLEAR "\xee\x94\xbc" // U+e53c +#define ICON_MD_LEADERBOARD "\xef\x88\x8c" // U+f20c +#define ICON_MD_LEAK_ADD "\xee\x8f\xb8" // U+e3f8 +#define ICON_MD_LEAK_REMOVE "\xee\x8f\xb9" // U+e3f9 +#define ICON_MD_LEAVE_BAGS_AT_HOME "\xef\x88\x9b" // U+f21b +#define ICON_MD_LEGEND_TOGGLE "\xef\x84\x9b" // U+f11b +#define ICON_MD_LENS "\xee\x8f\xba" // U+e3fa +#define ICON_MD_LENS_BLUR "\xef\x80\xa9" // U+f029 +#define ICON_MD_LIBRARY_ADD "\xee\x80\xae" // U+e02e +#define ICON_MD_LIBRARY_ADD_CHECK "\xee\xa6\xb7" // U+e9b7 +#define ICON_MD_LIBRARY_BOOKS "\xee\x80\xaf" // U+e02f +#define ICON_MD_LIBRARY_MUSIC "\xee\x80\xb0" // U+e030 +#define ICON_MD_LIGHT "\xef\x80\xaa" // U+f02a +#define ICON_MD_LIGHT_MODE "\xee\x94\x98" // U+e518 +#define ICON_MD_LIGHTBULB "\xee\x83\xb0" // U+e0f0 +#define ICON_MD_LIGHTBULB_CIRCLE "\xee\xaf\xbe" // U+ebfe +#define ICON_MD_LIGHTBULB_OUTLINE "\xee\xa4\x8f" // U+e90f +#define ICON_MD_LINE_AXIS "\xee\xaa\x9a" // U+ea9a +#define ICON_MD_LINE_STYLE "\xee\xa4\x99" // U+e919 +#define ICON_MD_LINE_WEIGHT "\xee\xa4\x9a" // U+e91a +#define ICON_MD_LINEAR_SCALE "\xee\x89\xa0" // U+e260 +#define ICON_MD_LINK "\xee\x85\x97" // U+e157 +#define ICON_MD_LINK_OFF "\xee\x85\xaf" // U+e16f +#define ICON_MD_LINKED_CAMERA "\xee\x90\xb8" // U+e438 +#define ICON_MD_LIQUOR "\xee\xa9\xa0" // U+ea60 +#define ICON_MD_LIST "\xee\xa2\x96" // U+e896 +#define ICON_MD_LIST_ALT "\xee\x83\xae" // U+e0ee +#define ICON_MD_LIVE_HELP "\xee\x83\x86" // U+e0c6 +#define ICON_MD_LIVE_TV "\xee\x98\xb9" // U+e639 +#define ICON_MD_LIVING "\xef\x80\xab" // U+f02b +#define ICON_MD_LOCAL_ACTIVITY "\xee\x94\xbf" // U+e53f +#define ICON_MD_LOCAL_AIRPORT "\xee\x94\xbd" // U+e53d +#define ICON_MD_LOCAL_ATM "\xee\x94\xbe" // U+e53e +#define ICON_MD_LOCAL_ATTRACTION "\xee\x94\xbf" // U+e53f +#define ICON_MD_LOCAL_BAR "\xee\x95\x80" // U+e540 +#define ICON_MD_LOCAL_CAFE "\xee\x95\x81" // U+e541 +#define ICON_MD_LOCAL_CAR_WASH "\xee\x95\x82" // U+e542 +#define ICON_MD_LOCAL_CONVENIENCE_STORE "\xee\x95\x83" // U+e543 +#define ICON_MD_LOCAL_DINING "\xee\x95\x96" // U+e556 +#define ICON_MD_LOCAL_DRINK "\xee\x95\x84" // U+e544 +#define ICON_MD_LOCAL_FIRE_DEPARTMENT "\xee\xbd\x95" // U+ef55 +#define ICON_MD_LOCAL_FLORIST "\xee\x95\x85" // U+e545 +#define ICON_MD_LOCAL_GAS_STATION "\xee\x95\x86" // U+e546 +#define ICON_MD_LOCAL_GROCERY_STORE "\xee\x95\x87" // U+e547 +#define ICON_MD_LOCAL_HOSPITAL "\xee\x95\x88" // U+e548 +#define ICON_MD_LOCAL_HOTEL "\xee\x95\x89" // U+e549 +#define ICON_MD_LOCAL_LAUNDRY_SERVICE "\xee\x95\x8a" // U+e54a +#define ICON_MD_LOCAL_LIBRARY "\xee\x95\x8b" // U+e54b +#define ICON_MD_LOCAL_MALL "\xee\x95\x8c" // U+e54c +#define ICON_MD_LOCAL_MOVIES "\xee\x95\x8d" // U+e54d +#define ICON_MD_LOCAL_OFFER "\xee\x95\x8e" // U+e54e +#define ICON_MD_LOCAL_PARKING "\xee\x95\x8f" // U+e54f +#define ICON_MD_LOCAL_PHARMACY "\xee\x95\x90" // U+e550 +#define ICON_MD_LOCAL_PHONE "\xee\x95\x91" // U+e551 +#define ICON_MD_LOCAL_PIZZA "\xee\x95\x92" // U+e552 +#define ICON_MD_LOCAL_PLAY "\xee\x95\x93" // U+e553 +#define ICON_MD_LOCAL_POLICE "\xee\xbd\x96" // U+ef56 +#define ICON_MD_LOCAL_POST_OFFICE "\xee\x95\x94" // U+e554 +#define ICON_MD_LOCAL_PRINT_SHOP "\xee\x95\x95" // U+e555 +#define ICON_MD_LOCAL_PRINTSHOP "\xee\x95\x95" // U+e555 +#define ICON_MD_LOCAL_RESTAURANT "\xee\x95\x96" // U+e556 +#define ICON_MD_LOCAL_SEE "\xee\x95\x97" // U+e557 +#define ICON_MD_LOCAL_SHIPPING "\xee\x95\x98" // U+e558 +#define ICON_MD_LOCAL_TAXI "\xee\x95\x99" // U+e559 +#define ICON_MD_LOCATION_CITY "\xee\x9f\xb1" // U+e7f1 +#define ICON_MD_LOCATION_DISABLED "\xee\x86\xb6" // U+e1b6 +#define ICON_MD_LOCATION_HISTORY "\xee\x95\x9a" // U+e55a +#define ICON_MD_LOCATION_OFF "\xee\x83\x87" // U+e0c7 +#define ICON_MD_LOCATION_ON "\xee\x83\x88" // U+e0c8 +#define ICON_MD_LOCATION_PIN "\xef\x87\x9b" // U+f1db +#define ICON_MD_LOCATION_SEARCHING "\xee\x86\xb7" // U+e1b7 +#define ICON_MD_LOCK "\xee\xa2\x97" // U+e897 +#define ICON_MD_LOCK_CLOCK "\xee\xbd\x97" // U+ef57 +#define ICON_MD_LOCK_OPEN "\xee\xa2\x98" // U+e898 +#define ICON_MD_LOCK_OUTLINE "\xee\xa2\x99" // U+e899 +#define ICON_MD_LOCK_PERSON "\xef\xa3\xb3" // U+f8f3 +#define ICON_MD_LOCK_RESET "\xee\xab\x9e" // U+eade +#define ICON_MD_LOGIN "\xee\xa9\xb7" // U+ea77 +#define ICON_MD_LOGO_DEV "\xee\xab\x96" // U+ead6 +#define ICON_MD_LOGOUT "\xee\xa6\xba" // U+e9ba +#define ICON_MD_LOOKS "\xee\x8f\xbc" // U+e3fc +#define ICON_MD_LOOKS_3 "\xee\x8f\xbb" // U+e3fb +#define ICON_MD_LOOKS_4 "\xee\x8f\xbd" // U+e3fd +#define ICON_MD_LOOKS_5 "\xee\x8f\xbe" // U+e3fe +#define ICON_MD_LOOKS_6 "\xee\x8f\xbf" // U+e3ff +#define ICON_MD_LOOKS_ONE "\xee\x90\x80" // U+e400 +#define ICON_MD_LOOKS_TWO "\xee\x90\x81" // U+e401 +#define ICON_MD_LOOP "\xee\x80\xa8" // U+e028 +#define ICON_MD_LOUPE "\xee\x90\x82" // U+e402 +#define ICON_MD_LOW_PRIORITY "\xee\x85\xad" // U+e16d +#define ICON_MD_LOYALTY "\xee\xa2\x9a" // U+e89a +#define ICON_MD_LTE_MOBILEDATA "\xef\x80\xac" // U+f02c +#define ICON_MD_LTE_PLUS_MOBILEDATA "\xef\x80\xad" // U+f02d +#define ICON_MD_LUGGAGE "\xef\x88\xb5" // U+f235 +#define ICON_MD_LUNCH_DINING "\xee\xa9\xa1" // U+ea61 +#define ICON_MD_LYRICS "\xee\xb0\x8b" // U+ec0b +#define ICON_MD_MACRO_OFF "\xef\xa3\x92" // U+f8d2 +#define ICON_MD_MAIL "\xee\x85\x98" // U+e158 +#define ICON_MD_MAIL_LOCK "\xee\xb0\x8a" // U+ec0a +#define ICON_MD_MAIL_OUTLINE "\xee\x83\xa1" // U+e0e1 +#define ICON_MD_MALE "\xee\x96\x8e" // U+e58e +#define ICON_MD_MAN "\xee\x93\xab" // U+e4eb +#define ICON_MD_MAN_2 "\xef\xa3\xa1" // U+f8e1 +#define ICON_MD_MAN_3 "\xef\xa3\xa2" // U+f8e2 +#define ICON_MD_MAN_4 "\xef\xa3\xa3" // U+f8e3 +#define ICON_MD_MANAGE_ACCOUNTS "\xef\x80\xae" // U+f02e +#define ICON_MD_MANAGE_HISTORY "\xee\xaf\xa7" // U+ebe7 +#define ICON_MD_MANAGE_SEARCH "\xef\x80\xaf" // U+f02f +#define ICON_MD_MAP "\xee\x95\x9b" // U+e55b +#define ICON_MD_MAPS_HOME_WORK "\xef\x80\xb0" // U+f030 +#define ICON_MD_MAPS_UGC "\xee\xbd\x98" // U+ef58 +#define ICON_MD_MARGIN "\xee\xa6\xbb" // U+e9bb +#define ICON_MD_MARK_AS_UNREAD "\xee\xa6\xbc" // U+e9bc +#define ICON_MD_MARK_CHAT_READ "\xef\x86\x8b" // U+f18b +#define ICON_MD_MARK_CHAT_UNREAD "\xef\x86\x89" // U+f189 +#define ICON_MD_MARK_EMAIL_READ "\xef\x86\x8c" // U+f18c +#define ICON_MD_MARK_EMAIL_UNREAD "\xef\x86\x8a" // U+f18a +#define ICON_MD_MARK_UNREAD_CHAT_ALT "\xee\xae\x9d" // U+eb9d +#define ICON_MD_MARKUNREAD "\xee\x85\x99" // U+e159 +#define ICON_MD_MARKUNREAD_MAILBOX "\xee\xa2\x9b" // U+e89b +#define ICON_MD_MASKS "\xef\x88\x98" // U+f218 +#define ICON_MD_MAXIMIZE "\xee\xa4\xb0" // U+e930 +#define ICON_MD_MEDIA_BLUETOOTH_OFF "\xef\x80\xb1" // U+f031 +#define ICON_MD_MEDIA_BLUETOOTH_ON "\xef\x80\xb2" // U+f032 +#define ICON_MD_MEDIATION "\xee\xbe\xa7" // U+efa7 +#define ICON_MD_MEDICAL_INFORMATION "\xee\xaf\xad" // U+ebed +#define ICON_MD_MEDICAL_SERVICES "\xef\x84\x89" // U+f109 +#define ICON_MD_MEDICATION "\xef\x80\xb3" // U+f033 +#define ICON_MD_MEDICATION_LIQUID "\xee\xaa\x87" // U+ea87 +#define ICON_MD_MEETING_ROOM "\xee\xad\x8f" // U+eb4f +#define ICON_MD_MEMORY "\xee\x8c\xa2" // U+e322 +#define ICON_MD_MENU "\xee\x97\x92" // U+e5d2 +#define ICON_MD_MENU_BOOK "\xee\xa8\x99" // U+ea19 +#define ICON_MD_MENU_OPEN "\xee\xa6\xbd" // U+e9bd +#define ICON_MD_MERGE "\xee\xae\x98" // U+eb98 +#define ICON_MD_MERGE_TYPE "\xee\x89\x92" // U+e252 +#define ICON_MD_MESSAGE "\xee\x83\x89" // U+e0c9 +#define ICON_MD_MESSENGER "\xee\x83\x8a" // U+e0ca +#define ICON_MD_MESSENGER_OUTLINE "\xee\x83\x8b" // U+e0cb +#define ICON_MD_MIC "\xee\x80\xa9" // U+e029 +#define ICON_MD_MIC_EXTERNAL_OFF "\xee\xbd\x99" // U+ef59 +#define ICON_MD_MIC_EXTERNAL_ON "\xee\xbd\x9a" // U+ef5a +#define ICON_MD_MIC_NONE "\xee\x80\xaa" // U+e02a +#define ICON_MD_MIC_OFF "\xee\x80\xab" // U+e02b +#define ICON_MD_MICROWAVE "\xef\x88\x84" // U+f204 +#define ICON_MD_MILITARY_TECH "\xee\xa8\xbf" // U+ea3f +#define ICON_MD_MINIMIZE "\xee\xa4\xb1" // U+e931 +#define ICON_MD_MINOR_CRASH "\xee\xaf\xb1" // U+ebf1 +#define ICON_MD_MISCELLANEOUS_SERVICES "\xef\x84\x8c" // U+f10c +#define ICON_MD_MISSED_VIDEO_CALL "\xee\x81\xb3" // U+e073 +#define ICON_MD_MMS "\xee\x98\x98" // U+e618 +#define ICON_MD_MOBILE_FRIENDLY "\xee\x88\x80" // U+e200 +#define ICON_MD_MOBILE_OFF "\xee\x88\x81" // U+e201 +#define ICON_MD_MOBILE_SCREEN_SHARE "\xee\x83\xa7" // U+e0e7 +#define ICON_MD_MOBILEDATA_OFF "\xef\x80\xb4" // U+f034 +#define ICON_MD_MODE "\xef\x82\x97" // U+f097 +#define ICON_MD_MODE_COMMENT "\xee\x89\x93" // U+e253 +#define ICON_MD_MODE_EDIT "\xee\x89\x94" // U+e254 +#define ICON_MD_MODE_EDIT_OUTLINE "\xef\x80\xb5" // U+f035 +#define ICON_MD_MODE_FAN_OFF "\xee\xb0\x97" // U+ec17 +#define ICON_MD_MODE_NIGHT "\xef\x80\xb6" // U+f036 +#define ICON_MD_MODE_OF_TRAVEL "\xee\x9f\x8e" // U+e7ce +#define ICON_MD_MODE_STANDBY "\xef\x80\xb7" // U+f037 +#define ICON_MD_MODEL_TRAINING "\xef\x83\x8f" // U+f0cf +#define ICON_MD_MONETIZATION_ON "\xee\x89\xa3" // U+e263 +#define ICON_MD_MONEY "\xee\x95\xbd" // U+e57d +#define ICON_MD_MONEY_OFF "\xee\x89\x9c" // U+e25c +#define ICON_MD_MONEY_OFF_CSRED "\xef\x80\xb8" // U+f038 +#define ICON_MD_MONITOR "\xee\xbd\x9b" // U+ef5b +#define ICON_MD_MONITOR_HEART "\xee\xaa\xa2" // U+eaa2 +#define ICON_MD_MONITOR_WEIGHT "\xef\x80\xb9" // U+f039 +#define ICON_MD_MONOCHROME_PHOTOS "\xee\x90\x83" // U+e403 +#define ICON_MD_MOOD "\xee\x9f\xb2" // U+e7f2 +#define ICON_MD_MOOD_BAD "\xee\x9f\xb3" // U+e7f3 +#define ICON_MD_MOPED "\xee\xac\xa8" // U+eb28 +#define ICON_MD_MORE "\xee\x98\x99" // U+e619 +#define ICON_MD_MORE_HORIZ "\xee\x97\x93" // U+e5d3 +#define ICON_MD_MORE_TIME "\xee\xa9\x9d" // U+ea5d +#define ICON_MD_MORE_VERT "\xee\x97\x94" // U+e5d4 +#define ICON_MD_MOSQUE "\xee\xaa\xb2" // U+eab2 +#define ICON_MD_MOTION_PHOTOS_AUTO "\xef\x80\xba" // U+f03a +#define ICON_MD_MOTION_PHOTOS_OFF "\xee\xa7\x80" // U+e9c0 +#define ICON_MD_MOTION_PHOTOS_ON "\xee\xa7\x81" // U+e9c1 +#define ICON_MD_MOTION_PHOTOS_PAUSE "\xef\x88\xa7" // U+f227 +#define ICON_MD_MOTION_PHOTOS_PAUSED "\xee\xa7\x82" // U+e9c2 +#define ICON_MD_MOTORCYCLE "\xee\xa4\x9b" // U+e91b +#define ICON_MD_MOUSE "\xee\x8c\xa3" // U+e323 +#define ICON_MD_MOVE_DOWN "\xee\xad\xa1" // U+eb61 +#define ICON_MD_MOVE_TO_INBOX "\xee\x85\xa8" // U+e168 +#define ICON_MD_MOVE_UP "\xee\xad\xa4" // U+eb64 +#define ICON_MD_MOVIE "\xee\x80\xac" // U+e02c +#define ICON_MD_MOVIE_CREATION "\xee\x90\x84" // U+e404 +#define ICON_MD_MOVIE_EDIT "\xef\xa1\x80" // U+f840 +#define ICON_MD_MOVIE_FILTER "\xee\x90\xba" // U+e43a +#define ICON_MD_MOVING "\xee\x94\x81" // U+e501 +#define ICON_MD_MP "\xee\xa7\x83" // U+e9c3 +#define ICON_MD_MULTILINE_CHART "\xee\x9b\x9f" // U+e6df +#define ICON_MD_MULTIPLE_STOP "\xef\x86\xb9" // U+f1b9 +#define ICON_MD_MULTITRACK_AUDIO "\xee\x86\xb8" // U+e1b8 +#define ICON_MD_MUSEUM "\xee\xa8\xb6" // U+ea36 +#define ICON_MD_MUSIC_NOTE "\xee\x90\x85" // U+e405 +#define ICON_MD_MUSIC_OFF "\xee\x91\x80" // U+e440 +#define ICON_MD_MUSIC_VIDEO "\xee\x81\xa3" // U+e063 +#define ICON_MD_MY_LIBRARY_ADD "\xee\x80\xae" // U+e02e +#define ICON_MD_MY_LIBRARY_BOOKS "\xee\x80\xaf" // U+e02f +#define ICON_MD_MY_LIBRARY_MUSIC "\xee\x80\xb0" // U+e030 +#define ICON_MD_MY_LOCATION "\xee\x95\x9c" // U+e55c +#define ICON_MD_NAT "\xee\xbd\x9c" // U+ef5c +#define ICON_MD_NATURE "\xee\x90\x86" // U+e406 +#define ICON_MD_NATURE_PEOPLE "\xee\x90\x87" // U+e407 +#define ICON_MD_NAVIGATE_BEFORE "\xee\x90\x88" // U+e408 +#define ICON_MD_NAVIGATE_NEXT "\xee\x90\x89" // U+e409 +#define ICON_MD_NAVIGATION "\xee\x95\x9d" // U+e55d +#define ICON_MD_NEAR_ME "\xee\x95\xa9" // U+e569 +#define ICON_MD_NEAR_ME_DISABLED "\xef\x87\xaf" // U+f1ef +#define ICON_MD_NEARBY_ERROR "\xef\x80\xbb" // U+f03b +#define ICON_MD_NEARBY_OFF "\xef\x80\xbc" // U+f03c +#define ICON_MD_NEST_CAM_WIRED_STAND "\xee\xb0\x96" // U+ec16 +#define ICON_MD_NETWORK_CELL "\xee\x86\xb9" // U+e1b9 +#define ICON_MD_NETWORK_CHECK "\xee\x99\x80" // U+e640 +#define ICON_MD_NETWORK_LOCKED "\xee\x98\x9a" // U+e61a +#define ICON_MD_NETWORK_PING "\xee\xaf\x8a" // U+ebca +#define ICON_MD_NETWORK_WIFI "\xee\x86\xba" // U+e1ba +#define ICON_MD_NETWORK_WIFI_1_BAR "\xee\xaf\xa4" // U+ebe4 +#define ICON_MD_NETWORK_WIFI_2_BAR "\xee\xaf\x96" // U+ebd6 +#define ICON_MD_NETWORK_WIFI_3_BAR "\xee\xaf\xa1" // U+ebe1 +#define ICON_MD_NEW_LABEL "\xee\x98\x89" // U+e609 +#define ICON_MD_NEW_RELEASES "\xee\x80\xb1" // U+e031 +#define ICON_MD_NEWSPAPER "\xee\xae\x81" // U+eb81 +#define ICON_MD_NEXT_PLAN "\xee\xbd\x9d" // U+ef5d +#define ICON_MD_NEXT_WEEK "\xee\x85\xaa" // U+e16a +#define ICON_MD_NFC "\xee\x86\xbb" // U+e1bb +#define ICON_MD_NIGHT_SHELTER "\xef\x87\xb1" // U+f1f1 +#define ICON_MD_NIGHTLIFE "\xee\xa9\xa2" // U+ea62 +#define ICON_MD_NIGHTLIGHT "\xef\x80\xbd" // U+f03d +#define ICON_MD_NIGHTLIGHT_ROUND "\xee\xbd\x9e" // U+ef5e +#define ICON_MD_NIGHTS_STAY "\xee\xa9\x86" // U+ea46 +#define ICON_MD_NO_ACCOUNTS "\xef\x80\xbe" // U+f03e +#define ICON_MD_NO_ADULT_CONTENT "\xef\xa3\xbe" // U+f8fe +#define ICON_MD_NO_BACKPACK "\xef\x88\xb7" // U+f237 +#define ICON_MD_NO_CELL "\xef\x86\xa4" // U+f1a4 +#define ICON_MD_NO_CRASH "\xee\xaf\xb0" // U+ebf0 +#define ICON_MD_NO_DRINKS "\xef\x86\xa5" // U+f1a5 +#define ICON_MD_NO_ENCRYPTION "\xee\x99\x81" // U+e641 +#define ICON_MD_NO_ENCRYPTION_GMAILERRORRED "\xef\x80\xbf" // U+f03f +#define ICON_MD_NO_FLASH "\xef\x86\xa6" // U+f1a6 +#define ICON_MD_NO_FOOD "\xef\x86\xa7" // U+f1a7 +#define ICON_MD_NO_LUGGAGE "\xef\x88\xbb" // U+f23b +#define ICON_MD_NO_MEALS "\xef\x87\x96" // U+f1d6 +#define ICON_MD_NO_MEALS_OULINE "\xef\x88\xa9" // U+f229 +#define ICON_MD_NO_MEETING_ROOM "\xee\xad\x8e" // U+eb4e +#define ICON_MD_NO_PHOTOGRAPHY "\xef\x86\xa8" // U+f1a8 +#define ICON_MD_NO_SIM "\xee\x83\x8c" // U+e0cc +#define ICON_MD_NO_STROLLER "\xef\x86\xaf" // U+f1af +#define ICON_MD_NO_TRANSFER "\xef\x87\x95" // U+f1d5 +#define ICON_MD_NOISE_AWARE "\xee\xaf\xac" // U+ebec +#define ICON_MD_NOISE_CONTROL_OFF "\xee\xaf\xb3" // U+ebf3 +#define ICON_MD_NORDIC_WALKING "\xee\x94\x8e" // U+e50e +#define ICON_MD_NORTH "\xef\x87\xa0" // U+f1e0 +#define ICON_MD_NORTH_EAST "\xef\x87\xa1" // U+f1e1 +#define ICON_MD_NORTH_WEST "\xef\x87\xa2" // U+f1e2 +#define ICON_MD_NOT_ACCESSIBLE "\xef\x83\xbe" // U+f0fe +#define ICON_MD_NOT_INTERESTED "\xee\x80\xb3" // U+e033 +#define ICON_MD_NOT_LISTED_LOCATION "\xee\x95\xb5" // U+e575 +#define ICON_MD_NOT_STARTED "\xef\x83\x91" // U+f0d1 +#define ICON_MD_NOTE "\xee\x81\xaf" // U+e06f +#define ICON_MD_NOTE_ADD "\xee\xa2\x9c" // U+e89c +#define ICON_MD_NOTE_ALT "\xef\x81\x80" // U+f040 +#define ICON_MD_NOTES "\xee\x89\xac" // U+e26c +#define ICON_MD_NOTIFICATION_ADD "\xee\x8e\x99" // U+e399 +#define ICON_MD_NOTIFICATION_IMPORTANT "\xee\x80\x84" // U+e004 +#define ICON_MD_NOTIFICATIONS "\xee\x9f\xb4" // U+e7f4 +#define ICON_MD_NOTIFICATIONS_ACTIVE "\xee\x9f\xb7" // U+e7f7 +#define ICON_MD_NOTIFICATIONS_NONE "\xee\x9f\xb5" // U+e7f5 +#define ICON_MD_NOTIFICATIONS_OFF "\xee\x9f\xb6" // U+e7f6 +#define ICON_MD_NOTIFICATIONS_ON "\xee\x9f\xb7" // U+e7f7 +#define ICON_MD_NOTIFICATIONS_PAUSED "\xee\x9f\xb8" // U+e7f8 +#define ICON_MD_NOW_WALLPAPER "\xee\x86\xbc" // U+e1bc +#define ICON_MD_NOW_WIDGETS "\xee\x86\xbd" // U+e1bd +#define ICON_MD_NUMBERS "\xee\xab\x87" // U+eac7 +#define ICON_MD_OFFLINE_BOLT "\xee\xa4\xb2" // U+e932 +#define ICON_MD_OFFLINE_PIN "\xee\xa4\x8a" // U+e90a +#define ICON_MD_OFFLINE_SHARE "\xee\xa7\x85" // U+e9c5 +#define ICON_MD_OIL_BARREL "\xee\xb0\x95" // U+ec15 +#define ICON_MD_ON_DEVICE_TRAINING "\xee\xaf\xbd" // U+ebfd +#define ICON_MD_ONDEMAND_VIDEO "\xee\x98\xba" // U+e63a +#define ICON_MD_ONLINE_PREDICTION "\xef\x83\xab" // U+f0eb +#define ICON_MD_OPACITY "\xee\xa4\x9c" // U+e91c +#define ICON_MD_OPEN_IN_BROWSER "\xee\xa2\x9d" // U+e89d +#define ICON_MD_OPEN_IN_FULL "\xef\x87\x8e" // U+f1ce +#define ICON_MD_OPEN_IN_NEW "\xee\xa2\x9e" // U+e89e +#define ICON_MD_OPEN_IN_NEW_OFF "\xee\x93\xb6" // U+e4f6 +#define ICON_MD_OPEN_WITH "\xee\xa2\x9f" // U+e89f +#define ICON_MD_OTHER_HOUSES "\xee\x96\x8c" // U+e58c +#define ICON_MD_OUTBOND "\xef\x88\xa8" // U+f228 +#define ICON_MD_OUTBOUND "\xee\x87\x8a" // U+e1ca +#define ICON_MD_OUTBOX "\xee\xbd\x9f" // U+ef5f +#define ICON_MD_OUTDOOR_GRILL "\xee\xa9\x87" // U+ea47 +#define ICON_MD_OUTGOING_MAIL "\xef\x83\x92" // U+f0d2 +#define ICON_MD_OUTLET "\xef\x87\x94" // U+f1d4 +#define ICON_MD_OUTLINED_FLAG "\xee\x85\xae" // U+e16e +#define ICON_MD_OUTPUT "\xee\xae\xbe" // U+ebbe +#define ICON_MD_PADDING "\xee\xa7\x88" // U+e9c8 +#define ICON_MD_PAGES "\xee\x9f\xb9" // U+e7f9 +#define ICON_MD_PAGEVIEW "\xee\xa2\xa0" // U+e8a0 +#define ICON_MD_PAID "\xef\x81\x81" // U+f041 +#define ICON_MD_PALETTE "\xee\x90\x8a" // U+e40a +#define ICON_MD_PALLET "\xef\xa1\xaa" // U+f86a +#define ICON_MD_PAN_TOOL "\xee\xa4\xa5" // U+e925 +#define ICON_MD_PAN_TOOL_ALT "\xee\xae\xb9" // U+ebb9 +#define ICON_MD_PANORAMA "\xee\x90\x8b" // U+e40b +#define ICON_MD_PANORAMA_FISH_EYE "\xee\x90\x8c" // U+e40c +#define ICON_MD_PANORAMA_FISHEYE "\xee\x90\x8c" // U+e40c +#define ICON_MD_PANORAMA_HORIZONTAL "\xee\x90\x8d" // U+e40d +#define ICON_MD_PANORAMA_HORIZONTAL_SELECT "\xee\xbd\xa0" // U+ef60 +#define ICON_MD_PANORAMA_PHOTOSPHERE "\xee\xa7\x89" // U+e9c9 +#define ICON_MD_PANORAMA_PHOTOSPHERE_SELECT "\xee\xa7\x8a" // U+e9ca +#define ICON_MD_PANORAMA_VERTICAL "\xee\x90\x8e" // U+e40e +#define ICON_MD_PANORAMA_VERTICAL_SELECT "\xee\xbd\xa1" // U+ef61 +#define ICON_MD_PANORAMA_WIDE_ANGLE "\xee\x90\x8f" // U+e40f +#define ICON_MD_PANORAMA_WIDE_ANGLE_SELECT "\xee\xbd\xa2" // U+ef62 +#define ICON_MD_PARAGLIDING "\xee\x94\x8f" // U+e50f +#define ICON_MD_PARK "\xee\xa9\xa3" // U+ea63 +#define ICON_MD_PARTY_MODE "\xee\x9f\xba" // U+e7fa +#define ICON_MD_PASSWORD "\xef\x81\x82" // U+f042 +#define ICON_MD_PATTERN "\xef\x81\x83" // U+f043 +#define ICON_MD_PAUSE "\xee\x80\xb4" // U+e034 +#define ICON_MD_PAUSE_CIRCLE "\xee\x86\xa2" // U+e1a2 +#define ICON_MD_PAUSE_CIRCLE_FILLED "\xee\x80\xb5" // U+e035 +#define ICON_MD_PAUSE_CIRCLE_OUTLINE "\xee\x80\xb6" // U+e036 +#define ICON_MD_PAUSE_PRESENTATION "\xee\x83\xaa" // U+e0ea +#define ICON_MD_PAYMENT "\xee\xa2\xa1" // U+e8a1 +#define ICON_MD_PAYMENTS "\xee\xbd\xa3" // U+ef63 +#define ICON_MD_PAYPAL "\xee\xaa\x8d" // U+ea8d +#define ICON_MD_PEDAL_BIKE "\xee\xac\xa9" // U+eb29 +#define ICON_MD_PENDING "\xee\xbd\xa4" // U+ef64 +#define ICON_MD_PENDING_ACTIONS "\xef\x86\xbb" // U+f1bb +#define ICON_MD_PENTAGON "\xee\xad\x90" // U+eb50 +#define ICON_MD_PEOPLE "\xee\x9f\xbb" // U+e7fb +#define ICON_MD_PEOPLE_ALT "\xee\xa8\xa1" // U+ea21 +#define ICON_MD_PEOPLE_OUTLINE "\xee\x9f\xbc" // U+e7fc +#define ICON_MD_PERCENT "\xee\xad\x98" // U+eb58 +#define ICON_MD_PERM_CAMERA_MIC "\xee\xa2\xa2" // U+e8a2 +#define ICON_MD_PERM_CONTACT_CAL "\xee\xa2\xa3" // U+e8a3 +#define ICON_MD_PERM_CONTACT_CALENDAR "\xee\xa2\xa3" // U+e8a3 +#define ICON_MD_PERM_DATA_SETTING "\xee\xa2\xa4" // U+e8a4 +#define ICON_MD_PERM_DEVICE_INFO "\xee\xa2\xa5" // U+e8a5 +#define ICON_MD_PERM_DEVICE_INFORMATION "\xee\xa2\xa5" // U+e8a5 +#define ICON_MD_PERM_IDENTITY "\xee\xa2\xa6" // U+e8a6 +#define ICON_MD_PERM_MEDIA "\xee\xa2\xa7" // U+e8a7 +#define ICON_MD_PERM_PHONE_MSG "\xee\xa2\xa8" // U+e8a8 +#define ICON_MD_PERM_SCAN_WIFI "\xee\xa2\xa9" // U+e8a9 +#define ICON_MD_PERSON "\xee\x9f\xbd" // U+e7fd +#define ICON_MD_PERSON_2 "\xef\xa3\xa4" // U+f8e4 +#define ICON_MD_PERSON_3 "\xef\xa3\xa5" // U+f8e5 +#define ICON_MD_PERSON_4 "\xef\xa3\xa6" // U+f8e6 +#define ICON_MD_PERSON_ADD "\xee\x9f\xbe" // U+e7fe +#define ICON_MD_PERSON_ADD_ALT "\xee\xa9\x8d" // U+ea4d +#define ICON_MD_PERSON_ADD_ALT_1 "\xee\xbd\xa5" // U+ef65 +#define ICON_MD_PERSON_ADD_DISABLED "\xee\xa7\x8b" // U+e9cb +#define ICON_MD_PERSON_OFF "\xee\x94\x90" // U+e510 +#define ICON_MD_PERSON_OUTLINE "\xee\x9f\xbf" // U+e7ff +#define ICON_MD_PERSON_PIN "\xee\x95\x9a" // U+e55a +#define ICON_MD_PERSON_PIN_CIRCLE "\xee\x95\xaa" // U+e56a +#define ICON_MD_PERSON_REMOVE "\xee\xbd\xa6" // U+ef66 +#define ICON_MD_PERSON_REMOVE_ALT_1 "\xee\xbd\xa7" // U+ef67 +#define ICON_MD_PERSON_SEARCH "\xef\x84\x86" // U+f106 +#define ICON_MD_PERSONAL_INJURY "\xee\x9b\x9a" // U+e6da +#define ICON_MD_PERSONAL_VIDEO "\xee\x98\xbb" // U+e63b +#define ICON_MD_PEST_CONTROL "\xef\x83\xba" // U+f0fa +#define ICON_MD_PEST_CONTROL_RODENT "\xef\x83\xbd" // U+f0fd +#define ICON_MD_PETS "\xee\xa4\x9d" // U+e91d +#define ICON_MD_PHISHING "\xee\xab\x97" // U+ead7 +#define ICON_MD_PHONE "\xee\x83\x8d" // U+e0cd +#define ICON_MD_PHONE_ANDROID "\xee\x8c\xa4" // U+e324 +#define ICON_MD_PHONE_BLUETOOTH_SPEAKER "\xee\x98\x9b" // U+e61b +#define ICON_MD_PHONE_CALLBACK "\xee\x99\x89" // U+e649 +#define ICON_MD_PHONE_DISABLED "\xee\xa7\x8c" // U+e9cc +#define ICON_MD_PHONE_ENABLED "\xee\xa7\x8d" // U+e9cd +#define ICON_MD_PHONE_FORWARDED "\xee\x98\x9c" // U+e61c +#define ICON_MD_PHONE_IN_TALK "\xee\x98\x9d" // U+e61d +#define ICON_MD_PHONE_IPHONE "\xee\x8c\xa5" // U+e325 +#define ICON_MD_PHONE_LOCKED "\xee\x98\x9e" // U+e61e +#define ICON_MD_PHONE_MISSED "\xee\x98\x9f" // U+e61f +#define ICON_MD_PHONE_PAUSED "\xee\x98\xa0" // U+e620 +#define ICON_MD_PHONELINK "\xee\x8c\xa6" // U+e326 +#define ICON_MD_PHONELINK_ERASE "\xee\x83\x9b" // U+e0db +#define ICON_MD_PHONELINK_LOCK "\xee\x83\x9c" // U+e0dc +#define ICON_MD_PHONELINK_OFF "\xee\x8c\xa7" // U+e327 +#define ICON_MD_PHONELINK_RING "\xee\x83\x9d" // U+e0dd +#define ICON_MD_PHONELINK_SETUP "\xee\x83\x9e" // U+e0de +#define ICON_MD_PHOTO "\xee\x90\x90" // U+e410 +#define ICON_MD_PHOTO_ALBUM "\xee\x90\x91" // U+e411 +#define ICON_MD_PHOTO_CAMERA "\xee\x90\x92" // U+e412 +#define ICON_MD_PHOTO_CAMERA_BACK "\xee\xbd\xa8" // U+ef68 +#define ICON_MD_PHOTO_CAMERA_FRONT "\xee\xbd\xa9" // U+ef69 +#define ICON_MD_PHOTO_FILTER "\xee\x90\xbb" // U+e43b +#define ICON_MD_PHOTO_LIBRARY "\xee\x90\x93" // U+e413 +#define ICON_MD_PHOTO_SIZE_SELECT_ACTUAL "\xee\x90\xb2" // U+e432 +#define ICON_MD_PHOTO_SIZE_SELECT_LARGE "\xee\x90\xb3" // U+e433 +#define ICON_MD_PHOTO_SIZE_SELECT_SMALL "\xee\x90\xb4" // U+e434 +#define ICON_MD_PHP "\xee\xae\x8f" // U+eb8f +#define ICON_MD_PIANO "\xee\x94\xa1" // U+e521 +#define ICON_MD_PIANO_OFF "\xee\x94\xa0" // U+e520 +#define ICON_MD_PICTURE_AS_PDF "\xee\x90\x95" // U+e415 +#define ICON_MD_PICTURE_IN_PICTURE "\xee\xa2\xaa" // U+e8aa +#define ICON_MD_PICTURE_IN_PICTURE_ALT "\xee\xa4\x91" // U+e911 +#define ICON_MD_PIE_CHART "\xee\x9b\x84" // U+e6c4 +#define ICON_MD_PIE_CHART_OUTLINE "\xef\x81\x84" // U+f044 +#define ICON_MD_PIE_CHART_OUTLINED "\xee\x9b\x85" // U+e6c5 +#define ICON_MD_PIN "\xef\x81\x85" // U+f045 +#define ICON_MD_PIN_DROP "\xee\x95\x9e" // U+e55e +#define ICON_MD_PIN_END "\xee\x9d\xa7" // U+e767 +#define ICON_MD_PIN_INVOKE "\xee\x9d\xa3" // U+e763 +#define ICON_MD_PINCH "\xee\xac\xb8" // U+eb38 +#define ICON_MD_PIVOT_TABLE_CHART "\xee\xa7\x8e" // U+e9ce +#define ICON_MD_PIX "\xee\xaa\xa3" // U+eaa3 +#define ICON_MD_PLACE "\xee\x95\x9f" // U+e55f +#define ICON_MD_PLAGIARISM "\xee\xa9\x9a" // U+ea5a +#define ICON_MD_PLAY_ARROW "\xee\x80\xb7" // U+e037 +#define ICON_MD_PLAY_CIRCLE "\xee\x87\x84" // U+e1c4 +#define ICON_MD_PLAY_CIRCLE_FILL "\xee\x80\xb8" // U+e038 +#define ICON_MD_PLAY_CIRCLE_FILLED "\xee\x80\xb8" // U+e038 +#define ICON_MD_PLAY_CIRCLE_OUTLINE "\xee\x80\xb9" // U+e039 +#define ICON_MD_PLAY_DISABLED "\xee\xbd\xaa" // U+ef6a +#define ICON_MD_PLAY_FOR_WORK "\xee\xa4\x86" // U+e906 +#define ICON_MD_PLAY_LESSON "\xef\x81\x87" // U+f047 +#define ICON_MD_PLAYLIST_ADD "\xee\x80\xbb" // U+e03b +#define ICON_MD_PLAYLIST_ADD_CHECK "\xee\x81\xa5" // U+e065 +#define ICON_MD_PLAYLIST_ADD_CHECK_CIRCLE "\xee\x9f\xa6" // U+e7e6 +#define ICON_MD_PLAYLIST_ADD_CIRCLE "\xee\x9f\xa5" // U+e7e5 +#define ICON_MD_PLAYLIST_PLAY "\xee\x81\x9f" // U+e05f +#define ICON_MD_PLAYLIST_REMOVE "\xee\xae\x80" // U+eb80 +#define ICON_MD_PLUMBING "\xef\x84\x87" // U+f107 +#define ICON_MD_PLUS_ONE "\xee\xa0\x80" // U+e800 +#define ICON_MD_PODCASTS "\xef\x81\x88" // U+f048 +#define ICON_MD_POINT_OF_SALE "\xef\x85\xbe" // U+f17e +#define ICON_MD_POLICY "\xee\xa8\x97" // U+ea17 +#define ICON_MD_POLL "\xee\xa0\x81" // U+e801 +#define ICON_MD_POLYLINE "\xee\xae\xbb" // U+ebbb +#define ICON_MD_POLYMER "\xee\xa2\xab" // U+e8ab +#define ICON_MD_POOL "\xee\xad\x88" // U+eb48 +#define ICON_MD_PORTABLE_WIFI_OFF "\xee\x83\x8e" // U+e0ce +#define ICON_MD_PORTRAIT "\xee\x90\x96" // U+e416 +#define ICON_MD_POST_ADD "\xee\xa8\xa0" // U+ea20 +#define ICON_MD_POWER "\xee\x98\xbc" // U+e63c +#define ICON_MD_POWER_INPUT "\xee\x8c\xb6" // U+e336 +#define ICON_MD_POWER_OFF "\xee\x99\x86" // U+e646 +#define ICON_MD_POWER_SETTINGS_NEW "\xee\xa2\xac" // U+e8ac +#define ICON_MD_PRECISION_MANUFACTURING "\xef\x81\x89" // U+f049 +#define ICON_MD_PREGNANT_WOMAN "\xee\xa4\x9e" // U+e91e +#define ICON_MD_PRESENT_TO_ALL "\xee\x83\x9f" // U+e0df +#define ICON_MD_PREVIEW "\xef\x87\x85" // U+f1c5 +#define ICON_MD_PRICE_CHANGE "\xef\x81\x8a" // U+f04a +#define ICON_MD_PRICE_CHECK "\xef\x81\x8b" // U+f04b +#define ICON_MD_PRINT "\xee\xa2\xad" // U+e8ad +#define ICON_MD_PRINT_DISABLED "\xee\xa7\x8f" // U+e9cf +#define ICON_MD_PRIORITY_HIGH "\xee\x99\x85" // U+e645 +#define ICON_MD_PRIVACY_TIP "\xef\x83\x9c" // U+f0dc +#define ICON_MD_PRIVATE_CONNECTIVITY "\xee\x9d\x84" // U+e744 +#define ICON_MD_PRODUCTION_QUANTITY_LIMITS "\xee\x87\x91" // U+e1d1 +#define ICON_MD_PROPANE "\xee\xb0\x94" // U+ec14 +#define ICON_MD_PROPANE_TANK "\xee\xb0\x93" // U+ec13 +#define ICON_MD_PSYCHOLOGY "\xee\xa9\x8a" // U+ea4a +#define ICON_MD_PSYCHOLOGY_ALT "\xef\xa3\xaa" // U+f8ea +#define ICON_MD_PUBLIC "\xee\xa0\x8b" // U+e80b +#define ICON_MD_PUBLIC_OFF "\xef\x87\x8a" // U+f1ca +#define ICON_MD_PUBLISH "\xee\x89\x95" // U+e255 +#define ICON_MD_PUBLISHED_WITH_CHANGES "\xef\x88\xb2" // U+f232 +#define ICON_MD_PUNCH_CLOCK "\xee\xaa\xa8" // U+eaa8 +#define ICON_MD_PUSH_PIN "\xef\x84\x8d" // U+f10d +#define ICON_MD_QR_CODE "\xee\xbd\xab" // U+ef6b +#define ICON_MD_QR_CODE_2 "\xee\x80\x8a" // U+e00a +#define ICON_MD_QR_CODE_SCANNER "\xef\x88\x86" // U+f206 +#define ICON_MD_QUERY_BUILDER "\xee\xa2\xae" // U+e8ae +#define ICON_MD_QUERY_STATS "\xee\x93\xbc" // U+e4fc +#define ICON_MD_QUESTION_ANSWER "\xee\xa2\xaf" // U+e8af +#define ICON_MD_QUESTION_MARK "\xee\xae\x8b" // U+eb8b +#define ICON_MD_QUEUE "\xee\x80\xbc" // U+e03c +#define ICON_MD_QUEUE_MUSIC "\xee\x80\xbd" // U+e03d +#define ICON_MD_QUEUE_PLAY_NEXT "\xee\x81\xa6" // U+e066 +#define ICON_MD_QUICK_CONTACTS_DIALER "\xee\x83\x8f" // U+e0cf +#define ICON_MD_QUICK_CONTACTS_MAIL "\xee\x83\x90" // U+e0d0 +#define ICON_MD_QUICKREPLY "\xee\xbd\xac" // U+ef6c +#define ICON_MD_QUIZ "\xef\x81\x8c" // U+f04c +#define ICON_MD_QUORA "\xee\xaa\x98" // U+ea98 +#define ICON_MD_R_MOBILEDATA "\xef\x81\x8d" // U+f04d +#define ICON_MD_RADAR "\xef\x81\x8e" // U+f04e +#define ICON_MD_RADIO "\xee\x80\xbe" // U+e03e +#define ICON_MD_RADIO_BUTTON_CHECKED "\xee\xa0\xb7" // U+e837 +#define ICON_MD_RADIO_BUTTON_OFF "\xee\xa0\xb6" // U+e836 +#define ICON_MD_RADIO_BUTTON_ON "\xee\xa0\xb7" // U+e837 +#define ICON_MD_RADIO_BUTTON_UNCHECKED "\xee\xa0\xb6" // U+e836 +#define ICON_MD_RAILWAY_ALERT "\xee\xa7\x91" // U+e9d1 +#define ICON_MD_RAMEN_DINING "\xee\xa9\xa4" // U+ea64 +#define ICON_MD_RAMP_LEFT "\xee\xae\x9c" // U+eb9c +#define ICON_MD_RAMP_RIGHT "\xee\xae\x96" // U+eb96 +#define ICON_MD_RATE_REVIEW "\xee\x95\xa0" // U+e560 +#define ICON_MD_RAW_OFF "\xef\x81\x8f" // U+f04f +#define ICON_MD_RAW_ON "\xef\x81\x90" // U+f050 +#define ICON_MD_READ_MORE "\xee\xbd\xad" // U+ef6d +#define ICON_MD_REAL_ESTATE_AGENT "\xee\x9c\xba" // U+e73a +#define ICON_MD_REBASE_EDIT "\xef\xa1\x86" // U+f846 +#define ICON_MD_RECEIPT "\xee\xa2\xb0" // U+e8b0 +#define ICON_MD_RECEIPT_LONG "\xee\xbd\xae" // U+ef6e +#define ICON_MD_RECENT_ACTORS "\xee\x80\xbf" // U+e03f +#define ICON_MD_RECOMMEND "\xee\xa7\x92" // U+e9d2 +#define ICON_MD_RECORD_VOICE_OVER "\xee\xa4\x9f" // U+e91f +#define ICON_MD_RECTANGLE "\xee\xad\x94" // U+eb54 +#define ICON_MD_RECYCLING "\xee\x9d\xa0" // U+e760 +#define ICON_MD_REDDIT "\xee\xaa\xa0" // U+eaa0 +#define ICON_MD_REDEEM "\xee\xa2\xb1" // U+e8b1 +#define ICON_MD_REDO "\xee\x85\x9a" // U+e15a +#define ICON_MD_REDUCE_CAPACITY "\xef\x88\x9c" // U+f21c +#define ICON_MD_REFRESH "\xee\x97\x95" // U+e5d5 +#define ICON_MD_REMEMBER_ME "\xef\x81\x91" // U+f051 +#define ICON_MD_REMOVE "\xee\x85\x9b" // U+e15b +#define ICON_MD_REMOVE_CIRCLE "\xee\x85\x9c" // U+e15c +#define ICON_MD_REMOVE_CIRCLE_OUTLINE "\xee\x85\x9d" // U+e15d +#define ICON_MD_REMOVE_DONE "\xee\xa7\x93" // U+e9d3 +#define ICON_MD_REMOVE_FROM_QUEUE "\xee\x81\xa7" // U+e067 +#define ICON_MD_REMOVE_MODERATOR "\xee\xa7\x94" // U+e9d4 +#define ICON_MD_REMOVE_RED_EYE "\xee\x90\x97" // U+e417 +#define ICON_MD_REMOVE_ROAD "\xee\xaf\xbc" // U+ebfc +#define ICON_MD_REMOVE_SHOPPING_CART "\xee\xa4\xa8" // U+e928 +#define ICON_MD_REORDER "\xee\xa3\xbe" // U+e8fe +#define ICON_MD_REPARTITION "\xef\xa3\xa8" // U+f8e8 +#define ICON_MD_REPEAT "\xee\x81\x80" // U+e040 +#define ICON_MD_REPEAT_ON "\xee\xa7\x96" // U+e9d6 +#define ICON_MD_REPEAT_ONE "\xee\x81\x81" // U+e041 +#define ICON_MD_REPEAT_ONE_ON "\xee\xa7\x97" // U+e9d7 +#define ICON_MD_REPLAY "\xee\x81\x82" // U+e042 +#define ICON_MD_REPLAY_10 "\xee\x81\x99" // U+e059 +#define ICON_MD_REPLAY_30 "\xee\x81\x9a" // U+e05a +#define ICON_MD_REPLAY_5 "\xee\x81\x9b" // U+e05b +#define ICON_MD_REPLAY_CIRCLE_FILLED "\xee\xa7\x98" // U+e9d8 +#define ICON_MD_REPLY "\xee\x85\x9e" // U+e15e +#define ICON_MD_REPLY_ALL "\xee\x85\x9f" // U+e15f +#define ICON_MD_REPORT "\xee\x85\xa0" // U+e160 +#define ICON_MD_REPORT_GMAILERRORRED "\xef\x81\x92" // U+f052 +#define ICON_MD_REPORT_OFF "\xee\x85\xb0" // U+e170 +#define ICON_MD_REPORT_PROBLEM "\xee\xa2\xb2" // U+e8b2 +#define ICON_MD_REQUEST_PAGE "\xef\x88\xac" // U+f22c +#define ICON_MD_REQUEST_QUOTE "\xef\x86\xb6" // U+f1b6 +#define ICON_MD_RESET_TV "\xee\xa7\x99" // U+e9d9 +#define ICON_MD_RESTART_ALT "\xef\x81\x93" // U+f053 +#define ICON_MD_RESTAURANT "\xee\x95\xac" // U+e56c +#define ICON_MD_RESTAURANT_MENU "\xee\x95\xa1" // U+e561 +#define ICON_MD_RESTORE "\xee\xa2\xb3" // U+e8b3 +#define ICON_MD_RESTORE_FROM_TRASH "\xee\xa4\xb8" // U+e938 +#define ICON_MD_RESTORE_PAGE "\xee\xa4\xa9" // U+e929 +#define ICON_MD_REVIEWS "\xef\x81\x94" // U+f054 +#define ICON_MD_RICE_BOWL "\xef\x87\xb5" // U+f1f5 +#define ICON_MD_RING_VOLUME "\xee\x83\x91" // U+e0d1 +#define ICON_MD_ROCKET "\xee\xae\xa5" // U+eba5 +#define ICON_MD_ROCKET_LAUNCH "\xee\xae\x9b" // U+eb9b +#define ICON_MD_ROLLER_SHADES "\xee\xb0\x92" // U+ec12 +#define ICON_MD_ROLLER_SHADES_CLOSED "\xee\xb0\x91" // U+ec11 +#define ICON_MD_ROLLER_SKATING "\xee\xaf\x8d" // U+ebcd +#define ICON_MD_ROOFING "\xef\x88\x81" // U+f201 +#define ICON_MD_ROOM "\xee\xa2\xb4" // U+e8b4 +#define ICON_MD_ROOM_PREFERENCES "\xef\x86\xb8" // U+f1b8 +#define ICON_MD_ROOM_SERVICE "\xee\xad\x89" // U+eb49 +#define ICON_MD_ROTATE_90_DEGREES_CCW "\xee\x90\x98" // U+e418 +#define ICON_MD_ROTATE_90_DEGREES_CW "\xee\xaa\xab" // U+eaab +#define ICON_MD_ROTATE_LEFT "\xee\x90\x99" // U+e419 +#define ICON_MD_ROTATE_RIGHT "\xee\x90\x9a" // U+e41a +#define ICON_MD_ROUNDABOUT_LEFT "\xee\xae\x99" // U+eb99 +#define ICON_MD_ROUNDABOUT_RIGHT "\xee\xae\xa3" // U+eba3 +#define ICON_MD_ROUNDED_CORNER "\xee\xa4\xa0" // U+e920 +#define ICON_MD_ROUTE "\xee\xab\x8d" // U+eacd +#define ICON_MD_ROUTER "\xee\x8c\xa8" // U+e328 +#define ICON_MD_ROWING "\xee\xa4\xa1" // U+e921 +#define ICON_MD_RSS_FEED "\xee\x83\xa5" // U+e0e5 +#define ICON_MD_RSVP "\xef\x81\x95" // U+f055 +#define ICON_MD_RTT "\xee\xa6\xad" // U+e9ad +#define ICON_MD_RULE "\xef\x87\x82" // U+f1c2 +#define ICON_MD_RULE_FOLDER "\xef\x87\x89" // U+f1c9 +#define ICON_MD_RUN_CIRCLE "\xee\xbd\xaf" // U+ef6f +#define ICON_MD_RUNNING_WITH_ERRORS "\xee\x94\x9d" // U+e51d +#define ICON_MD_RV_HOOKUP "\xee\x99\x82" // U+e642 +#define ICON_MD_SAFETY_CHECK "\xee\xaf\xaf" // U+ebef +#define ICON_MD_SAFETY_DIVIDER "\xee\x87\x8c" // U+e1cc +#define ICON_MD_SAILING "\xee\x94\x82" // U+e502 +#define ICON_MD_SANITIZER "\xef\x88\x9d" // U+f21d +#define ICON_MD_SATELLITE "\xee\x95\xa2" // U+e562 +#define ICON_MD_SATELLITE_ALT "\xee\xac\xba" // U+eb3a +#define ICON_MD_SAVE "\xee\x85\xa1" // U+e161 +#define ICON_MD_SAVE_ALT "\xee\x85\xb1" // U+e171 +#define ICON_MD_SAVE_AS "\xee\xad\xa0" // U+eb60 +#define ICON_MD_SAVED_SEARCH "\xee\xa8\x91" // U+ea11 +#define ICON_MD_SAVINGS "\xee\x8b\xab" // U+e2eb +#define ICON_MD_SCALE "\xee\xad\x9f" // U+eb5f +#define ICON_MD_SCANNER "\xee\x8c\xa9" // U+e329 +#define ICON_MD_SCATTER_PLOT "\xee\x89\xa8" // U+e268 +#define ICON_MD_SCHEDULE "\xee\xa2\xb5" // U+e8b5 +#define ICON_MD_SCHEDULE_SEND "\xee\xa8\x8a" // U+ea0a +#define ICON_MD_SCHEMA "\xee\x93\xbd" // U+e4fd +#define ICON_MD_SCHOOL "\xee\xa0\x8c" // U+e80c +#define ICON_MD_SCIENCE "\xee\xa9\x8b" // U+ea4b +#define ICON_MD_SCORE "\xee\x89\xa9" // U+e269 +#define ICON_MD_SCOREBOARD "\xee\xaf\x90" // U+ebd0 +#define ICON_MD_SCREEN_LOCK_LANDSCAPE "\xee\x86\xbe" // U+e1be +#define ICON_MD_SCREEN_LOCK_PORTRAIT "\xee\x86\xbf" // U+e1bf +#define ICON_MD_SCREEN_LOCK_ROTATION "\xee\x87\x80" // U+e1c0 +#define ICON_MD_SCREEN_ROTATION "\xee\x87\x81" // U+e1c1 +#define ICON_MD_SCREEN_ROTATION_ALT "\xee\xaf\xae" // U+ebee +#define ICON_MD_SCREEN_SEARCH_DESKTOP "\xee\xbd\xb0" // U+ef70 +#define ICON_MD_SCREEN_SHARE "\xee\x83\xa2" // U+e0e2 +#define ICON_MD_SCREENSHOT "\xef\x81\x96" // U+f056 +#define ICON_MD_SCREENSHOT_MONITOR "\xee\xb0\x88" // U+ec08 +#define ICON_MD_SCUBA_DIVING "\xee\xaf\x8e" // U+ebce +#define ICON_MD_SD "\xee\xa7\x9d" // U+e9dd +#define ICON_MD_SD_CARD "\xee\x98\xa3" // U+e623 +#define ICON_MD_SD_CARD_ALERT "\xef\x81\x97" // U+f057 +#define ICON_MD_SD_STORAGE "\xee\x87\x82" // U+e1c2 +#define ICON_MD_SEARCH "\xee\xa2\xb6" // U+e8b6 +#define ICON_MD_SEARCH_OFF "\xee\xa9\xb6" // U+ea76 +#define ICON_MD_SECURITY "\xee\x8c\xaa" // U+e32a +#define ICON_MD_SECURITY_UPDATE "\xef\x81\x98" // U+f058 +#define ICON_MD_SECURITY_UPDATE_GOOD "\xef\x81\x99" // U+f059 +#define ICON_MD_SECURITY_UPDATE_WARNING "\xef\x81\x9a" // U+f05a +#define ICON_MD_SEGMENT "\xee\xa5\x8b" // U+e94b +#define ICON_MD_SELECT_ALL "\xee\x85\xa2" // U+e162 +#define ICON_MD_SELF_IMPROVEMENT "\xee\xa9\xb8" // U+ea78 +#define ICON_MD_SELL "\xef\x81\x9b" // U+f05b +#define ICON_MD_SEND "\xee\x85\xa3" // U+e163 +#define ICON_MD_SEND_AND_ARCHIVE "\xee\xa8\x8c" // U+ea0c +#define ICON_MD_SEND_TIME_EXTENSION "\xee\xab\x9b" // U+eadb +#define ICON_MD_SEND_TO_MOBILE "\xef\x81\x9c" // U+f05c +#define ICON_MD_SENSOR_DOOR "\xef\x86\xb5" // U+f1b5 +#define ICON_MD_SENSOR_OCCUPIED "\xee\xb0\x90" // U+ec10 +#define ICON_MD_SENSOR_WINDOW "\xef\x86\xb4" // U+f1b4 +#define ICON_MD_SENSORS "\xee\x94\x9e" // U+e51e +#define ICON_MD_SENSORS_OFF "\xee\x94\x9f" // U+e51f +#define ICON_MD_SENTIMENT_DISSATISFIED "\xee\xa0\x91" // U+e811 +#define ICON_MD_SENTIMENT_NEUTRAL "\xee\xa0\x92" // U+e812 +#define ICON_MD_SENTIMENT_SATISFIED "\xee\xa0\x93" // U+e813 +#define ICON_MD_SENTIMENT_SATISFIED_ALT "\xee\x83\xad" // U+e0ed +#define ICON_MD_SENTIMENT_VERY_DISSATISFIED "\xee\xa0\x94" // U+e814 +#define ICON_MD_SENTIMENT_VERY_SATISFIED "\xee\xa0\x95" // U+e815 +#define ICON_MD_SET_MEAL "\xef\x87\xaa" // U+f1ea +#define ICON_MD_SETTINGS "\xee\xa2\xb8" // U+e8b8 +#define ICON_MD_SETTINGS_ACCESSIBILITY "\xef\x81\x9d" // U+f05d +#define ICON_MD_SETTINGS_APPLICATIONS "\xee\xa2\xb9" // U+e8b9 +#define ICON_MD_SETTINGS_BACKUP_RESTORE "\xee\xa2\xba" // U+e8ba +#define ICON_MD_SETTINGS_BLUETOOTH "\xee\xa2\xbb" // U+e8bb +#define ICON_MD_SETTINGS_BRIGHTNESS "\xee\xa2\xbd" // U+e8bd +#define ICON_MD_SETTINGS_CELL "\xee\xa2\xbc" // U+e8bc +#define ICON_MD_SETTINGS_DISPLAY "\xee\xa2\xbd" // U+e8bd +#define ICON_MD_SETTINGS_ETHERNET "\xee\xa2\xbe" // U+e8be +#define ICON_MD_SETTINGS_INPUT_ANTENNA "\xee\xa2\xbf" // U+e8bf +#define ICON_MD_SETTINGS_INPUT_COMPONENT "\xee\xa3\x80" // U+e8c0 +#define ICON_MD_SETTINGS_INPUT_COMPOSITE "\xee\xa3\x81" // U+e8c1 +#define ICON_MD_SETTINGS_INPUT_HDMI "\xee\xa3\x82" // U+e8c2 +#define ICON_MD_SETTINGS_INPUT_SVIDEO "\xee\xa3\x83" // U+e8c3 +#define ICON_MD_SETTINGS_OVERSCAN "\xee\xa3\x84" // U+e8c4 +#define ICON_MD_SETTINGS_PHONE "\xee\xa3\x85" // U+e8c5 +#define ICON_MD_SETTINGS_POWER "\xee\xa3\x86" // U+e8c6 +#define ICON_MD_SETTINGS_REMOTE "\xee\xa3\x87" // U+e8c7 +#define ICON_MD_SETTINGS_SUGGEST "\xef\x81\x9e" // U+f05e +#define ICON_MD_SETTINGS_SYSTEM_DAYDREAM "\xee\x87\x83" // U+e1c3 +#define ICON_MD_SETTINGS_VOICE "\xee\xa3\x88" // U+e8c8 +#define ICON_MD_SEVERE_COLD "\xee\xaf\x93" // U+ebd3 +#define ICON_MD_SHAPE_LINE "\xef\xa3\x93" // U+f8d3 +#define ICON_MD_SHARE "\xee\xa0\x8d" // U+e80d +#define ICON_MD_SHARE_ARRIVAL_TIME "\xee\x94\xa4" // U+e524 +#define ICON_MD_SHARE_LOCATION "\xef\x81\x9f" // U+f05f +#define ICON_MD_SHELVES "\xef\xa1\xae" // U+f86e +#define ICON_MD_SHIELD "\xee\xa7\xa0" // U+e9e0 +#define ICON_MD_SHIELD_MOON "\xee\xaa\xa9" // U+eaa9 +#define ICON_MD_SHOP "\xee\xa3\x89" // U+e8c9 +#define ICON_MD_SHOP_2 "\xee\x86\x9e" // U+e19e +#define ICON_MD_SHOP_TWO "\xee\xa3\x8a" // U+e8ca +#define ICON_MD_SHOPIFY "\xee\xaa\x9d" // U+ea9d +#define ICON_MD_SHOPPING_BAG "\xef\x87\x8c" // U+f1cc +#define ICON_MD_SHOPPING_BASKET "\xee\xa3\x8b" // U+e8cb +#define ICON_MD_SHOPPING_CART "\xee\xa3\x8c" // U+e8cc +#define ICON_MD_SHOPPING_CART_CHECKOUT "\xee\xae\x88" // U+eb88 +#define ICON_MD_SHORT_TEXT "\xee\x89\xa1" // U+e261 +#define ICON_MD_SHORTCUT "\xef\x81\xa0" // U+f060 +#define ICON_MD_SHOW_CHART "\xee\x9b\xa1" // U+e6e1 +#define ICON_MD_SHOWER "\xef\x81\xa1" // U+f061 +#define ICON_MD_SHUFFLE "\xee\x81\x83" // U+e043 +#define ICON_MD_SHUFFLE_ON "\xee\xa7\xa1" // U+e9e1 +#define ICON_MD_SHUTTER_SPEED "\xee\x90\xbd" // U+e43d +#define ICON_MD_SICK "\xef\x88\xa0" // U+f220 +#define ICON_MD_SIGN_LANGUAGE "\xee\xaf\xa5" // U+ebe5 +#define ICON_MD_SIGNAL_CELLULAR_0_BAR "\xef\x82\xa8" // U+f0a8 +#define ICON_MD_SIGNAL_CELLULAR_4_BAR "\xee\x87\x88" // U+e1c8 +#define ICON_MD_SIGNAL_CELLULAR_ALT "\xee\x88\x82" // U+e202 +#define ICON_MD_SIGNAL_CELLULAR_ALT_1_BAR "\xee\xaf\x9f" // U+ebdf +#define ICON_MD_SIGNAL_CELLULAR_ALT_2_BAR "\xee\xaf\xa3" // U+ebe3 +#define ICON_MD_SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR "\xef\x82\xac" // U+f0ac +#define ICON_MD_SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR "\xee\x87\x8d" // U+e1cd +#define ICON_MD_SIGNAL_CELLULAR_NO_SIM "\xee\x87\x8e" // U+e1ce +#define ICON_MD_SIGNAL_CELLULAR_NODATA "\xef\x81\xa2" // U+f062 +#define ICON_MD_SIGNAL_CELLULAR_NULL "\xee\x87\x8f" // U+e1cf +#define ICON_MD_SIGNAL_CELLULAR_OFF "\xee\x87\x90" // U+e1d0 +#define ICON_MD_SIGNAL_WIFI_0_BAR "\xef\x82\xb0" // U+f0b0 +#define ICON_MD_SIGNAL_WIFI_4_BAR "\xee\x87\x98" // U+e1d8 +#define ICON_MD_SIGNAL_WIFI_4_BAR_LOCK "\xee\x87\x99" // U+e1d9 +#define ICON_MD_SIGNAL_WIFI_BAD "\xef\x81\xa3" // U+f063 +#define ICON_MD_SIGNAL_WIFI_CONNECTED_NO_INTERNET_4 "\xef\x81\xa4" // U+f064 +#define ICON_MD_SIGNAL_WIFI_OFF "\xee\x87\x9a" // U+e1da +#define ICON_MD_SIGNAL_WIFI_STATUSBAR_4_BAR "\xef\x81\xa5" // U+f065 +#define ICON_MD_SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4 "\xef\x81\xa6" // U+f066 +#define ICON_MD_SIGNAL_WIFI_STATUSBAR_NULL "\xef\x81\xa7" // U+f067 +#define ICON_MD_SIGNPOST "\xee\xae\x91" // U+eb91 +#define ICON_MD_SIM_CARD "\xee\x8c\xab" // U+e32b +#define ICON_MD_SIM_CARD_ALERT "\xee\x98\xa4" // U+e624 +#define ICON_MD_SIM_CARD_DOWNLOAD "\xef\x81\xa8" // U+f068 +#define ICON_MD_SINGLE_BED "\xee\xa9\x88" // U+ea48 +#define ICON_MD_SIP "\xef\x81\xa9" // U+f069 +#define ICON_MD_SKATEBOARDING "\xee\x94\x91" // U+e511 +#define ICON_MD_SKIP_NEXT "\xee\x81\x84" // U+e044 +#define ICON_MD_SKIP_PREVIOUS "\xee\x81\x85" // U+e045 +#define ICON_MD_SLEDDING "\xee\x94\x92" // U+e512 +#define ICON_MD_SLIDESHOW "\xee\x90\x9b" // U+e41b +#define ICON_MD_SLOW_MOTION_VIDEO "\xee\x81\xa8" // U+e068 +#define ICON_MD_SMART_BUTTON "\xef\x87\x81" // U+f1c1 +#define ICON_MD_SMART_DISPLAY "\xef\x81\xaa" // U+f06a +#define ICON_MD_SMART_SCREEN "\xef\x81\xab" // U+f06b +#define ICON_MD_SMART_TOY "\xef\x81\xac" // U+f06c +#define ICON_MD_SMARTPHONE "\xee\x8c\xac" // U+e32c +#define ICON_MD_SMOKE_FREE "\xee\xad\x8a" // U+eb4a +#define ICON_MD_SMOKING_ROOMS "\xee\xad\x8b" // U+eb4b +#define ICON_MD_SMS "\xee\x98\xa5" // U+e625 +#define ICON_MD_SMS_FAILED "\xee\x98\xa6" // U+e626 +#define ICON_MD_SNAPCHAT "\xee\xa9\xae" // U+ea6e +#define ICON_MD_SNIPPET_FOLDER "\xef\x87\x87" // U+f1c7 +#define ICON_MD_SNOOZE "\xee\x81\x86" // U+e046 +#define ICON_MD_SNOWBOARDING "\xee\x94\x93" // U+e513 +#define ICON_MD_SNOWING "\xee\xa0\x8f" // U+e80f +#define ICON_MD_SNOWMOBILE "\xee\x94\x83" // U+e503 +#define ICON_MD_SNOWSHOEING "\xee\x94\x94" // U+e514 +#define ICON_MD_SOAP "\xef\x86\xb2" // U+f1b2 +#define ICON_MD_SOCIAL_DISTANCE "\xee\x87\x8b" // U+e1cb +#define ICON_MD_SOLAR_POWER "\xee\xb0\x8f" // U+ec0f +#define ICON_MD_SORT "\xee\x85\xa4" // U+e164 +#define ICON_MD_SORT_BY_ALPHA "\xee\x81\x93" // U+e053 +#define ICON_MD_SOS "\xee\xaf\xb7" // U+ebf7 +#define ICON_MD_SOUP_KITCHEN "\xee\x9f\x93" // U+e7d3 +#define ICON_MD_SOURCE "\xef\x87\x84" // U+f1c4 +#define ICON_MD_SOUTH "\xef\x87\xa3" // U+f1e3 +#define ICON_MD_SOUTH_AMERICA "\xee\x9f\xa4" // U+e7e4 +#define ICON_MD_SOUTH_EAST "\xef\x87\xa4" // U+f1e4 +#define ICON_MD_SOUTH_WEST "\xef\x87\xa5" // U+f1e5 +#define ICON_MD_SPA "\xee\xad\x8c" // U+eb4c +#define ICON_MD_SPACE_BAR "\xee\x89\x96" // U+e256 +#define ICON_MD_SPACE_DASHBOARD "\xee\x99\xab" // U+e66b +#define ICON_MD_SPATIAL_AUDIO "\xee\xaf\xab" // U+ebeb +#define ICON_MD_SPATIAL_AUDIO_OFF "\xee\xaf\xa8" // U+ebe8 +#define ICON_MD_SPATIAL_TRACKING "\xee\xaf\xaa" // U+ebea +#define ICON_MD_SPEAKER "\xee\x8c\xad" // U+e32d +#define ICON_MD_SPEAKER_GROUP "\xee\x8c\xae" // U+e32e +#define ICON_MD_SPEAKER_NOTES "\xee\xa3\x8d" // U+e8cd +#define ICON_MD_SPEAKER_NOTES_OFF "\xee\xa4\xaa" // U+e92a +#define ICON_MD_SPEAKER_PHONE "\xee\x83\x92" // U+e0d2 +#define ICON_MD_SPEED "\xee\xa7\xa4" // U+e9e4 +#define ICON_MD_SPELLCHECK "\xee\xa3\x8e" // U+e8ce +#define ICON_MD_SPLITSCREEN "\xef\x81\xad" // U+f06d +#define ICON_MD_SPOKE "\xee\xa6\xa7" // U+e9a7 +#define ICON_MD_SPORTS "\xee\xa8\xb0" // U+ea30 +#define ICON_MD_SPORTS_BAR "\xef\x87\xb3" // U+f1f3 +#define ICON_MD_SPORTS_BASEBALL "\xee\xa9\x91" // U+ea51 +#define ICON_MD_SPORTS_BASKETBALL "\xee\xa8\xa6" // U+ea26 +#define ICON_MD_SPORTS_CRICKET "\xee\xa8\xa7" // U+ea27 +#define ICON_MD_SPORTS_ESPORTS "\xee\xa8\xa8" // U+ea28 +#define ICON_MD_SPORTS_FOOTBALL "\xee\xa8\xa9" // U+ea29 +#define ICON_MD_SPORTS_GOLF "\xee\xa8\xaa" // U+ea2a +#define ICON_MD_SPORTS_GYMNASTICS "\xee\xaf\x84" // U+ebc4 +#define ICON_MD_SPORTS_HANDBALL "\xee\xa8\xb3" // U+ea33 +#define ICON_MD_SPORTS_HOCKEY "\xee\xa8\xab" // U+ea2b +#define ICON_MD_SPORTS_KABADDI "\xee\xa8\xb4" // U+ea34 +#define ICON_MD_SPORTS_MARTIAL_ARTS "\xee\xab\xa9" // U+eae9 +#define ICON_MD_SPORTS_MMA "\xee\xa8\xac" // U+ea2c +#define ICON_MD_SPORTS_MOTORSPORTS "\xee\xa8\xad" // U+ea2d +#define ICON_MD_SPORTS_RUGBY "\xee\xa8\xae" // U+ea2e +#define ICON_MD_SPORTS_SCORE "\xef\x81\xae" // U+f06e +#define ICON_MD_SPORTS_SOCCER "\xee\xa8\xaf" // U+ea2f +#define ICON_MD_SPORTS_TENNIS "\xee\xa8\xb2" // U+ea32 +#define ICON_MD_SPORTS_VOLLEYBALL "\xee\xa8\xb1" // U+ea31 +#define ICON_MD_SQUARE "\xee\xac\xb6" // U+eb36 +#define ICON_MD_SQUARE_FOOT "\xee\xa9\x89" // U+ea49 +#define ICON_MD_SSID_CHART "\xee\xad\xa6" // U+eb66 +#define ICON_MD_STACKED_BAR_CHART "\xee\xa7\xa6" // U+e9e6 +#define ICON_MD_STACKED_LINE_CHART "\xef\x88\xab" // U+f22b +#define ICON_MD_STADIUM "\xee\xae\x90" // U+eb90 +#define ICON_MD_STAIRS "\xef\x86\xa9" // U+f1a9 +#define ICON_MD_STAR "\xee\xa0\xb8" // U+e838 +#define ICON_MD_STAR_BORDER "\xee\xa0\xba" // U+e83a +#define ICON_MD_STAR_BORDER_PURPLE500 "\xef\x82\x99" // U+f099 +#define ICON_MD_STAR_HALF "\xee\xa0\xb9" // U+e839 +#define ICON_MD_STAR_OUTLINE "\xef\x81\xaf" // U+f06f +#define ICON_MD_STAR_PURPLE500 "\xef\x82\x9a" // U+f09a +#define ICON_MD_STAR_RATE "\xef\x83\xac" // U+f0ec +#define ICON_MD_STARS "\xee\xa3\x90" // U+e8d0 +#define ICON_MD_START "\xee\x82\x89" // U+e089 +#define ICON_MD_STAY_CURRENT_LANDSCAPE "\xee\x83\x93" // U+e0d3 +#define ICON_MD_STAY_CURRENT_PORTRAIT "\xee\x83\x94" // U+e0d4 +#define ICON_MD_STAY_PRIMARY_LANDSCAPE "\xee\x83\x95" // U+e0d5 +#define ICON_MD_STAY_PRIMARY_PORTRAIT "\xee\x83\x96" // U+e0d6 +#define ICON_MD_STICKY_NOTE_2 "\xef\x87\xbc" // U+f1fc +#define ICON_MD_STOP "\xee\x81\x87" // U+e047 +#define ICON_MD_STOP_CIRCLE "\xee\xbd\xb1" // U+ef71 +#define ICON_MD_STOP_SCREEN_SHARE "\xee\x83\xa3" // U+e0e3 +#define ICON_MD_STORAGE "\xee\x87\x9b" // U+e1db +#define ICON_MD_STORE "\xee\xa3\x91" // U+e8d1 +#define ICON_MD_STORE_MALL_DIRECTORY "\xee\x95\xa3" // U+e563 +#define ICON_MD_STOREFRONT "\xee\xa8\x92" // U+ea12 +#define ICON_MD_STORM "\xef\x81\xb0" // U+f070 +#define ICON_MD_STRAIGHT "\xee\xae\x95" // U+eb95 +#define ICON_MD_STRAIGHTEN "\xee\x90\x9c" // U+e41c +#define ICON_MD_STREAM "\xee\xa7\xa9" // U+e9e9 +#define ICON_MD_STREETVIEW "\xee\x95\xae" // U+e56e +#define ICON_MD_STRIKETHROUGH_S "\xee\x89\x97" // U+e257 +#define ICON_MD_STROLLER "\xef\x86\xae" // U+f1ae +#define ICON_MD_STYLE "\xee\x90\x9d" // U+e41d +#define ICON_MD_SUBDIRECTORY_ARROW_LEFT "\xee\x97\x99" // U+e5d9 +#define ICON_MD_SUBDIRECTORY_ARROW_RIGHT "\xee\x97\x9a" // U+e5da +#define ICON_MD_SUBJECT "\xee\xa3\x92" // U+e8d2 +#define ICON_MD_SUBSCRIPT "\xef\x84\x91" // U+f111 +#define ICON_MD_SUBSCRIPTIONS "\xee\x81\xa4" // U+e064 +#define ICON_MD_SUBTITLES "\xee\x81\x88" // U+e048 +#define ICON_MD_SUBTITLES_OFF "\xee\xbd\xb2" // U+ef72 +#define ICON_MD_SUBWAY "\xee\x95\xaf" // U+e56f +#define ICON_MD_SUMMARIZE "\xef\x81\xb1" // U+f071 +#define ICON_MD_SUNNY "\xee\xa0\x9a" // U+e81a +#define ICON_MD_SUNNY_SNOWING "\xee\xa0\x99" // U+e819 +#define ICON_MD_SUPERSCRIPT "\xef\x84\x92" // U+f112 +#define ICON_MD_SUPERVISED_USER_CIRCLE "\xee\xa4\xb9" // U+e939 +#define ICON_MD_SUPERVISOR_ACCOUNT "\xee\xa3\x93" // U+e8d3 +#define ICON_MD_SUPPORT "\xee\xbd\xb3" // U+ef73 +#define ICON_MD_SUPPORT_AGENT "\xef\x83\xa2" // U+f0e2 +#define ICON_MD_SURFING "\xee\x94\x95" // U+e515 +#define ICON_MD_SURROUND_SOUND "\xee\x81\x89" // U+e049 +#define ICON_MD_SWAP_CALLS "\xee\x83\x97" // U+e0d7 +#define ICON_MD_SWAP_HORIZ "\xee\xa3\x94" // U+e8d4 +#define ICON_MD_SWAP_HORIZONTAL_CIRCLE "\xee\xa4\xb3" // U+e933 +#define ICON_MD_SWAP_VERT "\xee\xa3\x95" // U+e8d5 +#define ICON_MD_SWAP_VERT_CIRCLE "\xee\xa3\x96" // U+e8d6 +#define ICON_MD_SWAP_VERTICAL_CIRCLE "\xee\xa3\x96" // U+e8d6 +#define ICON_MD_SWIPE "\xee\xa7\xac" // U+e9ec +#define ICON_MD_SWIPE_DOWN "\xee\xad\x93" // U+eb53 +#define ICON_MD_SWIPE_DOWN_ALT "\xee\xac\xb0" // U+eb30 +#define ICON_MD_SWIPE_LEFT "\xee\xad\x99" // U+eb59 +#define ICON_MD_SWIPE_LEFT_ALT "\xee\xac\xb3" // U+eb33 +#define ICON_MD_SWIPE_RIGHT "\xee\xad\x92" // U+eb52 +#define ICON_MD_SWIPE_RIGHT_ALT "\xee\xad\x96" // U+eb56 +#define ICON_MD_SWIPE_UP "\xee\xac\xae" // U+eb2e +#define ICON_MD_SWIPE_UP_ALT "\xee\xac\xb5" // U+eb35 +#define ICON_MD_SWIPE_VERTICAL "\xee\xad\x91" // U+eb51 +#define ICON_MD_SWITCH_ACCESS_SHORTCUT "\xee\x9f\xa1" // U+e7e1 +#define ICON_MD_SWITCH_ACCESS_SHORTCUT_ADD "\xee\x9f\xa2" // U+e7e2 +#define ICON_MD_SWITCH_ACCOUNT "\xee\xa7\xad" // U+e9ed +#define ICON_MD_SWITCH_CAMERA "\xee\x90\x9e" // U+e41e +#define ICON_MD_SWITCH_LEFT "\xef\x87\x91" // U+f1d1 +#define ICON_MD_SWITCH_RIGHT "\xef\x87\x92" // U+f1d2 +#define ICON_MD_SWITCH_VIDEO "\xee\x90\x9f" // U+e41f +#define ICON_MD_SYNAGOGUE "\xee\xaa\xb0" // U+eab0 +#define ICON_MD_SYNC "\xee\x98\xa7" // U+e627 +#define ICON_MD_SYNC_ALT "\xee\xa8\x98" // U+ea18 +#define ICON_MD_SYNC_DISABLED "\xee\x98\xa8" // U+e628 +#define ICON_MD_SYNC_LOCK "\xee\xab\xae" // U+eaee +#define ICON_MD_SYNC_PROBLEM "\xee\x98\xa9" // U+e629 +#define ICON_MD_SYSTEM_SECURITY_UPDATE "\xef\x81\xb2" // U+f072 +#define ICON_MD_SYSTEM_SECURITY_UPDATE_GOOD "\xef\x81\xb3" // U+f073 +#define ICON_MD_SYSTEM_SECURITY_UPDATE_WARNING "\xef\x81\xb4" // U+f074 +#define ICON_MD_SYSTEM_UPDATE "\xee\x98\xaa" // U+e62a +#define ICON_MD_SYSTEM_UPDATE_ALT "\xee\xa3\x97" // U+e8d7 +#define ICON_MD_SYSTEM_UPDATE_TV "\xee\xa3\x97" // U+e8d7 +#define ICON_MD_TAB "\xee\xa3\x98" // U+e8d8 +#define ICON_MD_TAB_UNSELECTED "\xee\xa3\x99" // U+e8d9 +#define ICON_MD_TABLE_BAR "\xee\xab\x92" // U+ead2 +#define ICON_MD_TABLE_CHART "\xee\x89\xa5" // U+e265 +#define ICON_MD_TABLE_RESTAURANT "\xee\xab\x86" // U+eac6 +#define ICON_MD_TABLE_ROWS "\xef\x84\x81" // U+f101 +#define ICON_MD_TABLE_VIEW "\xef\x86\xbe" // U+f1be +#define ICON_MD_TABLET "\xee\x8c\xaf" // U+e32f +#define ICON_MD_TABLET_ANDROID "\xee\x8c\xb0" // U+e330 +#define ICON_MD_TABLET_MAC "\xee\x8c\xb1" // U+e331 +#define ICON_MD_TAG "\xee\xa7\xaf" // U+e9ef +#define ICON_MD_TAG_FACES "\xee\x90\xa0" // U+e420 +#define ICON_MD_TAKEOUT_DINING "\xee\xa9\xb4" // U+ea74 +#define ICON_MD_TAP_AND_PLAY "\xee\x98\xab" // U+e62b +#define ICON_MD_TAPAS "\xef\x87\xa9" // U+f1e9 +#define ICON_MD_TASK "\xef\x81\xb5" // U+f075 +#define ICON_MD_TASK_ALT "\xee\x8b\xa6" // U+e2e6 +#define ICON_MD_TAXI_ALERT "\xee\xbd\xb4" // U+ef74 +#define ICON_MD_TELEGRAM "\xee\xa9\xab" // U+ea6b +#define ICON_MD_TEMPLE_BUDDHIST "\xee\xaa\xb3" // U+eab3 +#define ICON_MD_TEMPLE_HINDU "\xee\xaa\xaf" // U+eaaf +#define ICON_MD_TERMINAL "\xee\xae\x8e" // U+eb8e +#define ICON_MD_TERRAIN "\xee\x95\xa4" // U+e564 +#define ICON_MD_TEXT_DECREASE "\xee\xab\x9d" // U+eadd +#define ICON_MD_TEXT_FIELDS "\xee\x89\xa2" // U+e262 +#define ICON_MD_TEXT_FORMAT "\xee\x85\xa5" // U+e165 +#define ICON_MD_TEXT_INCREASE "\xee\xab\xa2" // U+eae2 +#define ICON_MD_TEXT_ROTATE_UP "\xee\xa4\xba" // U+e93a +#define ICON_MD_TEXT_ROTATE_VERTICAL "\xee\xa4\xbb" // U+e93b +#define ICON_MD_TEXT_ROTATION_ANGLEDOWN "\xee\xa4\xbc" // U+e93c +#define ICON_MD_TEXT_ROTATION_ANGLEUP "\xee\xa4\xbd" // U+e93d +#define ICON_MD_TEXT_ROTATION_DOWN "\xee\xa4\xbe" // U+e93e +#define ICON_MD_TEXT_ROTATION_NONE "\xee\xa4\xbf" // U+e93f +#define ICON_MD_TEXT_SNIPPET "\xef\x87\x86" // U+f1c6 +#define ICON_MD_TEXTSMS "\xee\x83\x98" // U+e0d8 +#define ICON_MD_TEXTURE "\xee\x90\xa1" // U+e421 +#define ICON_MD_THEATER_COMEDY "\xee\xa9\xa6" // U+ea66 +#define ICON_MD_THEATERS "\xee\xa3\x9a" // U+e8da +#define ICON_MD_THERMOSTAT "\xef\x81\xb6" // U+f076 +#define ICON_MD_THERMOSTAT_AUTO "\xef\x81\xb7" // U+f077 +#define ICON_MD_THUMB_DOWN "\xee\xa3\x9b" // U+e8db +#define ICON_MD_THUMB_DOWN_ALT "\xee\xa0\x96" // U+e816 +#define ICON_MD_THUMB_DOWN_OFF_ALT "\xee\xa7\xb2" // U+e9f2 +#define ICON_MD_THUMB_UP "\xee\xa3\x9c" // U+e8dc +#define ICON_MD_THUMB_UP_ALT "\xee\xa0\x97" // U+e817 +#define ICON_MD_THUMB_UP_OFF_ALT "\xee\xa7\xb3" // U+e9f3 +#define ICON_MD_THUMBS_UP_DOWN "\xee\xa3\x9d" // U+e8dd +#define ICON_MD_THUNDERSTORM "\xee\xaf\x9b" // U+ebdb +#define ICON_MD_TIKTOK "\xee\xa9\xbe" // U+ea7e +#define ICON_MD_TIME_TO_LEAVE "\xee\x98\xac" // U+e62c +#define ICON_MD_TIMELAPSE "\xee\x90\xa2" // U+e422 +#define ICON_MD_TIMELINE "\xee\xa4\xa2" // U+e922 +#define ICON_MD_TIMER "\xee\x90\xa5" // U+e425 +#define ICON_MD_TIMER_10 "\xee\x90\xa3" // U+e423 +#define ICON_MD_TIMER_10_SELECT "\xef\x81\xba" // U+f07a +#define ICON_MD_TIMER_3 "\xee\x90\xa4" // U+e424 +#define ICON_MD_TIMER_3_SELECT "\xef\x81\xbb" // U+f07b +#define ICON_MD_TIMER_OFF "\xee\x90\xa6" // U+e426 +#define ICON_MD_TIPS_AND_UPDATES "\xee\x9e\x9a" // U+e79a +#define ICON_MD_TIRE_REPAIR "\xee\xaf\x88" // U+ebc8 +#define ICON_MD_TITLE "\xee\x89\xa4" // U+e264 +#define ICON_MD_TOC "\xee\xa3\x9e" // U+e8de +#define ICON_MD_TODAY "\xee\xa3\x9f" // U+e8df +#define ICON_MD_TOGGLE_OFF "\xee\xa7\xb5" // U+e9f5 +#define ICON_MD_TOGGLE_ON "\xee\xa7\xb6" // U+e9f6 +#define ICON_MD_TOKEN "\xee\xa8\xa5" // U+ea25 +#define ICON_MD_TOLL "\xee\xa3\xa0" // U+e8e0 +#define ICON_MD_TONALITY "\xee\x90\xa7" // U+e427 +#define ICON_MD_TOPIC "\xef\x87\x88" // U+f1c8 +#define ICON_MD_TORNADO "\xee\x86\x99" // U+e199 +#define ICON_MD_TOUCH_APP "\xee\xa4\x93" // U+e913 +#define ICON_MD_TOUR "\xee\xbd\xb5" // U+ef75 +#define ICON_MD_TOYS "\xee\x8c\xb2" // U+e332 +#define ICON_MD_TRACK_CHANGES "\xee\xa3\xa1" // U+e8e1 +#define ICON_MD_TRAFFIC "\xee\x95\xa5" // U+e565 +#define ICON_MD_TRAIN "\xee\x95\xb0" // U+e570 +#define ICON_MD_TRAM "\xee\x95\xb1" // U+e571 +#define ICON_MD_TRANSCRIBE "\xef\xa3\xac" // U+f8ec +#define ICON_MD_TRANSFER_WITHIN_A_STATION "\xee\x95\xb2" // U+e572 +#define ICON_MD_TRANSFORM "\xee\x90\xa8" // U+e428 +#define ICON_MD_TRANSGENDER "\xee\x96\x8d" // U+e58d +#define ICON_MD_TRANSIT_ENTEREXIT "\xee\x95\xb9" // U+e579 +#define ICON_MD_TRANSLATE "\xee\xa3\xa2" // U+e8e2 +#define ICON_MD_TRAVEL_EXPLORE "\xee\x8b\x9b" // U+e2db +#define ICON_MD_TRENDING_DOWN "\xee\xa3\xa3" // U+e8e3 +#define ICON_MD_TRENDING_FLAT "\xee\xa3\xa4" // U+e8e4 +#define ICON_MD_TRENDING_NEUTRAL "\xee\xa3\xa4" // U+e8e4 +#define ICON_MD_TRENDING_UP "\xee\xa3\xa5" // U+e8e5 +#define ICON_MD_TRIP_ORIGIN "\xee\x95\xbb" // U+e57b +#define ICON_MD_TROLLEY "\xef\xa1\xab" // U+f86b +#define ICON_MD_TROUBLESHOOT "\xee\x87\x92" // U+e1d2 +#define ICON_MD_TRY "\xef\x81\xbc" // U+f07c +#define ICON_MD_TSUNAMI "\xee\xaf\x98" // U+ebd8 +#define ICON_MD_TTY "\xef\x86\xaa" // U+f1aa +#define ICON_MD_TUNE "\xee\x90\xa9" // U+e429 +#define ICON_MD_TUNGSTEN "\xef\x81\xbd" // U+f07d +#define ICON_MD_TURN_LEFT "\xee\xae\xa6" // U+eba6 +#define ICON_MD_TURN_RIGHT "\xee\xae\xab" // U+ebab +#define ICON_MD_TURN_SHARP_LEFT "\xee\xae\xa7" // U+eba7 +#define ICON_MD_TURN_SHARP_RIGHT "\xee\xae\xaa" // U+ebaa +#define ICON_MD_TURN_SLIGHT_LEFT "\xee\xae\xa4" // U+eba4 +#define ICON_MD_TURN_SLIGHT_RIGHT "\xee\xae\x9a" // U+eb9a +#define ICON_MD_TURNED_IN "\xee\xa3\xa6" // U+e8e6 +#define ICON_MD_TURNED_IN_NOT "\xee\xa3\xa7" // U+e8e7 +#define ICON_MD_TV "\xee\x8c\xb3" // U+e333 +#define ICON_MD_TV_OFF "\xee\x99\x87" // U+e647 +#define ICON_MD_TWO_WHEELER "\xee\xa7\xb9" // U+e9f9 +#define ICON_MD_TYPE_SPECIMEN "\xef\xa3\xb0" // U+f8f0 +#define ICON_MD_U_TURN_LEFT "\xee\xae\xa1" // U+eba1 +#define ICON_MD_U_TURN_RIGHT "\xee\xae\xa2" // U+eba2 +#define ICON_MD_UMBRELLA "\xef\x86\xad" // U+f1ad +#define ICON_MD_UNARCHIVE "\xee\x85\xa9" // U+e169 +#define ICON_MD_UNDO "\xee\x85\xa6" // U+e166 +#define ICON_MD_UNFOLD_LESS "\xee\x97\x96" // U+e5d6 +#define ICON_MD_UNFOLD_LESS_DOUBLE "\xef\xa3\x8f" // U+f8cf +#define ICON_MD_UNFOLD_MORE "\xee\x97\x97" // U+e5d7 +#define ICON_MD_UNFOLD_MORE_DOUBLE "\xef\xa3\x90" // U+f8d0 +#define ICON_MD_UNPUBLISHED "\xef\x88\xb6" // U+f236 +#define ICON_MD_UNSUBSCRIBE "\xee\x83\xab" // U+e0eb +#define ICON_MD_UPCOMING "\xef\x81\xbe" // U+f07e +#define ICON_MD_UPDATE "\xee\xa4\xa3" // U+e923 +#define ICON_MD_UPDATE_DISABLED "\xee\x81\xb5" // U+e075 +#define ICON_MD_UPGRADE "\xef\x83\xbb" // U+f0fb +#define ICON_MD_UPLOAD "\xef\x82\x9b" // U+f09b +#define ICON_MD_UPLOAD_FILE "\xee\xa7\xbc" // U+e9fc +#define ICON_MD_USB "\xee\x87\xa0" // U+e1e0 +#define ICON_MD_USB_OFF "\xee\x93\xba" // U+e4fa +#define ICON_MD_VACCINES "\xee\x84\xb8" // U+e138 +#define ICON_MD_VAPE_FREE "\xee\xaf\x86" // U+ebc6 +#define ICON_MD_VAPING_ROOMS "\xee\xaf\x8f" // U+ebcf +#define ICON_MD_VERIFIED "\xee\xbd\xb6" // U+ef76 +#define ICON_MD_VERIFIED_USER "\xee\xa3\xa8" // U+e8e8 +#define ICON_MD_VERTICAL_ALIGN_BOTTOM "\xee\x89\x98" // U+e258 +#define ICON_MD_VERTICAL_ALIGN_CENTER "\xee\x89\x99" // U+e259 +#define ICON_MD_VERTICAL_ALIGN_TOP "\xee\x89\x9a" // U+e25a +#define ICON_MD_VERTICAL_DISTRIBUTE "\xee\x81\xb6" // U+e076 +#define ICON_MD_VERTICAL_SHADES "\xee\xb0\x8e" // U+ec0e +#define ICON_MD_VERTICAL_SHADES_CLOSED "\xee\xb0\x8d" // U+ec0d +#define ICON_MD_VERTICAL_SPLIT "\xee\xa5\x89" // U+e949 +#define ICON_MD_VIBRATION "\xee\x98\xad" // U+e62d +#define ICON_MD_VIDEO_CALL "\xee\x81\xb0" // U+e070 +#define ICON_MD_VIDEO_CAMERA_BACK "\xef\x81\xbf" // U+f07f +#define ICON_MD_VIDEO_CAMERA_FRONT "\xef\x82\x80" // U+f080 +#define ICON_MD_VIDEO_CHAT "\xef\xa2\xa0" // U+f8a0 +#define ICON_MD_VIDEO_COLLECTION "\xee\x81\x8a" // U+e04a +#define ICON_MD_VIDEO_FILE "\xee\xae\x87" // U+eb87 +#define ICON_MD_VIDEO_LABEL "\xee\x81\xb1" // U+e071 +#define ICON_MD_VIDEO_LIBRARY "\xee\x81\x8a" // U+e04a +#define ICON_MD_VIDEO_SETTINGS "\xee\xa9\xb5" // U+ea75 +#define ICON_MD_VIDEO_STABLE "\xef\x82\x81" // U+f081 +#define ICON_MD_VIDEOCAM "\xee\x81\x8b" // U+e04b +#define ICON_MD_VIDEOCAM_OFF "\xee\x81\x8c" // U+e04c +#define ICON_MD_VIDEOGAME_ASSET "\xee\x8c\xb8" // U+e338 +#define ICON_MD_VIDEOGAME_ASSET_OFF "\xee\x94\x80" // U+e500 +#define ICON_MD_VIEW_AGENDA "\xee\xa3\xa9" // U+e8e9 +#define ICON_MD_VIEW_ARRAY "\xee\xa3\xaa" // U+e8ea +#define ICON_MD_VIEW_CAROUSEL "\xee\xa3\xab" // U+e8eb +#define ICON_MD_VIEW_COLUMN "\xee\xa3\xac" // U+e8ec +#define ICON_MD_VIEW_COMFORTABLE "\xee\x90\xaa" // U+e42a +#define ICON_MD_VIEW_COMFY "\xee\x90\xaa" // U+e42a +#define ICON_MD_VIEW_COMFY_ALT "\xee\xad\xb3" // U+eb73 +#define ICON_MD_VIEW_COMPACT "\xee\x90\xab" // U+e42b +#define ICON_MD_VIEW_COMPACT_ALT "\xee\xad\xb4" // U+eb74 +#define ICON_MD_VIEW_COZY "\xee\xad\xb5" // U+eb75 +#define ICON_MD_VIEW_DAY "\xee\xa3\xad" // U+e8ed +#define ICON_MD_VIEW_HEADLINE "\xee\xa3\xae" // U+e8ee +#define ICON_MD_VIEW_IN_AR "\xee\xa7\xbe" // U+e9fe +#define ICON_MD_VIEW_KANBAN "\xee\xad\xbf" // U+eb7f +#define ICON_MD_VIEW_LIST "\xee\xa3\xaf" // U+e8ef +#define ICON_MD_VIEW_MODULE "\xee\xa3\xb0" // U+e8f0 +#define ICON_MD_VIEW_QUILT "\xee\xa3\xb1" // U+e8f1 +#define ICON_MD_VIEW_SIDEBAR "\xef\x84\x94" // U+f114 +#define ICON_MD_VIEW_STREAM "\xee\xa3\xb2" // U+e8f2 +#define ICON_MD_VIEW_TIMELINE "\xee\xae\x85" // U+eb85 +#define ICON_MD_VIEW_WEEK "\xee\xa3\xb3" // U+e8f3 +#define ICON_MD_VIGNETTE "\xee\x90\xb5" // U+e435 +#define ICON_MD_VILLA "\xee\x96\x86" // U+e586 +#define ICON_MD_VISIBILITY "\xee\xa3\xb4" // U+e8f4 +#define ICON_MD_VISIBILITY_OFF "\xee\xa3\xb5" // U+e8f5 +#define ICON_MD_VOICE_CHAT "\xee\x98\xae" // U+e62e +#define ICON_MD_VOICE_OVER_OFF "\xee\xa5\x8a" // U+e94a +#define ICON_MD_VOICEMAIL "\xee\x83\x99" // U+e0d9 +#define ICON_MD_VOLCANO "\xee\xaf\x9a" // U+ebda +#define ICON_MD_VOLUME_DOWN "\xee\x81\x8d" // U+e04d +#define ICON_MD_VOLUME_DOWN_ALT "\xee\x9e\x9c" // U+e79c +#define ICON_MD_VOLUME_MUTE "\xee\x81\x8e" // U+e04e +#define ICON_MD_VOLUME_OFF "\xee\x81\x8f" // U+e04f +#define ICON_MD_VOLUME_UP "\xee\x81\x90" // U+e050 +#define ICON_MD_VOLUNTEER_ACTIVISM "\xee\xa9\xb0" // U+ea70 +#define ICON_MD_VPN_KEY "\xee\x83\x9a" // U+e0da +#define ICON_MD_VPN_KEY_OFF "\xee\xad\xba" // U+eb7a +#define ICON_MD_VPN_LOCK "\xee\x98\xaf" // U+e62f +#define ICON_MD_VRPANO "\xef\x82\x82" // U+f082 +#define ICON_MD_WALLET "\xef\xa3\xbf" // U+f8ff +#define ICON_MD_WALLET_GIFTCARD "\xee\xa3\xb6" // U+e8f6 +#define ICON_MD_WALLET_MEMBERSHIP "\xee\xa3\xb7" // U+e8f7 +#define ICON_MD_WALLET_TRAVEL "\xee\xa3\xb8" // U+e8f8 +#define ICON_MD_WALLPAPER "\xee\x86\xbc" // U+e1bc +#define ICON_MD_WAREHOUSE "\xee\xae\xb8" // U+ebb8 +#define ICON_MD_WARNING "\xee\x80\x82" // U+e002 +#define ICON_MD_WARNING_AMBER "\xef\x82\x83" // U+f083 +#define ICON_MD_WASH "\xef\x86\xb1" // U+f1b1 +#define ICON_MD_WATCH "\xee\x8c\xb4" // U+e334 +#define ICON_MD_WATCH_LATER "\xee\xa4\xa4" // U+e924 +#define ICON_MD_WATCH_OFF "\xee\xab\xa3" // U+eae3 +#define ICON_MD_WATER "\xef\x82\x84" // U+f084 +#define ICON_MD_WATER_DAMAGE "\xef\x88\x83" // U+f203 +#define ICON_MD_WATER_DROP "\xee\x9e\x98" // U+e798 +#define ICON_MD_WATERFALL_CHART "\xee\xa8\x80" // U+ea00 +#define ICON_MD_WAVES "\xee\x85\xb6" // U+e176 +#define ICON_MD_WAVING_HAND "\xee\x9d\xa6" // U+e766 +#define ICON_MD_WB_AUTO "\xee\x90\xac" // U+e42c +#define ICON_MD_WB_CLOUDY "\xee\x90\xad" // U+e42d +#define ICON_MD_WB_INCANDESCENT "\xee\x90\xae" // U+e42e +#define ICON_MD_WB_IRIDESCENT "\xee\x90\xb6" // U+e436 +#define ICON_MD_WB_SHADE "\xee\xa8\x81" // U+ea01 +#define ICON_MD_WB_SUNNY "\xee\x90\xb0" // U+e430 +#define ICON_MD_WB_TWIGHLIGHT "\xee\xa8\x82" // U+ea02 +#define ICON_MD_WB_TWILIGHT "\xee\x87\x86" // U+e1c6 +#define ICON_MD_WC "\xee\x98\xbd" // U+e63d +#define ICON_MD_WEB "\xee\x81\x91" // U+e051 +#define ICON_MD_WEB_ASSET "\xee\x81\xa9" // U+e069 +#define ICON_MD_WEB_ASSET_OFF "\xee\x93\xb7" // U+e4f7 +#define ICON_MD_WEB_STORIES "\xee\x96\x95" // U+e595 +#define ICON_MD_WEBHOOK "\xee\xae\x92" // U+eb92 +#define ICON_MD_WECHAT "\xee\xaa\x81" // U+ea81 +#define ICON_MD_WEEKEND "\xee\x85\xab" // U+e16b +#define ICON_MD_WEST "\xef\x87\xa6" // U+f1e6 +#define ICON_MD_WHATSHOT "\xee\xa0\x8e" // U+e80e +#define ICON_MD_WHEELCHAIR_PICKUP "\xef\x86\xab" // U+f1ab +#define ICON_MD_WHERE_TO_VOTE "\xee\x85\xb7" // U+e177 +#define ICON_MD_WIDGETS "\xee\x86\xbd" // U+e1bd +#define ICON_MD_WIDTH_FULL "\xef\xa3\xb5" // U+f8f5 +#define ICON_MD_WIDTH_NORMAL "\xef\xa3\xb6" // U+f8f6 +#define ICON_MD_WIDTH_WIDE "\xef\xa3\xb7" // U+f8f7 +#define ICON_MD_WIFI "\xee\x98\xbe" // U+e63e +#define ICON_MD_WIFI_1_BAR "\xee\x93\x8a" // U+e4ca +#define ICON_MD_WIFI_2_BAR "\xee\x93\x99" // U+e4d9 +#define ICON_MD_WIFI_CALLING "\xee\xbd\xb7" // U+ef77 +#define ICON_MD_WIFI_CALLING_3 "\xef\x82\x85" // U+f085 +#define ICON_MD_WIFI_CHANNEL "\xee\xad\xaa" // U+eb6a +#define ICON_MD_WIFI_FIND "\xee\xac\xb1" // U+eb31 +#define ICON_MD_WIFI_LOCK "\xee\x87\xa1" // U+e1e1 +#define ICON_MD_WIFI_OFF "\xee\x99\x88" // U+e648 +#define ICON_MD_WIFI_PASSWORD "\xee\xad\xab" // U+eb6b +#define ICON_MD_WIFI_PROTECTED_SETUP "\xef\x83\xbc" // U+f0fc +#define ICON_MD_WIFI_TETHERING "\xee\x87\xa2" // U+e1e2 +#define ICON_MD_WIFI_TETHERING_ERROR "\xee\xab\x99" // U+ead9 +#define ICON_MD_WIFI_TETHERING_ERROR_ROUNDED "\xef\x82\x86" // U+f086 +#define ICON_MD_WIFI_TETHERING_OFF "\xef\x82\x87" // U+f087 +#define ICON_MD_WIND_POWER "\xee\xb0\x8c" // U+ec0c +#define ICON_MD_WINDOW "\xef\x82\x88" // U+f088 +#define ICON_MD_WINE_BAR "\xef\x87\xa8" // U+f1e8 +#define ICON_MD_WOMAN "\xee\x84\xbe" // U+e13e +#define ICON_MD_WOMAN_2 "\xef\xa3\xa7" // U+f8e7 +#define ICON_MD_WOO_COMMERCE "\xee\xa9\xad" // U+ea6d +#define ICON_MD_WORDPRESS "\xee\xaa\x9f" // U+ea9f +#define ICON_MD_WORK "\xee\xa3\xb9" // U+e8f9 +#define ICON_MD_WORK_HISTORY "\xee\xb0\x89" // U+ec09 +#define ICON_MD_WORK_OFF "\xee\xa5\x82" // U+e942 +#define ICON_MD_WORK_OUTLINE "\xee\xa5\x83" // U+e943 +#define ICON_MD_WORKSPACE_PREMIUM "\xee\x9e\xaf" // U+e7af +#define ICON_MD_WORKSPACES "\xee\x86\xa0" // U+e1a0 +#define ICON_MD_WORKSPACES_FILLED "\xee\xa8\x8d" // U+ea0d +#define ICON_MD_WORKSPACES_OUTLINE "\xee\xa8\x8f" // U+ea0f +#define ICON_MD_WRAP_TEXT "\xee\x89\x9b" // U+e25b +#define ICON_MD_WRONG_LOCATION "\xee\xbd\xb8" // U+ef78 +#define ICON_MD_WYSIWYG "\xef\x87\x83" // U+f1c3 +#define ICON_MD_YARD "\xef\x82\x89" // U+f089 +#define ICON_MD_YOUTUBE_SEARCHED_FOR "\xee\xa3\xba" // U+e8fa +#define ICON_MD_ZOOM_IN "\xee\xa3\xbf" // U+e8ff +#define ICON_MD_ZOOM_IN_MAP "\xee\xac\xad" // U+eb2d +#define ICON_MD_ZOOM_OUT "\xee\xa4\x80" // U+e900 +#define ICON_MD_ZOOM_OUT_MAP "\xee\x95\xab" // U+e56b \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/MaterialDesign/MaterialIcons.h b/Amalgam/src/Features/ImGui/MaterialDesign/MaterialIcons.h new file mode 100644 index 0000000..c5a0a70 --- /dev/null +++ b/Amalgam/src/Features/ImGui/MaterialDesign/MaterialIcons.h @@ -0,0 +1,5137 @@ +#pragma once +static const unsigned int MaterialIcons_compressed_size = 246305; +static const unsigned int MaterialIcons_compressed_data[246308 / 4] = +{ + 0x0000bc57, 0x00000000, 0xe8710500, 0x00000400, 0x00010037, 0x000f0000, 0x00030080, 0x45444770, 0x00090546, 0x01000053, 0x28158214, 0x4f50471c, + 0x00150053, 0x200f820a, 0x380f8208, 0x5553470c, 0xc89a4442, 0x6d0000b2, 0xef000080, 0x2f534fc4, 0x22730a32, 0x201f8263, 0x381f82cc, 0x616d6360, + 0xa0049470, 0x370000ba, 0x350000f0, 0x7476638e, 0x01110020, 0x201b8244, 0x260382fc, 0x73616704, 0x82ffff70, 0x38748469, 0x6c670800, 0x9c8a6679, + 0x0100041a, 0x0400445d, 0x6568a114, 0xeb186461, 0x207f83b8, 0x212f8294, 0x10826836, 0x02010423, 0x205f8203, 0x080f8270, 0x6d682428, 0x6df67874, + 0x00000bf5, 0x0000a803, 0x6f6c7011, 0xf00f6163, 0x0000e761, 0x00001815, 0x616dd822, 0x0f097078, 0x2f82d001, 0x2f823020, 0x616e202c, 0xf11b656d, + 0x00008035, 0x13822c02, 0x6f707a28, 0x86ff7473, 0x0b823200, 0x1f835020, 0x01209b86, 0x02209382, 0x0a209284, 0x0a20eb82, 0x01201982, 0x0c200382, + 0x02830382, 0x0200022c, 0x27000300, 0x28000100, 0x0b82f604, 0x00000127, 0x9f01b508, 0x82718200, 0x0002241e, 0x84010000, 0x0040223b, 0x200b822e, + 0x842b8200, 0x83ff2106, 0x0a846783, 0x0124048d, 0x00020000, 0x02260083, 0xfffeff00, 0x3d8502ff, 0x03871083, 0x4f840320, 0x5a04012c, 0x0361708f, + 0xf53c0f5f, 0x31850900, 0xa1a4d824, 0x00820037, 0xd12adf23, 0x243b82c4, 0x020102fd, 0x200e8203, 0x82958508, 0x02042c09, 0x00900100, 0x01000005, + 0x8266014c, 0x8647200f, 0x00f52507, 0x00840019, 0x05202682, 0x18822f83, 0x01210282, 0x20048212, 0x88038204, 0x00802202, 0x848f8230, 0x0002210e, + 0x01200084, 0x04850584, 0x2b002022, 0x07280882, 0x03005a00, 0x09040100, 0x60220b82, 0x0b86c000, 0x1c000124, 0x0b86a400, 0x0e000224, 0x0b869600, + 0x52000324, 0x0b864400, 0x238a0420, 0x1a000524, 0x17862a00, 0x09820620, 0x4d00002c, 0x74006100, 0x72006500, 0x09826900, 0x49006c2e, 0x6f006300, + 0x73006e00, 0x52002d00, 0x67241782, 0x6c007500, 0x72221982, 0x25845600, 0x27827320, 0x1f826f20, 0x31002026, 0x30002e00, 0x37220582, 0x31844600, + 0x07847420, 0x67007222, 0x20222782, 0x1d843200, 0x3a002024, 0x63902000, 0x658a2020, 0x35202185, 0x33206d82, 0x32200382, 0x39205184, 0xa38f798e, + 0x43203f8b, 0x70227b82, 0xbf847900, 0x68006722, 0x2020cb82, 0x97837b82, 0x79823820, 0x1d824720, 0x91826f20, 0x93826c20, 0x0f822c20, 0xb9824920, + 0x99826320, 0x41002022, 0x6c20d582, 0x52201182, 0x3785cf82, 0x0d847320, 0xf9826520, 0x4d826520, 0x31827620, 0x29826420, 0x00020025, 0x82001100, + 0x00022100, 0x2b2800cc, 0x15002b00, 0x55004000, 0x40200782, 0x0b830784, 0x0d883520, 0x6b006b22, 0x25831582, 0x2b222985, 0x1b828000, 0xab002b22, + 0x13830584, 0x41864020, 0x55203783, 0x1f831d82, 0x2b202385, 0x6b223984, 0x07829500, 0x40222583, 0x6b822200, 0x6b825520, 0x15200387, 0x2b200f82, + 0x55207b84, 0x15200982, 0x13835384, 0x39842c20, 0x21850983, 0xa3844020, 0x53834383, 0x31820020, 0x21827720, 0x39846b20, 0xc1831587, 0xad842b20, + 0x6b201183, 0x2b224b84, 0x49843300, 0x20053241, 0x2045825b, 0x8303846b, 0x880020b7, 0x862a20f7, 0x8325837b, 0x834585c5, 0x00402279, 0x22478254, + 0x82020040, 0x07074157, 0x26824020, 0xfb852183, 0x8983d785, 0x27413d20, 0x82212008, 0x201d852d, 0x87f98400, 0x85318923, 0x416b20e9, 0xd5830839, + 0x6f41b58b, 0x002b2207, 0x83018895, 0x8255207f, 0x000f214f, 0x2b200185, 0xc383fd82, 0x20072541, 0x207f8415, 0x20f78408, 0x22e58440, 0x82010015, + 0x206b8523, 0x236b8433, 0x00090008, 0x66202183, 0x4020c384, 0x44225b82, 0xad822000, 0x87009522, 0xb187a986, 0x0f864020, 0x95220789, 0x35822b00, + 0x03825520, 0x80201383, 0x35203782, 0x55201182, 0x21067141, 0x0983006b, 0x83848020, 0x83054b42, 0x827720d3, 0x82402021, 0x82552021, 0x07f34117, + 0x93845720, 0x3b844b20, 0x57414183, 0x20238307, 0x834d8435, 0x82038367, 0x2002846a, 0x064f416b, 0x20058142, 0x42138215, 0x80200515, 0x40205d84, + 0x80250582, 0xb700ab00, 0x837d8300, 0x842b2013, 0x842682fd, 0x84402002, 0x866b2099, 0x05e3420b, 0x55205183, 0xbb422582, 0x82152005, 0x20098721, + 0x4115826b, 0x6b2005a7, 0xc3834f82, 0x85003521, 0x418020a5, 0x0f200677, 0x8508e741, 0x41518397, 0x438305bf, 0x1d820020, 0x4107ad42, 0xa742073b, + 0x20238505, 0x22f78455, 0x82a8002b, 0x09b94167, 0x33830989, 0x23820020, 0x20050543, 0x43a38631, 0x55200541, 0x2b22c382, 0x61821e00, 0x2a201d83, + 0x19438784, 0x42758d09, 0x80280541, 0x2b006b00, 0xb700ab00, 0x13835184, 0x43059b41, 0x9183052b, 0x12001524, 0xff845700, 0x18001522, 0xfb852582, + 0x69822b20, 0x5f825920, 0x11841e20, 0x1282c785, 0x2b20b384, 0x81830584, 0x12824c20, 0x8b05ab41, 0x05054185, 0x9d845520, 0x2005f341, 0x437d8480, + 0x5f8505a7, 0x8b411d85, 0x84152005, 0x431183cf, 0x8020057b, 0x19830f82, 0x3a20c185, 0x83082343, 0x82602063, 0x826b20cf, 0x843a2011, 0x82152023, + 0x843e20b7, 0x82402011, 0x834d8505, 0x43552065, 0xcd41087f, 0x41802007, 0x2b2006d5, 0x55223182, 0x41829500, 0x09829520, 0x49002b26, 0xb700ab00, + 0x80222d82, 0x47868000, 0xd5005526, 0x9e005600, 0x45830182, 0x8024bf83, 0xc0007700, 0x00221582, 0x0b458500, 0x0513410a, 0x0020d385, 0x0f875d82, + 0x99820020, 0x6b413583, 0x823d2005, 0x826b200d, 0x0533446d, 0x09821520, 0x89842020, 0x5520df85, 0x1520db84, 0x80201182, 0xcd838d82, 0x83058945, + 0x00d52227, 0x4317823a, 0x214505d3, 0x054d4505, 0x83001521, 0x855d8561, 0x054b4167, 0x55204583, 0x42065d45, 0x4d4105cb, 0x09494405, 0x87057f42, + 0x0001210f, 0x85059544, 0x2015832b, 0x208d8423, 0x85cb8a2b, 0x825520d3, 0x82552071, 0x006b24f9, 0x840e0055, 0x422383bd, 0xdb430541, 0x00492207, + 0x414f8209, 0x9f8709e1, 0x6b204183, 0x83082946, 0x008021d7, 0x1f83eb83, 0x87057543, 0x05294285, 0x35833785, 0x8305b544, 0x820020b3, 0x0575447b, + 0x7d820020, 0x7d430b20, 0x09b14308, 0x2d202583, 0x29831782, 0x23828020, 0x03821120, 0x03821520, 0x07846b20, 0xb7824020, 0x43825a20, 0x2207b742, + 0x8234002b, 0x051d4191, 0x1787bf83, 0x20058146, 0x83c78400, 0x4503837d, 0x6b200593, 0xa9851384, 0x4d822b20, 0x87051741, 0x0961417f, 0x1d85e985, + 0x35223d83, 0xed822700, 0x2b223d83, 0x73845a00, 0x87821520, 0x00001524, 0x8f846500, 0x42052f41, 0xab20090b, 0x4020af82, 0xf5415f82, 0x05174305, + 0x0f820020, 0x8985d783, 0xe1449d83, 0x05c74305, 0x47824b20, 0x9d842a20, 0x49003722, 0x22066b42, 0x822a0055, 0x0531446b, 0x51844020, 0x85059947, + 0x11d74531, 0xcf4311bd, 0x057b4305, 0x6d841520, 0x8705b941, 0x84002079, 0x05ef41f7, 0x42050943, 0x354105b5, 0x09fd4105, 0x15242f83, 0x1e000000, + 0x0020cd84, 0x2b224982, 0x05820800, 0x09841520, 0x95411520, 0x43fd8508, 0x45850711, 0x6385d985, 0x90002b22, 0x31437182, 0x42252009, 0xab20062f, + 0x15220784, 0x01825500, 0x03822620, 0x97843f20, 0x05841520, 0x2c005e22, 0x33240782, 0x6b003f00, 0x03830782, 0x43843220, 0x27002b26, 0x01007600, + 0x67852d82, 0x85059741, 0x0563460b, 0x2207b542, 0x843d003f, 0x20898539, 0x206b8255, 0x20b78226, 0x08f94242, 0x17418f83, 0x833d8505, 0x448189e9, + 0xd38d0595, 0x00206b83, 0x6b204782, 0x4106d343, 0xad410701, 0x227d8705, 0x4788006b, 0x9d8508ef, 0x49054946, 0x934209d3, 0x84002005, 0x842a20d9, + 0x002b22ed, 0x21538242, 0x0d87006b, 0x15821e20, 0x45862d20, 0x15220b83, 0x2b411e00, 0x43ab8306, 0x4f830579, 0xd9462820, 0x20c5850a, 0x06594740, + 0x1344b987, 0x84002005, 0x0040243f, 0x822c001f, 0x00552455, 0x470f0080, 0x0f200649, 0x8b427782, 0x84542005, 0x07b141d9, 0x20094143, 0x2351821e, + 0x0095002b, 0x15856b83, 0xdf882820, 0x4d843c20, 0x5d826720, 0x16001e22, 0x20068b47, 0x480d821e, 0xa9460579, 0x09134209, 0x00001522, 0x43423384, + 0x05a94205, 0x40221d87, 0x1b825200, 0x87824020, 0x43845320, 0x20058b43, 0x850f822b, 0x200f87c5, 0x20438254, 0x08d34511, 0x08201b83, 0x15209184, + 0x4406ef41, 0x3783051b, 0xbb822b20, 0x99827d20, 0x33477d20, 0x822b2008, 0x84202037, 0x052f4af3, 0xab008022, 0x85084147, 0x0040248d, 0x8280005f, + 0x466d8537, 0x2b2009ad, 0x7d419382, 0x05bf4105, 0x49825520, 0x89822b20, 0xf3830d83, 0xe3420f20, 0x05ab4108, 0x27202b83, 0x420ac341, 0x5d430587, + 0x05e34205, 0x8783f785, 0xf7848020, 0x95002b22, 0x20089d42, 0x0a474b40, 0x0b825520, 0xa5820020, 0x0b836983, 0x2009d345, 0x45a78429, 0x714109a7, + 0x05074209, 0x4f845320, 0xa986ab20, 0x2d822b20, 0x0b822820, 0xdf821e20, 0x4a004022, 0x85087747, 0x0563413f, 0x82058347, 0x410282d6, 0x40200741, + 0x1e20f982, 0x20086546, 0x204d8435, 0x830f8855, 0x426b20ed, 0x6021065f, 0x050b4900, 0x3742d983, 0x07994905, 0xb1431520, 0x43558508, 0x7f43059b, + 0x85438507, 0x051942f3, 0x49054142, 0x272007cd, 0x15205782, 0x82089f42, 0x8502869a, 0x483185b3, 0x3a200761, 0x4d4a2784, 0x002b2205, 0x06c94895, + 0x44096b41, 0xef41092b, 0x07d74105, 0x83053143, 0x05cd4191, 0x0f004022, 0x55207582, 0x0f22fb84, 0x0b825f00, 0x85840020, 0x1e202783, 0xb383fd82, + 0x83071541, 0x821e2087, 0x82402093, 0xff2a2217, 0x42eb84fe, 0x40210913, 0x228d8300, 0x825a006b, 0x8235201d, 0x00552203, 0x08e7418b, 0x0f825520, + 0xa7472020, 0x4411830c, 0x40220551, 0xbd844400, 0x6b410f20, 0x00342406, 0x4d600035, 0x0542088f, 0x826b2007, 0x20418311, 0x83af8255, 0x84002037, + 0x20cd857d, 0x421b8255, 0x3f200535, 0xe54c638c, 0x05514705, 0x5c004022, 0x1c221b84, 0xc1823000, 0x0b820020, 0x22052141, 0x8429005d, 0x0056226d, + 0x20138439, 0x20058259, 0x0c374825, 0x97822b20, 0x33822e20, 0x4105df49, 0x2b2209b7, 0xf1823300, 0x2b822a20, 0x83054749, 0x008024fd, 0x494000ab, + 0x292006ab, 0x8306e742, 0x842b20ad, 0x84402013, 0x422d83e1, 0x5b830709, 0x20051943, 0x4a218280, 0x9b490509, 0x43152009, 0x1e2008fd, 0x20069543, + 0x0a954222, 0x1520c383, 0x20084b43, 0x205b8255, 0x22a58295, 0x82350000, 0x001e2291, 0x830f82c0, 0x20538309, 0x201182ab, 0x08d3496b, 0x21096f44, + 0xdd430000, 0x22058505, 0x820f0040, 0x821e205d, 0x84802043, 0x20b783a7, 0x0643448c, 0x20077b48, 0x08614415, 0x87431d83, 0x00552205, 0x205f8480, + 0x203d826b, 0x83c582ab, 0x822b20bf, 0x82ab2011, 0x8295200f, 0x82802003, 0x84c0201f, 0x822b2007, 0x8240205b, 0x8240200d, 0x47282055, 0x8d420a9d, + 0x0b714e05, 0xd7889520, 0x83078d4d, 0x098d4d51, 0x5a00b523, 0x85c78500, 0x208d8307, 0x4133822c, 0xd941053b, 0x07db4605, 0x4705b141, 0xef4b0903, + 0x443f8507, 0xb7430525, 0x84142007, 0x862b20df, 0x07314df5, 0x0b474f89, 0x20bf8305, 0x45298252, 0x2e220589, 0xd7825500, 0x15200283, 0x02220482, + 0x43840000, 0x00230682, 0x82ab001e, 0x82ae2001, 0x8255201f, 0x00152203, 0x2201829e, 0x824a0095, 0x2083831f, 0x2013821e, 0x4545843e, 0x91850727, + 0x5220f187, 0x03874282, 0x0b826120, 0x03827020, 0x03827f20, 0x03828e20, 0x03829d20, 0x0382ac20, 0x0382bb20, 0x0382ca20, 0x0382d920, 0x0382e820, + 0x0000f727, 0x00000601, 0x21898201, 0x07822401, 0x03823320, 0x03824220, 0x03825120, 0x03826020, 0x03826f20, 0x03827e20, 0x03828d20, 0x03829c20, + 0x0382ab20, 0x0382ba20, 0x0382c920, 0x0382d820, 0x0382e720, 0x0000f624, 0x03820502, 0x03821420, 0x03822320, 0x03823220, 0x03824120, 0x03825020, + 0x03825f20, 0x03826e20, 0x03827d20, 0x0000b723, 0x21278203, 0x07823503, 0x0000a224, 0x03820b04, 0x03825a20, 0x0000ec24, 0x03829105, 0x0000c124, + 0x03821406, 0x03823720, 0x03825920, 0x0000a424, 0x03824507, 0x0000d124, 0x03822f08, 0x03828420, 0x0000fb24, 0x03827709, 0x0000c523, 0x2567820a, + 0x0000a50a, 0x03821a0b, 0x03827c20, 0x0382d420, 0x0000fa23, 0x21c3820c, 0x0782830c, 0x03829b20, 0x0000c823, 0x2167820d, 0x0782560d, 0x0000c324, + 0x0382190e, 0x00008524, 0x0382030f, 0x03823f20, 0x0f25d782, 0x100000ce, 0x20038217, 0x2003823b, 0x20038261, 0x240382d0, 0x110000eb, 0x2303824d, + 0x120000f4, 0x1220c782, 0x12259f82, 0x130000e1, 0x20038213, 0x24038232, 0x140000b1, 0x82038207, 0xd814242f, 0x82150000, 0x89153473, 0x67160000, + 0xcd170000, 0x8f180000, 0x6d190000, 0x821a0000, 0x9d1b251b, 0x081c0000, 0xa9240382, 0x3e1d0000, 0x79200382, 0xdd200382, 0xff240382, 0x471e0000, + 0xaf240382, 0x0a1f0000, 0x51200382, 0xd7820382, 0x00212025, 0x82b42000, 0x00f92403, 0x827b2100, 0x00be2303, 0xaf822200, 0x82522221, 0x82962007, + 0x00d32403, 0x822e2300, 0x82732003, 0x00e62403, 0x82422400, 0x292f8203, 0x00005f25, 0x0000b625, 0x03821a26, 0x2621db82, 0x20078275, 0x820382a0, + 0x82262053, 0x5527256b, 0x88270000, 0xe4280382, 0x5e280000, 0x00290000, 0xe7820382, 0x00352a25, 0x828a2a00, 0x00bc2303, 0xdb822b00, 0x00b52b24, + 0x1c822c00, 0x82782c21, 0x00d42407, 0x82082d00, 0x824e2003, 0x82932003, 0x202f8203, 0x29af822e, 0x0000402f, 0x0000c22f, 0x03825030, 0x31245f82, + 0x3100000a, 0x31202382, 0x31252382, 0x320000d7, 0x20038237, 0x2403828b, 0x330000f8, 0x24038246, 0x340000b3, 0x82038242, 0xc035245b, 0x82360000, + 0x8d3621a3, 0xe3240782, 0x39370000, 0xb6200382, 0xe0240382, 0x30380000, 0xae230382, 0x82390000, 0x7f39214f, 0xed240782, 0x4d3a0000, 0xc2240382, + 0x263b0000, 0xa8240382, 0x283c0000, 0xc1240382, 0x143d0000, 0x3c200382, 0x8e200382, 0xcc240382, 0x203e0000, 0x85200382, 0xe2230382, 0x823f0000, + 0x6d3f2153, 0xca240782, 0x6b400000, 0xde240382, 0x1b410000, 0x5f200382, 0x90200382, 0xb7200382, 0xd8240382, 0x9f420000, 0xf1240382, 0x58430000, + 0xa2200382, 0xec240382, 0x23440000, 0x3d200382, 0x37820382, 0xeb824420, 0xcf824420, 0x00134525, 0x82594500, 0x240f8203, 0x00009546, 0x25af8246, + 0x0000e646, 0x03822247, 0x03825a20, 0x0000b523, 0x215f8248, 0x07827e48, 0x49201782, 0x49252b82, 0x4a0000b7, 0x20038210, 0x2403824a, 0x4b0000d1, + 0x2003822d, 0x24038278, 0x4c0000f2, 0x28038247, 0x4d000096, 0x4e000016, 0x8203825c, 0x1e4f25d7, 0x7a4f0000, 0xe1240382, 0x48500000, 0x1f820382, + 0x00085125, 0x82625100, 0x82a62003, 0x00fb2403, 0x82495200, 0x82882003, 0x00c72303, 0x43825300, 0x828f5321, 0x00f42307, 0x17825400, 0x00bd5424, + 0x4f825500, 0x827b5521, 0x00c82307, 0x7b825600, 0x82735621, 0x29d38207, 0x00004c57, 0x0000c957, 0x03824058, 0x0000a124, 0x03823e59, 0x0000db24, + 0x03823c5a, 0x5a204f82, 0x5a25fb82, 0x5b0000cd, 0x82038253, 0x1d5c297f, 0xaa5c0000, 0x385d0000, 0xfa230382, 0x825e0000, 0xdc5e2523, 0x555f0000, + 0x6e200382, 0xa0200382, 0xe5240382, 0x0d600000, 0x3f200382, 0x5d200382, 0x9f820382, 0x00416129, 0x00956100, 0x820c6200, 0x00872403, 0x82266300, + 0x82842003, 0x00dd2403, 0x82376400, 0x82942003, 0x00c52403, 0x82346500, 0x82a82003, 0x00f12803, 0x00bc6600, 0x82b16700, 0x00f82b03, 0x00c06800, + 0x006c6900, 0x97826a00, 0x009d6a25, 0x82676b00, 0x00d32303, 0xb3826c00, 0x006d6d29, 0x00b76d00, 0x82036e00, 0x824f2003, 0x829c2003, 0x253f8203, + 0x0000366f, 0x0382a96f, 0x0000f324, 0x03822e70, 0x03828020, 0x70253382, 0x710000fd, 0x2303824b, 0x720000c1, 0x7221c782, 0x20078291, 0x240382c3, + 0x730000f9, 0x20038232, 0x20038276, 0x820382ba, 0x2774250f, 0x7f740000, 0xdb240382, 0x1a750000, 0x92200382, 0xf1240382, 0x58760000, 0x9f200382, + 0xd5240382, 0x0a770000, 0x47200382, 0x73200382, 0x96240382, 0x33780000, 0x60200382, 0xa2200382, 0xcf240382, 0x25790000, 0xfb820382, 0x00b87924, + 0x37827a00, 0x82a37a21, 0x25d38207, 0x00001b7b, 0x0382527b, 0x0382ce20, 0x7c295382, 0x7c00004a, 0x7d00009a, 0x20038211, 0x23038261, 0x7e0000e8, + 0x7e211f82, 0x24078282, 0x7f0000b3, 0x82038217, 0xad7f253f, 0x01800000, 0x53200382, 0xda240382, 0x4d810000, 0xa0200382, 0xcd200382, 0xb3820382, + 0x00348225, 0x827d8200, 0x00e32403, 0x82398300, 0x252f8203, 0x00003684, 0x03828084, 0x0000d224, 0x03822885, 0x0000b423, 0x21438286, 0x07824c86, + 0x86249b82, 0x870000e6, 0x87210782, 0x200782b6, 0x230382d7, 0x880000f7, 0x88216f82, 0x23078241, 0x8900006d, 0x8921c382, 0x20078254, 0x2403828a, + 0x8a0000df, 0x20038229, 0x82038263, 0x828b2073, 0xb18b29c7, 0xf38b0000, 0x428c0000, 0x9c200382, 0xfc280382, 0x7a8d0000, 0x0f8e0000, 0x65200382, + 0xaa240382, 0x218f0000, 0x0b820382, 0x97828f20, 0x00759029, 0x00bd9000, 0x820e9100, 0x006a2303, 0x17829200, 0x82b49221, 0x00ff2407, 0x824a9300, + 0x00852303, 0x2f829400, 0x009f9425, 0x821e9500, 0x828c2003, 0x20db8203, 0x381b8296, 0x0000a396, 0x0000ca96, 0x00000097, 0x00002b98, 0x00005099, + 0x00000b9b, 0x257f829c, 0x0000159d, 0x0382499d, 0x9d25ff82, 0x9e0000dc, 0x20038229, 0x24038271, 0x9f0000d6, 0x23038231, 0xa000007f, 0xa0212b82, + 0x24078277, 0xa10000f4, 0x28038262, 0xa20000f6, 0xa3000072, 0x20038203, 0x24038264, 0xa40000fe, 0x2303824e, 0xa50000af, 0xa5211382, 0x2407827d, + 0xa60000bf, 0x82038206, 0x93a6216b, 0xd5240782, 0x1ca70000, 0x81200382, 0xc4240382, 0x1ba80000, 0x5f200382, 0xa6200382, 0xd8230382, 0x82a90000, + 0x43a9212b, 0xae200782, 0xda240382, 0x45aa0000, 0x80230382, 0x82ab0000, 0x84ab2117, 0x73820782, 0x0087ac25, 0x8224ad00, 0x00962403, 0x8210ae00, + 0x009d2403, 0x8239af00, 0x00ac2803, 0x006bb000, 0x8208b100, 0x00ba2403, 0x8207b200, 0x00832303, 0xef82b300, 0x9f82b320, 0x828ab321, 0x00eb280b, + 0x00b6b400, 0x826ab500, 0x00f02403, 0x8233b600, 0x826f2003, 0x00902403, 0x8223b700, 0x00e62703, 0x00a4b800, 0x9382b900, 0xcf82b920, 0x0089ba24, + 0xcb82bb00, 0x8252bb21, 0x00a12307, 0x2782bc00, 0x00d7bc25, 0x8249bd00, 0x25588203, 0x0000d9bd, 0x038253be, 0x0000fd24, 0x038220bf, 0x03829120, + 0xc024b782, 0xc0000029, 0xc0206f82, 0xc1241782, 0xc1000044, 0xc2209b82, 0xc2299782, 0xc200008e, 0xc30000dc, 0x2003820d, 0x82038247, 0xd5c32143, + 0xd7820782, 0x00cbc425, 0x8213c500, 0x824c2003, 0x00b22303, 0x0b82c600, 0x8278c621, 0x00bf2407, 0x8218c700, 0x28ff8203, 0x0000e5c7, 0x00009ac8, + 0x203f82c9, 0x25d382c9, 0x0000d7c9, 0x03824bca, 0x0000bc24, 0x03820ecb, 0xcb25cb82, 0xcc0000fb, 0x24038257, 0xcd0000b4, 0x2003822c, 0x2c03828b, + 0xce0000e7, 0xcf0000de, 0xd00000d0, 0x23038238, 0xd10000b9, 0xd1249782, 0xd200009f, 0xd2219782, 0x24078293, 0xd30000c4, 0x20038230, 0x24038271, + 0xd40000e0, 0x24038269, 0xd50000c9, 0x23038211, 0xd60000d1, 0xd6207782, 0xd7294782, 0xd7000051, 0xd80000e1, 0x2403827b, 0xd90000fe, 0x23038281, + 0xda0000f3, 0xdb241782, 0xdb00001f, 0xdc250f82, 0xdc000010, 0x2003825c, 0x280382a6, 0xdd0000ff, 0xde0000b6, 0x82038243, 0x6cdf294f, 0xeadf0000, + 0x48e00000, 0xc6240382, 0x2de10000, 0x73820382, 0x9382e120, 0x00f4e125, 0x8256e200, 0x256b8203, 0x000029e3, 0x03829ce3, 0x0000d528, 0x000026e4, + 0x038205e5, 0x03826320, 0xe628eb82, 0xe6000068, 0xe70000fd, 0xe7256b82, 0xe80000d3, 0x2003821b, 0x820382a9, 0x59e9289f, 0xd8e90000, 0x82ea0000, + 0x82ea20fb, 0x82ea20c3, 0x82eb2057, 0x5beb29c3, 0xceeb0000, 0x18ec0000, 0x76200382, 0xcf240382, 0x3bed0000, 0xb7240382, 0x45ee0000, 0xaa200382, + 0xf6240382, 0x6def0000, 0x90200382, 0xe9240382, 0x38f00000, 0x93200382, 0xec240382, 0x55f10000, 0x8f820382, 0x00c2f125, 0x8296f200, 0x00ff2403, + 0x8254f300, 0x248f8203, 0x0000ddf3, 0x20cf82f4, 0x248382f4, 0x0000fbf4, 0x293382f5, 0x0000f8f5, 0x000099f6, 0x038227f7, 0x0000a324, 0x038232f8, + 0x0382a620, 0x0000de23, 0x254b82f9, 0x000024fa, 0x03827dfa, 0x0382bd20, 0x0000e224, 0x03825afb, 0x03829220, 0x0000d623, 0x258382fc, 0x0000dcfc, + 0x038206fd, 0x03821d20, 0x03824a20, 0x03826120, 0x03828b20, 0x0382d520, 0x0000f724, 0x038219fe, 0x03823a20, 0x03826e20, 0x03829020, 0x0382b220, + 0x0000fa24, 0x038244ff, 0xff25df82, 0x000100c5, 0x20038213, 0x20038264, 0x2003829b, 0x240382d0, 0x010100f9, 0x20038225, 0x20038251, 0x2003827b, + 0x200382a9, 0x240382d7, 0x020100ef, 0x20038205, 0x20038226, 0x82038246, 0x3903253b, 0x8c030100, 0xdd240382, 0x35040100, 0xbb240382, 0x24050100, + 0xa0240382, 0x0c060100, 0x67200382, 0xaa240382, 0x23070100, 0x9d240382, 0x3f080100, 0xb7240382, 0x47090100, 0xe7240382, 0x690a0100, 0x07820382, + 0x003b0b25, 0x82860b01, 0x00da2303, 0x7b820c01, 0x00830c25, 0x82170d01, 0x82922003, 0x00e92403, 0x82630e01, 0x29078203, 0x01005b0f, 0x0100a20f, + 0x03826b10, 0x0100c924, 0x03824111, 0x03828020, 0x0100e424, 0x03823e12, 0x0100a024, 0x03823813, 0x0100b324, 0x03822914, 0x03829020, 0x0100eb24, + 0x03823a15, 0x03827920, 0x0100fb24, 0x03824e16, 0x1729bb82, 0x17010056, 0x180100c3, 0x20038240, 0x200382a3, 0x240382d1, 0x190100ff, 0x82038259, + 0x4c1a250b, 0xbd1a0100, 0xfd240382, 0x511b0100, 0xa4200382, 0xf7240382, 0x1d1c0100, 0xd2240382, 0x7d1d0100, 0xed230382, 0x821e0100, 0x341f28df, + 0xac1f0100, 0x82200100, 0x772021e7, 0xdd230782, 0x82210100, 0xd8212547, 0x45220100, 0xb1230382, 0x82230100, 0x82232083, 0x6124252b, 0x98240100, + 0x97820382, 0x00532525, 0x828e2501, 0x00e62403, 0x82602601, 0x00952403, 0x82072701, 0x20df8203, 0x20ab8227, 0x25078228, 0x0100f428, 0x03827529, + 0x0100ec24, 0x0382522a, 0x0100b824, 0x0382032b, 0x03824a20, 0x03828320, 0x2b248b82, 0x2c0100ff, 0x2d24c782, 0x2d010017, 0x2d257782, 0x2e0100a5, + 0x82038213, 0xcc2e2537, 0x6e2f0100, 0xd5240382, 0x47300100, 0xb3820382, 0xfb823120, 0x00f13124, 0x93823201, 0x829f3221, 0x25d78207, 0x01007733, + 0x03820034, 0x03827420, 0x0100e524, 0x03825435, 0x0100c424, 0x03822136, 0x36211382, 0x240782ba, 0x370100e7, 0x23038224, 0x380100bf, 0x38215f82, + 0x20078270, 0x82038296, 0x30392563, 0x76390100, 0xab200382, 0xfe240382, 0x383a0100, 0x79200382, 0xcf240382, 0x5b3b0100, 0x7d200382, 0xbd240382, + 0x1c3c0100, 0x81200382, 0xc9240382, 0x463d0100, 0xc1240382, 0x053e0100, 0x8c200382, 0xd7240382, 0x3e3f0100, 0xb0240382, 0x6c400100, 0xfd240382, + 0x2a410100, 0x57200382, 0xbe240382, 0x26420100, 0x86200382, 0x87820382, 0x000e4324, 0x17824301, 0x4b824320, 0x00f44325, 0x822f4401, 0x827f2003, + 0x00d92403, 0x821d4501, 0x82512003, 0x00942403, 0x82684601, 0x253b8203, 0x01001247, 0x03828547, 0x48249b82, 0x4901007d, 0x4921eb82, 0x20078248, + 0x820382a4, 0x824a2013, 0xad4a25ef, 0x204b0100, 0x73200382, 0xf8280382, 0x6b4c0100, 0x614d0100, 0xbb240382, 0x234e0100, 0x8a200382, 0xfb240382, + 0x364f0100, 0x89200382, 0xc2240382, 0x18500100, 0xf7820382, 0x00c45025, 0x82195101, 0x009c2403, 0x825d5201, 0x828d2003, 0x00ee2403, 0x823d5301, + 0x828b2003, 0x00e12703, 0x00a55401, 0x1f825501, 0xd7825520, 0x00655629, 0x00c95601, 0x824d5701, 0x29838203, 0x01001c58, 0x0100db58, 0x03829a59, + 0x0100ed28, 0x01009d5a, 0x0382105b, 0x01009324, 0x0382055c, 0x5d254382, 0x5d010002, 0x24038256, 0x5e0100c6, 0x24038234, 0x5f0100b8, 0x20038230, + 0x24038275, 0x600100b9, 0x20038200, 0x8203823b, 0xd660254f, 0x08610100, 0x4f200382, 0xd7820382, 0x00f66129, 0x00bf6201, 0x823e6301, 0x82942003, + 0x00eb2403, 0x82776401, 0x00ca2403, 0x822b6501, 0x00862403, 0x821e6601, 0x211b8203, 0x0782c366, 0x0100e524, 0x03821467, 0x03824120, 0x03827e20, + 0x0100bb24, 0x03821a68, 0x03824e20, 0x03827d20, 0x0100b324, 0x03820369, 0x03824220, 0x03829120, 0x6a29df82, 0x6a01001f, 0x6b01007c, 0x23038204, + 0x6c01005b, 0x6c250782, 0x6d0100c5, 0x20038221, 0x820382a0, 0x5f6e2583, 0x856e0100, 0x0b820382, 0x006c6f28, 0x00ab6f01, 0x77827001, 0x82807021, + 0x25138207, 0x01004971, 0x03829871, 0x72259f82, 0x72010029, 0x24038289, 0x730100cc, 0x2003820e, 0x8203826e, 0x8f752423, 0x82750100, 0x507629df, + 0xa1760100, 0x40770100, 0xc0240382, 0x56780100, 0x2f820382, 0x00fd7824, 0x67827901, 0xb3827920, 0x003d7a24, 0x93827a01, 0x00057b29, 0x00547b01, + 0x82327c01, 0x827a2003, 0x00e32303, 0xc7827d01, 0x00fa7d29, 0x00907e01, 0x82087f01, 0x823c2003, 0x00b72803, 0x002c8001, 0x82018101, 0x008e2303, + 0xc3828201, 0x82718221, 0x256f8207, 0x01002683, 0x03827483, 0x0382be20, 0x0100f824, 0x03821284, 0x03822b20, 0x03825e20, 0x0100a423, 0x210b8285, + 0x07828285, 0x0382b420, 0x0100dd24, 0x03823086, 0x0100c324, 0x03820687, 0x03824720, 0x8725b782, 0x880100d8, 0x24038219, 0x8901005b, 0x8203822e, + 0x828920c3, 0x1f8a25a7, 0xb08a0100, 0xe2230382, 0x828b0100, 0x658b250b, 0x008c0100, 0x32200382, 0x9c200382, 0xea230382, 0x828d0100, 0x768d210b, + 0xcf280782, 0x668e0100, 0x2f8f0100, 0xd5270382, 0x9b900100, 0x82910100, 0x1192314f, 0xd1920100, 0xa2930100, 0x52940100, 0x25950100, 0xf7240382, + 0x5a960100, 0x77820382, 0x00c29731, 0x00899801, 0x00709901, 0x00519a01, 0x82289b01, 0x00ac2803, 0x004a9c01, 0x82029d01, 0x007f2403, 0x82179e01, + 0x00c82403, 0x82569f01, 0x00fd2803, 0x007aa001, 0x8213a101, 0x00c42303, 0x5382a201, 0x00fca224, 0xff82a301, 0xeb82a420, 0xe782a420, 0x0055a52d, + 0x00e5a501, 0x0090a601, 0x8254a701, 0x25bf8203, 0x01008ba8, 0x03824da9, 0x01008a23, 0x21fb82aa, 0x078288aa, 0x0100e323, 0x258782ab, 0x0100b6ab, + 0x03821eac, 0x03825620, 0x0100a923, 0x207382ad, 0x20db82ad, 0x208f82ae, 0x292b82af, 0x01008caf, 0x0100d6af, 0x038220b0, 0x03829220, 0x0100f624, + 0x038243b1, 0x0382a520, 0x0100e924, 0x03822eb3, 0x03825d20, 0x0100ca24, 0x038231b4, 0x0382a620, 0x0100cc23, 0x21bf82b5, 0x078247b5, 0xb520cf82, + 0xb6293382, 0xb6010063, 0xb70100d1, 0x24038216, 0xb801009f, 0x24038214, 0xb9010060, 0x2403820d, 0xba010094, 0x20038207, 0x23038283, 0xbb0100dc, + 0xbb24ab82, 0xbc0100c2, 0xbd244b82, 0xbd010005, 0xbd252782, 0xbe0100ae, 0x20038216, 0x24038290, 0xbf0100e4, 0x2403824b, 0xc00100f2, 0x2403821c, + 0xc1010091, 0x2403820c, 0xc2010059, 0x24038215, 0xc301009c, 0x20038219, 0x2403826c, 0xc40100f1, 0x20038276, 0x280382b8, 0xc50100fa, 0xc60100a3, + 0x24038201, 0xc70100c4, 0x2003820b, 0x2003824c, 0x230382a0, 0xc80100ef, 0xc821f382, 0x23078286, 0xc90100e1, 0xc920cb82, 0xca2d3382, 0xca01004a, + 0xcb0100bf, 0xcc010033, 0x82038218, 0xb6cc250f, 0x2fcd0100, 0x58200382, 0xc9230382, 0x82ce0100, 0xc6ce24eb, 0x82cf0100, 0x8dcf2d1f, 0xcfd00100, + 0x25d10100, 0x2cd20100, 0xfb820382, 0x8782d320, 0xb382d320, 0x0046d42c, 0x00c0d401, 0x0050d501, 0x7b82d601, 0x006bd625, 0x8200d701, 0x825c2003, + 0x00f82403, 0x8277d801, 0x00ea2303, 0x9382d901, 0x00c1d928, 0x007cda01, 0xf382db01, 0x008cdb25, 0x8239dc01, 0x00c42803, 0x00d1dd01, 0x821dde01, + 0x82692003, 0x00e82403, 0x8279df01, 0x24e38203, 0x010095e0, 0x20a382e1, 0x252b82e1, 0x010024e2, 0x038266e2, 0x0100ca27, 0x010044e3, 0x251782e4, + 0x0100a1e4, 0x038205e5, 0x03823720, 0x0100a724, 0x038203e7, 0x0382b420, 0x0100ff2c, 0x0100b6e8, 0x01005fe9, 0x038215ea, 0x0382ab20, 0x0100f228, + 0x0100aceb, 0x038264ec, 0x0382bb20, 0x0100e623, 0x29eb82ed, 0x01000eee, 0x0100c2ee, 0x038259ef, 0x03829020, 0xf029db82, 0xf001006f, 0xf10100e4, + 0x24038272, 0xf20100e9, 0x24038223, 0xf30100a4, 0x24038232, 0xf40100bc, 0x2703821f, 0xf5010096, 0xf601003e, 0xf625c382, 0xf70100c5, 0x82038228, + 0xc8f72db7, 0xa5f80100, 0x0df90100, 0x6efa0100, 0xb7240382, 0x5cfb0100, 0xfa230382, 0x82fc0100, 0x82fc208f, 0xe6fc288b, 0xc6fd0100, 0x82fe0100, + 0x81fe214f, 0xe5230782, 0x82ff0100, 0xb9ff258b, 0x45000200, 0xbe280382, 0x7a010200, 0x09030200, 0xac240382, 0x11040200, 0xb5280382, 0xaf050200, + 0x1a060200, 0x1f820382, 0x003a0725, 0x824d0802, 0x00cc2403, 0x82550902, 0x00dd2403, 0x82370a02, 0x00d92403, 0x82350b02, 0x82832003, 0x00e42803, + 0x007f0c02, 0x821d0d02, 0x00872403, 0x820f0e02, 0x00aa2403, 0x82540f02, 0x29078203, 0x02002010, 0x0200c210, 0x03820611, 0x02007223, 0x29238212, + 0x02004313, 0x0200bd13, 0x03821414, 0x02009e24, 0x03823815, 0x0200db24, 0x03822116, 0x0200cd24, 0x03822217, 0x03829d20, 0x0200de24, 0x03827d18, + 0x0200b724, 0x03825c19, 0x0200a023, 0x2577821a, 0x0200a11a, 0x03820e1b, 0x0200bc30, 0x02004f1c, 0x0200b81d, 0x02005d1e, 0x0382701f, 0x2025ab82, + 0x2102001b, 0x82038215, 0xa721243b, 0x82220200, 0x2c23249b, 0x82230200, 0x822420bf, 0x81252993, 0x61260200, 0x1c270200, 0x0f820382, 0x00ea2925, + 0x82502a02, 0x00e22b03, 0x00d72b02, 0x00442c02, 0x33822d02, 0x00da2d25, 0x82312e02, 0x29ab8203, 0x0200492f, 0x0200eb2f, 0x03824b30, 0x0200a924, + 0x03820131, 0x32207382, 0x32318782, 0x330200a6, 0x340200af, 0x350200ab, 0x36020058, 0x2803821a, 0x370200bb, 0x380200c9, 0x2003823b, 0x20038255, + 0x2303828d, 0x390200e5, 0x39255782, 0x3a02006b, 0x2403821e, 0x3b020077, 0x23038240, 0x3c0200ef, 0x3c257f82, 0x3d02008e, 0x8203829c, 0x823e250f, + 0x383f0200, 0xab820382, 0x00e73f25, 0x82454002, 0x00b52403, 0x82274102, 0x316b8203, 0x02006d42, 0x0200e142, 0x02008c43, 0x02002244, 0x03823945, + 0x47206382, 0x4725e782, 0x480200dc, 0x8203822f, 0x884929af, 0x644a0200, 0x254b0200, 0xff280382, 0xac4c0200, 0x494d0200, 0x85200382, 0xfb240382, + 0x5b4e0200, 0xc3240382, 0x244f0200, 0x8f820382, 0x002a5029, 0x00945002, 0x82155102, 0x00b82703, 0x00755202, 0xab825302, 0x82475321, 0x826c2007, + 0x00902403, 0x824b5402, 0x00a22403, 0x82915502, 0x29e78203, 0x02002956, 0x02009e56, 0x03823c57, 0x03829320, 0x0200e924, 0x03824258, 0x0200bc23, + 0x25038259, 0x0200585a, 0x0382125b, 0x0200c924, 0x0382445c, 0x5d28bf82, 0x5d02001a, 0x5e0200cb, 0x5f208782, 0x5f256382, 0x600200d7, 0x2403826b, + 0x610200fc, 0x28038231, 0x630200cd, 0x64020082, 0x28038235, 0x65020080, 0x6602009b, 0x27038240, 0x670200a1, 0x68020045, 0x6821e782, 0x2307826e, + 0x690200ae, 0x69240f82, 0x6a0200ca, 0x6a250782, 0x6b020087, 0x23038246, 0x6c0200a4, 0x6c256382, 0x6d0200c4, 0x2803820e, 0x6e0200c7, 0x6f020064, + 0x20038219, 0x23038263, 0x700200cc, 0x70250782, 0x710200f2, 0x20038209, 0x28038244, 0x720200f1, 0x73020049, 0x2003827b, 0x230382cf, 0x740200f8, + 0x7421fb82, 0x24078243, 0x750200fd, 0x20038259, 0x24038286, 0x760200d9, 0x24038226, 0x770200d1, 0x82038234, 0x07782993, 0xdb780200, 0xbe790200, + 0xed240382, 0x1c7a0200, 0x4f200382, 0xf92c0382, 0x947b0200, 0xb87c0200, 0x157d0200, 0x69200382, 0xb3820382, 0x00927e25, 0x820f7f02, 0x823a2003, + 0x009a2403, 0x82a38002, 0x00de2803, 0x00c08102, 0x82088202, 0x82302003, 0x200f8203, 0x20a38283, 0x25db8283, 0x02001484, 0x03829184, 0x0200ef28, + 0x02001e85, 0x03823d86, 0x0200e834, 0x0200b587, 0x02008288, 0x0200e58a, 0x0200978b, 0x0382328c, 0x0200e62c, 0x0200f48d, 0x0200718f, 0x03822690, + 0x02007f27, 0x02007d91, 0x21438292, 0x07828f92, 0x9325b782, 0x9402003e, 0x2803822c, 0x950200c1, 0x9602009b, 0x8203820b, 0x399724a3, 0x82970200, + 0x23982523, 0x9d980200, 0xdc230382, 0x82990200, 0x829920f7, 0xc299217b, 0xf6240b82, 0x299a0200, 0x62200382, 0xd7820382, 0x00c49a24, 0x03829b02, + 0x00739c25, 0x82a59c02, 0x00e32803, 0x006d9d02, 0x82119e02, 0x008d2403, 0x820a9f02, 0x826b2003, 0x25ab8203, 0x02007aa0, 0x038221a1, 0x02007424, + 0x03822fa2, 0x0200e924, 0x038260a3, 0x0382bb20, 0x0200dd23, 0x20bf82a4, 0x20db82a5, 0x251b82a6, 0x020089a6, 0x038230a7, 0x0200d028, 0x020063a8, + 0x03820da9, 0x03829a20, 0x0200f12c, 0x0200c7aa, 0x020084ab, 0x038202ac, 0x03826820, 0xad29b782, 0xad020017, 0xae0200cc, 0x27038272, 0xaf0200ed, + 0xb00200a1, 0xb0206b82, 0xb1290782, 0xb102004b, 0xb20200a6, 0x8203822a, 0x82b3203b, 0x82b4203b, 0xebb424e7, 0x82b50200, 0x04b62967, 0xa7b60200, + 0x4ab70200, 0xc3240382, 0x48b80200, 0xbd240382, 0x09b90200, 0xb5200382, 0x73820382, 0x002dba25, 0x827eba02, 0x25df8203, 0x02000fbb, 0x03823ebb, + 0x02009d24, 0x038256bc, 0x02007f28, 0x020036bd, 0x038208be, 0x03827820, 0x0200d228, 0x020041bf, 0x03820dc0, 0x03826a20, 0x0382ae20, 0x0200fb27, + 0x02009ec1, 0x212382c2, 0x078251c2, 0x0382a320, 0x0200e628, 0x0200d0c3, 0x038229c4, 0x03827020, 0xc524c782, 0xc502000c, 0xc5252782, 0xc60200f2, + 0x2003821b, 0x2303825f, 0xc70200c4, 0xc8204382, 0xc9253382, 0xca020094, 0x2303825d, 0xcb0200c0, 0xcb25d782, 0xcc020098, 0x24038226, 0xcd02007a, + 0x24038217, 0xce02008a, 0x2303820e, 0xcf020078, 0xd2290782, 0xd2020005, 0xd3020079, 0x2303825a, 0xd40200a4, 0xd425d382, 0xd50200fa, 0x2403828d, + 0xd60200dc, 0x23038265, 0xd70200e2, 0xd721cf82, 0x20078280, 0x820382b9, 0x3fd8297b, 0xdfd80200, 0x72d90200, 0xf7280382, 0xdada0200, 0x43db0200, + 0xcd230382, 0x82dc0200, 0xc6dc2597, 0x5cdd0200, 0xf3280382, 0x49de0200, 0x1adf0200, 0xca230382, 0x82e10200, 0x82e1206f, 0xe0e1259f, 0x07e30200, + 0x53200382, 0xde2c0382, 0xbde40200, 0x89e50200, 0x1ee60200, 0x86240382, 0x23e70200, 0xea270382, 0x27e80200, 0x82e90200, 0xc3e9253f, 0x4aea0200, + 0x57820382, 0x0016eb25, 0x828beb02, 0x25738203, 0x02008cec, 0x038233ed, 0x0200ba24, 0x03821dee, 0x03826820, 0x0200be23, 0x212382ef, 0x07826eef, + 0x0200cc2c, 0x020055f0, 0x02002af1, 0x038210f2, 0x03827b20, 0x0200b324, 0x03829ff3, 0x0200db24, 0x03821ff4, 0x03827120, 0xf4255f82, 0xf50200ee, + 0x20038231, 0x24038275, 0xf60200bc, 0x2403825f, 0xf70200a3, 0x28038214, 0xf80200d6, 0xf902008d, 0x82038208, 0x0afa29ab, 0x57fa0200, 0x49fb0200, + 0xe3240382, 0x39fc0200, 0x91200382, 0xe9240382, 0x3bfd0200, 0xcd240382, 0x41fe0200, 0xe8280382, 0x7dff0200, 0x02000300, 0xd1240382, 0x20010300, + 0xae240382, 0x38020300, 0x62200382, 0xb5240382, 0x3f030300, 0x9b240382, 0x10040300, 0x51240382, 0x2c060300, 0x8e2c0382, 0x5c070300, 0x37080300, + 0x1b090300, 0x43820382, 0x000a0a25, 0x82050b03, 0x00872403, 0x82580e03, 0x00cd2403, 0x82600f03, 0x00a72403, 0x822d1003, 0x828c2003, 0x00ed2803, + 0x00921103, 0x82451203, 0x296f8203, 0x03006d13, 0x0300af13, 0x03821914, 0x0300be34, 0x03004615, 0x03005a16, 0x03005d17, 0x0300c818, 0x03821f19, + 0x0300a627, 0x0300171a, 0x2523821b, 0x0300851b, 0x03820b1c, 0x03008f24, 0x03823e1d, 0x0300b323, 0x297b821e, 0x0300c61e, 0x0300931f, 0x03824720, + 0x0300e430, 0x0300e721, 0x0300bc22, 0x03009623, 0x03822724, 0x0300f22c, 0x0300fd25, 0x03009a26, 0x03821a27, 0x03827720, 0x0300c524, 0x03821328, + 0x0300b223, 0x21bb8229, 0x07825929, 0x0382a020, 0x0300dc28, 0x0300692a, 0x03820c2b, 0x03826f20, 0x0300e624, 0x0382612c, 0x0382a420, 0x0300f728, + 0x0300eb2d, 0x0382672e, 0x0300e228, 0x0300672f, 0x03822930, 0x03826820, 0x0300cb24, 0x03825e31, 0x0382ae20, 0x0300fb23, 0x25cb8232, 0x0300e832, + 0x03827833, 0x0300c328, 0x0300a834, 0x03822035, 0x03827a20, 0x0300ba24, 0x03823f36, 0x0300c724, 0x03828b37, 0x0300d828, 0x03009138, 0x03826239, + 0x0300f32c, 0x0300e53a, 0x0300873b, 0x0382053c, 0x03008328, 0x03003d3d, 0x0382343e, 0x03826d20, 0x0300ec2b, 0x0300d03f, 0x03001f40, 0x25b38241, + 0x03009b41, 0x03822e42, 0x03826320, 0x0300ce24, 0x03823f43, 0x44248b82, 0x45030073, 0x45212382, 0x240782a9, 0x460300fa, 0x24038237, 0x470300ee, + 0x23038249, 0x480300c9, 0x48251b82, 0x4903007c, 0x28038204, 0x4a030082, 0x4b030093, 0x28038221, 0x4c0300cb, 0x4d0300b4, 0x08038289, 0x0300fe20, + 0x03007b4e, 0x0300bc4f, 0x03006e50, 0x0300d551, 0x03007053, 0x0300a054, 0x0300b355, 0x03824d56, 0x5739bb82, 0x58030066, 0x59030033, 0x5a030039, + 0x5b0300da, 0x5c030027, 0x5d030047, 0x23038229, 0x5e03006f, 0x5e206382, 0x5f20f782, 0x602cff82, 0x60030003, 0x610300b1, 0x630300f4, 0x65244b82, + 0x660300a5, 0x67283b82, 0x6703000c, 0x68030085, 0x692d1f82, 0x6a03000b, 0x6b0300b9, 0x6c0300e9, 0x2003823c, 0x82038290, 0x6c6d258b, 0x1d6e0300, + 0x0f820382, 0x4b826f20, 0x00f06f24, 0x57827003, 0x00e77025, 0x825d7103, 0x00f52303, 0x43827203, 0x00d47225, 0x82197303, 0x00522403, 0x821e7403, + 0x82602003, 0x00db2403, 0x82627503, 0x00bd2303, 0x9f827603, 0x829f7621, 0x25cf8207, 0x03000a77, 0x03823f77, 0x03827320, 0x0300c124, 0x03822478, + 0x0300ae24, 0x03825579, 0x7a252b82, 0x7a03001a, 0x2803826a, 0x7b0300ca, 0x7c0300ab, 0x23038268, 0x7d0300e2, 0x7e251b82, 0x7f030051, 0x24038276, + 0x800300a4, 0x20038267, 0x8203829e, 0x258129ff, 0xb7810300, 0xdc820300, 0xfd240382, 0x2b830300, 0xde240382, 0x6b840300, 0xe1240382, 0x17850300, + 0x6e200382, 0xf9230382, 0x82860300, 0xb38621b7, 0xbb820782, 0x00278724, 0xcf828703, 0x97828720, 0x0096882d, 0x00868903, 0x005e8a03, 0x82368b03, + 0x009b2403, 0x824a8c03, 0x00eb2403, 0x82468d03, 0x82902003, 0x204b8203, 0x2983828e, 0x0300b88e, 0x0300d88e, 0x0382188f, 0x03823820, 0x0300ec23, + 0x258f8290, 0x03008290, 0x0382a391, 0x0300be24, 0x03824e92, 0x03009d24, 0x03823093, 0x03007e24, 0x03820f94, 0x03825f20, 0x0300f024, 0x03824095, + 0x0300dc24, 0x03827996, 0x0300e624, 0x03826c97, 0x0300c023, 0x28238298, 0x03001f99, 0x0300bc9a, 0x2533829b, 0x03002a9c, 0x0382a29c, 0x0300f224, + 0x03824f9d, 0x9e24f782, 0x9e03001b, 0x9f298b82, 0x9f030021, 0xa00300be, 0x20038202, 0x24038266, 0xa10300ca, 0x8203822e, 0x82a22097, 0x82a320bb, + 0xbda3254b, 0x1ea40300, 0x83240382, 0x60a50300, 0xd0240382, 0x78a60300, 0xc7230382, 0x82a70300, 0xcda725db, 0x41a80300, 0xbf240382, 0x2ba90300, + 0xa1230382, 0x82aa0300, 0x6faa215f, 0xff240782, 0x9fab0300, 0xe0230382, 0x82ac0300, 0xd2ac249f, 0x82ad0300, 0x9cad212b, 0xf7300782, 0x64ae0300, + 0x94af0300, 0x81b00300, 0x0cb10300, 0x33200382, 0x66200382, 0xa5280382, 0x8bb20300, 0x16b30300, 0x6a200382, 0xbc230382, 0x82b40300, 0x97b4218b, + 0xd7240782, 0x2fb50300, 0x65200382, 0xa6200382, 0xfb820382, 0x007cb625, 0x825eb703, 0x24b78203, 0x030053b8, 0x210f82b8, 0x0782afb8, 0x0300e324, + 0x038221b9, 0xb921b782, 0x8207828f, 0x82ba20a3, 0x82ba2053, 0xb3ba258b, 0x30bb0300, 0xc8240382, 0x52bc0300, 0xd3280382, 0x28bd0300, 0x0abe0300, + 0x0f820382, 0x00b6be29, 0x0092bf03, 0x8264c003, 0x00dc2303, 0x2b82c103, 0x007dc229, 0x0067c303, 0x823bc403, 0x82862003, 0x00d12303, 0xeb82c503, + 0x8265c521, 0x296f8207, 0x0300f9c5, 0x030043c6, 0x038234c7, 0xc9203382, 0xc9297b82, 0xc9030082, 0xca0300cf, 0x28038222, 0xcb030076, 0xcc030001, + 0x8203821d, 0x56cc2123, 0xd4270782, 0xd3cd0300, 0x82ce0300, 0x40ce2147, 0x90230782, 0x82cf0300, 0x88d031f3, 0xfbd00300, 0x9bd10300, 0x91d20300, + 0x18d30300, 0xdf270382, 0x92d40300, 0x83d50300, 0x00cc2403, 0x823cd603, 0x00952403, 0x8245d703, 0x00e12803, 0x0087d803, 0x822dd903, 0x00b52403, + 0x827fda03, 0x00eb2403, 0x825adb03, 0x008d2403, 0x822edc03, 0x00d52803, 0x009add03, 0x8216de03, 0x829d2003, 0x00ec2303, 0x8b82df03, 0x827bdf21, + 0x00f52307, 0x0782e003, 0x0000e129, 0x00c3e103, 0x8257e203, 0x00f82303, 0x2782e303, 0x000be429, 0x00bde403, 0x8227e503, 0x82972003, 0x00e72403, + 0x822fe603, 0x00fd2403, 0x828ee703, 0x00bf2803, 0x0011e803, 0x8210e903, 0x00942803, 0x00acea03, 0x829feb03, 0x00de2c03, 0x00c9ec03, 0x00beed03, + 0x824eee03, 0x82a02003, 0x00f22403, 0x8244ef03, 0x00c12403, 0x8261f003, 0x00c52f03, 0x009df103, 0x0054f203, 0x004bf303, 0x6b82f403, 0x0086f425, + 0x8226f503, 0x829e2003, 0x00c42703, 0x007af603, 0x5f82f703, 0x00bdf730, 0x001bf903, 0x0006fb03, 0x001cfc03, 0x8382fd03, 0x00fafd29, 0x00dcfe03, + 0x82100304, 0x00d42403, 0x82260504, 0x00ec2803, 0x00d00604, 0x821e0704, 0x825b2003, 0x00a72403, 0x820d0804, 0x009d2403, 0x82190904, 0x00d12403, + 0x822f0a04, 0x828d2003, 0x00dd2403, 0x82470b04, 0x00ad2403, 0x82140c04, 0x827c2003, 0x00c32803, 0x00ac0d04, 0x82440e04, 0x00f12303, 0x37820f04, + 0x00671029, 0x00c51004, 0x821b1104, 0x00912703, 0x00721204, 0x5b821304, 0x00211429, 0x00a11404, 0x82040000, 0x00032403, 0x82982600, 0x250b8307, + 0x00030024, 0x0f830001, 0x0a000322, 0x24221382, 0x05820c00, 0x74260022, 0x00230583, 0x82330300, 0x82302007, 0x82392003, 0x82032003, 0x865f2003, + 0x820d2003, 0x82612007, 0x827a2003, 0x000e2303, 0x0682e000, 0x4f83e020, 0x0b822820, 0xe0204782, 0x06210382, 0x200b8210, 0x2103850b, 0x0782e506, + 0x03850c20, 0x820e0621, 0x203f8207, 0x200382e0, 0x21278206, 0x0f820fe0, 0x06210382, 0x83078209, 0x21038233, 0x0b820b06, 0x03851120, 0x820d0621, + 0x85142007, 0x0f062103, 0x15200782, 0x06210385, 0x2007820c, 0x21038519, 0x07822d00, 0x03821b20, 0x88822120, 0x07822e20, 0x03822320, 0x0b822420, + 0x07823520, 0x2c209383, 0x37200b82, 0x2e200b82, 0x31200382, 0x3c200b82, 0x33200782, 0xd7830382, 0x07824020, 0x03823b20, 0x17825320, 0x07824720, + 0x03825520, 0x6020ff83, 0x75200782, 0x76230382, 0x83060000, 0x8289208b, 0x2103820b, 0x0782a307, 0x0382af20, 0x2f82bc20, 0x07828020, 0x0382be20, + 0x0b82bf20, 0x07828e20, 0x0382c320, 0x0b82c420, 0x07829020, 0x0382c620, 0x0b82f020, 0x00009224, 0x038538e1, 0x825d0721, 0x853e2007, 0x99072103, + 0x45200782, 0x79200382, 0xbd202382, 0x90200782, 0x95200382, 0xf2200b82, 0x1b830782, 0x08210382, 0x200b825c, 0x2103859c, 0x0782f800, 0x03859e20, + 0x82b30621, 0x85a02007, 0xe2062103, 0xa1200782, 0x06200385, 0xe121af82, 0x820b82a2, 0x94062103, 0xa3200782, 0x93820382, 0x82f90021, 0x85c42007, + 0x97062103, 0xc5200782, 0x06200385, 0xe121eb82, 0x820b82c6, 0xdd062103, 0xc8200782, 0x01210385, 0x2007821a, 0x200385ca, 0x20978306, 0x820b82cb, + 0xc2062103, 0xcc200782, 0x06210385, 0x200782a8, 0x240382cd, 0x010000d0, 0x2007821b, 0x210385d1, 0x07829d06, 0x0385d220, 0xef830820, 0x0b82d320, + 0x06210382, 0x2007821d, 0x210385d5, 0x07826f06, 0x0382d820, 0x3b82db20, 0x07821f20, 0x0382e020, 0x0b82e220, 0x07822320, 0x0385eb20, 0x822d0721, + 0x00fe2407, 0x8202e200, 0x82262017, 0x20038307, 0x200b826c, 0x200b822b, 0x21038586, 0x07826008, 0x0382bc20, 0x1782c420, 0x07827220, 0x0382c620, + 0x0b82c920, 0x07827b20, 0xe220a782, 0x01210382, 0x820b827f, 0x82e22067, 0x82062003, 0xe6e22197, 0x03820f82, 0xbb820620, 0x82e7e221, 0x2103820b, + 0x07823506, 0x0385ea20, 0x82210621, 0x20838207, 0x210382e2, 0x0b82a906, 0x0385ec20, 0x00380625, 0x8207e300, 0x82082003, 0x8280205f, 0x820a2007, + 0x82182003, 0x8282200b, 0x821a2007, 0x823a2003, 0x8291200b, 0x85992007, 0xe4062103, 0x9d200782, 0xe0200382, 0xb2201782, 0xe2200782, 0xee200382, + 0x2905df65, 0x0000f1e3, 0x000013e4, 0x07820302, 0x03821520, 0x0b822e20, 0xe421df82, 0x200b8230, 0x820b8240, 0xcae42103, 0x03820b82, 0x82460821, + 0x85d92007, 0x47082103, 0x97820782, 0x0382e420, 0x82930721, 0x85f3200b, 0xe8062103, 0xf4200782, 0x06210385, 0x200782ea, 0x210385f5, 0x0782ef06, + 0x0385f620, 0x82f90621, 0x85f72007, 0x0d072103, 0xf8200782, 0x06210385, 0x830782e9, 0x2103821b, 0x0b82f106, 0x0385fa20, 0x820b0721, 0x85fb2007, + 0xe6062103, 0xfc200782, 0x06210385, 0x200782fe, 0x210385fd, 0x07820107, 0x03820f83, 0x82f00621, 0x85ff200b, 0xec062503, 0x00e50000, 0x07210385, + 0x8207820c, 0x82e52027, 0x82062003, 0x02e5217f, 0x03820f82, 0x82000721, 0x85032007, 0x08072103, 0x03860782, 0x82e70621, 0x8509200b, 0xed062103, + 0x0a200782, 0xaf820382, 0x82f20621, 0x850e2007, 0xf8062103, 0x0f200782, 0x10240382, 0xfa060000, 0x11200782, 0x13240382, 0x05070000, 0x14200782, + 0x15200382, 0x43830b82, 0x0b821820, 0x06210382, 0x200782f6, 0x2103851c, 0x0782eb06, 0x03851d20, 0xaf820620, 0x821ee521, 0x001f240b, 0x82020700, + 0x85202007, 0xfd062103, 0x21200782, 0x06210385, 0x200782fc, 0x21038524, 0x07820407, 0x03852520, 0x82ee0621, 0x822d2007, 0x00362403, 0x82510200, + 0x82392007, 0x827d2003, 0x825b200b, 0x85832007, 0x1d072103, 0x84200782, 0x07210385, 0x2007821c, 0x21038585, 0x07821607, 0x03858620, 0x67830720, + 0x0b828720, 0x00008824, 0x07821707, 0x03858920, 0x82150721, 0x858a2007, 0x1b072103, 0x8b200782, 0x07210385, 0x2007821a, 0x2003828c, 0x202f828d, + 0x2007821f, 0x2103858e, 0x07821e07, 0x03858f20, 0x82100721, 0x85902007, 0x19072103, 0x91200782, 0x07210385, 0x20078214, 0x21038595, 0x07822207, + 0x03829820, 0x00009a24, 0x07821107, 0x0382c320, 0xbf82e120, 0x0782a020, 0x0385fa20, 0x00230725, 0x8509e600, 0x24072103, 0x0e200782, 0x20200382, + 0xbf202382, 0x1b830782, 0x0b824920, 0x0b82d220, 0x03855c20, 0x82fc0421, 0x825f2007, 0x00612403, 0x820d0500, 0x82632007, 0x82662003, 0x215f820b, + 0x0b826be6, 0x07210382, 0x20078229, 0x21038575, 0x07823405, 0x0385b120, 0x82250721, 0x85b32007, 0x26072103, 0xb8200782, 0x05210385, 0x20078261, + 0x200382c4, 0x206b82c5, 0x200782f9, 0x210385da, 0x07822707, 0x0385dd20, 0x82fb0221, 0x85df2007, 0x83022003, 0x20c78283, 0x250382e6, 0x0000fd02, + 0x03851ce7, 0x82030521, 0x207b8207, 0x210382e7, 0x0b82f904, 0x03853a20, 0x82280721, 0x853c2007, 0x8e072103, 0x42200782, 0x07210385, 0x2007822b, + 0x24038243, 0x07000044, 0x20078231, 0x21038545, 0x07822c07, 0x03854620, 0x822a0721, 0x85472007, 0x30072103, 0x48200782, 0x49200382, 0x2e202f82, + 0x60200782, 0x07210385, 0x82078239, 0x82e720c3, 0x35072103, 0x62200b82, 0x07210385, 0x20078233, 0x21038563, 0x07823807, 0x03856420, 0x82340721, + 0x85662007, 0x3a072103, 0x67200782, 0x07210385, 0x20078237, 0x21038569, 0x07823607, 0x03856d20, 0x823e0721, 0x856e2007, 0x3d072103, 0x6f200782, + 0x07210385, 0x2007823c, 0x21038570, 0x07823b07, 0x03859820, 0xd3830720, 0x0b829920, 0x07210382, 0x2007823f, 0x2103859a, 0x07824107, 0x03859b20, + 0x82400721, 0x859c2007, 0x42072103, 0xa2200782, 0xa3200382, 0x4420d782, 0xad200782, 0x07200385, 0xaf20f783, 0x03820b82, 0xf7830720, 0x0b82b020, + 0x07210382, 0x20078246, 0x210385c8, 0x07825007, 0x0385c920, 0x824d0721, 0x85ca2007, 0x4a072103, 0xcb200782, 0x07210385, 0x2007824f, 0x210385cc, + 0x07824b07, 0x0385cd20, 0x824e0721, 0x85ce2007, 0x51072103, 0xcf200782, 0x07210385, 0x2007824c, 0x210385d0, 0x07824907, 0x0385d320, 0x82520721, + 0x82e12007, 0x82e22003, 0x825320a7, 0x85e42007, 0x5a072103, 0xe5200782, 0x07210385, 0x20078258, 0x210385e6, 0x07825707, 0x0385e920, 0x82fe0221, + 0x00ee2807, 0x0001e800, 0x82ff0200, 0x820b2007, 0x000e2403, 0x82130300, 0x850f2007, 0x59072103, 0x10200782, 0x07210385, 0x20078255, 0x20038211, + 0x82238217, 0x18e82103, 0x03820b82, 0x82560721, 0x85192007, 0x5c072103, 0x1a200782, 0x07210385, 0x2007825b, 0x2103852b, 0x07826407, 0x03823420, + 0x3b823920, 0x07821e20, 0x03853a20, 0x820e0721, 0x853b2007, 0x5e072103, 0x42200782, 0x07210385, 0x20078267, 0x2403824d, 0x03000051, 0x20078224, + 0x20038253, 0x200b8273, 0x20078229, 0x20038275, 0x200b82b6, 0x2007824a, 0x200382b8, 0x200b82ce, 0x2407828c, 0xe90000d0, 0x200b8200, 0x200782a3, + 0x20038202, 0x200b8206, 0x200782d4, 0x82038208, 0xd90321cf, 0xbf820782, 0x8243e921, 0x82e12017, 0x8545200b, 0x14042103, 0x47200782, 0x7d240382, + 0x15040000, 0x7f200782, 0x04210385, 0x2007824c, 0x20038582, 0x218b8204, 0x0b8288e9, 0x23828920, 0x07824e20, 0x03858b20, 0x82500421, 0x858f2007, + 0x51042103, 0x92200782, 0x04210385, 0x20078252, 0x21038594, 0x07825304, 0x03859620, 0x82540421, 0x85982007, 0x55042103, 0x9a200782, 0x9b200382, + 0x56205382, 0x9d200782, 0x04210385, 0x20078258, 0x200382a1, 0x201782a3, 0x20078259, 0x210385a5, 0x07825c04, 0x0385a720, 0x82710721, 0x85a82007, + 0x5d042103, 0xaa200782, 0x04210385, 0x2007825e, 0x210385ad, 0x07825f04, 0x0382b020, 0x4782b220, 0x07826020, 0x0385b420, 0x82630421, 0x82b62007, + 0x82b72003, 0x82642017, 0x82ba2007, 0x82bd2003, 0x8266200b, 0x82c02007, 0x00c22403, 0x82780500, 0x85c32007, 0x6a042103, 0xc5200782, 0x04210385, + 0x2007826b, 0x200382c8, 0x202f82cf, 0x2007826c, 0x200382d1, 0x200b82d4, 0x20078274, 0x200382d6, 0x830b82d9, 0x82dd203b, 0x2103820b, 0x07827c04, + 0x0382e020, 0x1782e120, 0x07827d20, 0x0385e420, 0x827f0421, 0x85e62007, 0x80042103, 0xe9200782, 0x04210385, 0x20078281, 0x200382ec, 0x202f82ed, + 0x20078282, 0x210385ef, 0x07828404, 0x0382f220, 0x1782f320, 0x07828520, 0x0385f420, 0xb3830720, 0x0b82f520, 0x1782f620, 0x07828720, 0x0385f920, + 0x82890421, 0x85fc2007, 0x8a042103, 0xfe200782, 0x04250385, 0xea00008b, 0x20038200, 0x202f8202, 0x2007828c, 0x20038209, 0x200b8224, 0x2007828f, + 0x20038525, 0x21cb8207, 0x0b8226ea, 0x17823920, 0x0782ab20, 0x03853a20, 0x821c0521, 0x853b2007, 0x08052103, 0x3c200782, 0x05210385, 0x2007822b, + 0x2103853d, 0x07824005, 0x03853e20, 0x82550521, 0x853f2007, 0x72052103, 0x1b830782, 0x53824920, 0x0b82bf20, 0x03854a20, 0x82a90521, 0x854b2007, + 0xb8052103, 0x4c200782, 0x05210385, 0x20078210, 0x2103854d, 0x07829a05, 0x03854e20, 0x822a0521, 0x854f2007, 0x83052003, 0x82502013, 0x0059240b, + 0x82c90400, 0x855a2007, 0xa3052103, 0x5b200782, 0x05200385, 0x5c200783, 0x03820b82, 0x82590521, 0x855d2007, 0x77052103, 0x5e200782, 0x05210385, + 0x2007820c, 0x2103855f, 0x07822005, 0x03826020, 0x53826920, 0x0782d320, 0x03856b20, 0xbf830720, 0x0b826c20, 0x07210382, 0x20078263, 0x2103856d, + 0x07827607, 0x03856e20, 0x82700721, 0x20038307, 0x203b8274, 0x200b82dd, 0x21038575, 0x0782e105, 0x03857620, 0x82ba0521, 0x85772007, 0x67052103, + 0x78200782, 0x05210385, 0x200782bb, 0x21038579, 0x0782ff04, 0x03857e20, 0x82730721, 0x85802007, 0x83072003, 0x82812097, 0x2103820b, 0x07827507, + 0x03858720, 0x82690721, 0x858d2007, 0x6b072103, 0x8e200782, 0x07210385, 0x20078261, 0x20038596, 0x20df8307, 0x820b8298, 0x83072003, 0x829920bb, + 0x2103820b, 0x07826507, 0x03859a20, 0x82680721, 0x859b2007, 0x62072103, 0x9d200782, 0x07210385, 0x2007826f, 0x2103859f, 0x07827707, 0x0385a020, + 0xf7830720, 0x0b82a220, 0x07210382, 0x2007826a, 0x210385a3, 0x07826c07, 0x0385a620, 0xc7830720, 0x0b82a720, 0x07200382, 0xa820eb83, 0x03820b82, + 0xd3830720, 0x0000a923, 0x210382ea, 0x07828207, 0x0385aa20, 0x82790721, 0x85ab2007, 0x82072003, 0xacea21e7, 0xad240b82, 0x7c070000, 0xae200782, + 0x07210385, 0x2007827b, 0x210385af, 0x07828507, 0x0385b020, 0x82830721, 0x85b12007, 0x7a072103, 0xb2200782, 0x07210385, 0x2007827f, 0x210385b3, + 0x07828407, 0x0385c220, 0x828c0721, 0x85c32007, 0x90072103, 0xc6200782, 0x07210385, 0x20078298, 0x210385c7, 0x07829407, 0x0385c820, 0x828b0721, + 0x85c92007, 0x91072103, 0xca200782, 0x07210385, 0x2007828d, 0x210385cc, 0x07828a07, 0x0385cd20, 0x82960721, 0x85cf2007, 0x92072103, 0xd0200782, + 0x07210385, 0x2007828f, 0x210385d1, 0x07828707, 0x0385d220, 0x82970721, 0x85d32007, 0x88072103, 0xd4200782, 0x07210385, 0x20078286, 0x210385d5, + 0x07828907, 0x0385d620, 0x829c0721, 0x85d72007, 0x95072103, 0xd8200782, 0x07210385, 0x2007829b, 0x210385d9, 0x07829e07, 0x0385da20, 0x829a0721, + 0x85db2007, 0x9d072103, 0xdd200782, 0x07210385, 0x200782a4, 0x210385de, 0x0782a207, 0x0385df20, 0x82a10721, 0x85e02007, 0xa0072103, 0xe2200782, + 0xe3240382, 0xa5070000, 0xe4200782, 0x07210385, 0x2007829f, 0x210385e6, 0x0782a807, 0x0385e720, 0x82a70721, 0x85e82007, 0xa9072103, 0xe9200782, + 0x07210385, 0x200782ba, 0x210385ea, 0x0782b907, 0x0385eb20, 0x82b60721, 0x85ec2007, 0xb0072103, 0xee200782, 0x07210385, 0x200782bb, 0x210385ef, + 0x0782ae07, 0x0385f020, 0x82ab0721, 0x85f12007, 0xaf072103, 0xf2200782, 0x07210385, 0x200782b8, 0x210385f3, 0x0782b407, 0x0385f420, 0x82b70721, + 0x85f52007, 0xac072103, 0xf6200782, 0x07210385, 0x200782aa, 0x210385f7, 0x0782b107, 0x0385f820, 0x82b50721, 0x85f92007, 0xb3072103, 0xfa200782, + 0x07210385, 0x200782ad, 0x250385fb, 0x0000b207, 0x03821beb, 0x00001f24, 0x07823905, 0x03852820, 0x82760521, 0x85292007, 0x97052103, 0x2c200782, + 0x07210385, 0x200782c1, 0x2103852d, 0x0782d407, 0x03852e20, 0x82d00721, 0x852f2007, 0xc3072103, 0x30200782, 0x07210385, 0x200782cb, 0x21038531, + 0x0782d307, 0x03853220, 0x82be0721, 0x85332007, 0xcd072103, 0x34200782, 0x07210385, 0x200782c0, 0x21038535, 0x0782d107, 0x03853620, 0x82c90721, + 0x85372007, 0xbd072103, 0x38200782, 0x07210385, 0x830782c6, 0x210382b7, 0x0b82c207, 0x03853a20, 0x82c80721, 0x823b2007, 0x004c2403, 0x82e20400, + 0x824e2007, 0x824f2003, 0x82f4200b, 0x85502007, 0xc4072103, 0x51200782, 0x07210385, 0x200782d2, 0x21038552, 0x0782ce07, 0x03855320, 0x82ca0721, + 0x85542007, 0xc7072103, 0x56200782, 0x07210385, 0x200782cf, 0x21038557, 0x0782bf07, 0x03855820, 0x82c50721, 0x85592007, 0xcc072103, 0x5a200782, + 0x07210385, 0x200782bc, 0x2103855f, 0x0782e307, 0x03856020, 0x9b830720, 0x0b826120, 0x07210382, 0x200782e0, 0x21038562, 0x0782da07, 0x03856420, + 0x82e10721, 0x85652007, 0xdc072103, 0x66200782, 0x07210385, 0x200782e4, 0x21038567, 0x0782d707, 0x03856820, 0x82dd0721, 0x85692007, 0xdb072103, + 0x6a200782, 0x6b240382, 0xe8070000, 0x6f200782, 0x07210385, 0x200782d5, 0x21038570, 0x0782d807, 0x03827120, 0x23827220, 0x0782de20, 0x03827320, + 0x0b827520, 0x0782e520, 0x03857620, 0x82d60721, 0x85772007, 0xd9072103, 0x7a200782, 0x08210385, 0x20078202, 0x2103857b, 0x0782f007, 0x03857c20, + 0x82f50721, 0x857d2007, 0xef072103, 0x7e200782, 0x07210385, 0x200782f4, 0x2503857f, 0x00000008, 0x038580eb, 0x82f90721, 0x85812007, 0xf7072103, + 0x82200782, 0x07210385, 0x200782ed, 0x21038583, 0x0782f107, 0x03858420, 0x82f60721, 0x85852007, 0x01082103, 0x86200782, 0x07210385, 0x200782ec, + 0x21038587, 0x0782ff07, 0x03858820, 0x82fb0721, 0x858a2007, 0xf2072103, 0x8b200782, 0x07210385, 0x200782fa, 0x2103858c, 0x0782f307, 0x03858d20, + 0x82ea0721, 0x858e2007, 0xfe072103, 0x8f200782, 0x07210385, 0x200782f8, 0x21038590, 0x0782fd07, 0x03859120, 0x82fc0721, 0x85922007, 0x03082103, + 0x93200782, 0x07210385, 0x200782ee, 0x21038594, 0x0782eb07, 0x03859520, 0x82180821, 0x85962007, 0x13082103, 0x97200782, 0x08210385, 0x2007820a, + 0x21038598, 0x07820f08, 0x03859920, 0x82160821, 0x859a2007, 0x1e082103, 0x9b200782, 0x08210385, 0x20078215, 0x2103859c, 0x07821208, 0x03859d20, + 0x820e0821, 0x859e2007, 0x07082103, 0x9f200782, 0x08210385, 0x20078205, 0x210385a0, 0x07820c08, 0x0382a120, 0x0000a224, 0x07821f08, 0x0385a320, + 0x82170821, 0x85a42007, 0x1d082103, 0xa5200782, 0x08210385, 0x20078214, 0x210385a6, 0x07821908, 0x0385a720, 0x821b0821, 0x85a82007, 0x08082103, + 0xa9200782, 0x08210385, 0x20078206, 0x210385aa, 0x07821c08, 0x0385ab20, 0x821a0821, 0x85ac2007, 0x0d082103, 0xb6200782, 0x08210385, 0x20078209, + 0x210385b8, 0x07822108, 0x0385b920, 0x82100821, 0x85ba2007, 0x04082103, 0xbb200782, 0x08210385, 0x20078211, 0x210385bc, 0x07820b08, 0x0385bd20, + 0x82260821, 0x85be2007, 0x29082103, 0xc4200782, 0x08210385, 0x2007822d, 0x210385c5, 0x07822408, 0x0385c620, 0x822f0821, 0x85c82007, 0x2e082103, + 0xc9200782, 0x08210385, 0x20078225, 0x210385ca, 0x07822808, 0x0385cb20, 0x82270821, 0x85cc2007, 0x23082103, 0xcd200782, 0x08210385, 0x2007822a, + 0x210385ce, 0x07822c08, 0x0385cf20, 0x82300821, 0x85d02007, 0x2b082103, 0xd1200782, 0x08210385, 0x20078222, 0x210385d2, 0x07823708, 0x0385d320, + 0x823f0821, 0x85d42007, 0x36082103, 0xd5200782, 0x08210385, 0x20078238, 0x210385d6, 0x07823d08, 0x0385d720, 0x823b0821, 0x85d82007, 0x44082103, + 0xd9200782, 0x08210385, 0x20078232, 0x210385da, 0x07824508, 0x0385db20, 0x82430821, 0x85dc2007, 0x31082103, 0xdd200782, 0x08210385, 0x20078234, + 0x210385de, 0x07823908, 0x0385df20, 0x82410821, 0x85e02007, 0x33082103, 0xe1200782, 0x08210385, 0x2007823e, 0x210385e2, 0x07823508, 0x0385e320, + 0x82420821, 0x85e42007, 0x3c082103, 0xe5200782, 0x08210385, 0x20078240, 0x210385e6, 0x07823a08, 0x0385e720, 0x824c0821, 0x85e82007, 0x56082103, + 0xe9200782, 0x08210385, 0x20078249, 0x210385ea, 0x07825708, 0x0385eb20, 0x82550821, 0x85ec2007, 0x50082103, 0xed200782, 0x08210385, 0x2007824d, + 0x210385ee, 0x07825308, 0x0385ef20, 0x82520821, 0x85f02007, 0x4f082103, 0xf1200782, 0x08210385, 0x2007824e, 0x210385f2, 0x07824808, 0x0385f320, + 0x82510821, 0x85f42007, 0x4a082103, 0xf6200782, 0x08210385, 0x2007824b, 0x210385f7, 0x07825408, 0x0385fc20, 0x825a0821, 0x85fd2007, 0x59082103, + 0xfe200782, 0x08250385, 0xec000058, 0x21038508, 0x07825b08, 0x03850920, 0x825e0821, 0x850a2007, 0x6a082103, 0x0b200782, 0x08210385, 0x20078269, + 0x2103850c, 0x07827608, 0x03850d20, 0x82750821, 0x850e2007, 0x74082103, 0x0f200782, 0x08210385, 0x20078273, 0x21038510, 0x07827208, 0x03851120, + 0x82710821, 0x85122007, 0x70082103, 0x13200782, 0x08210385, 0x2007826f, 0x21038514, 0x07826e08, 0x03851520, 0x826d0821, 0x85162007, 0x6c082103, + 0x17200782, 0x08210385, 0x2007826b, 0x21038518, 0x07826808, 0x03851920, 0x82670821, 0x851a2007, 0x66082103, 0x1b200782, 0x08210385, 0x20078265, + 0x2103851c, 0x07826408, 0x03851d20, 0x82630821, 0x851e2007, 0x62082103, 0x1f200782, 0x08210385, 0x20078261, 0x21038520, 0x07825f08, 0x03853120, + 0x00a40825, 0x8238ef00, 0x00392403, 0x82f70400, 0x823a2007, 0x823b2003, 0x82fa200b, 0x823c2007, 0x823d2003, 0x82fd200b, 0x853e2007, 0x01052103, + 0x3f200782, 0x41240382, 0x05050000, 0x42200782, 0x05210385, 0x2007820b, 0x20038543, 0x21d38205, 0x0b8244ef, 0x05210382, 0x20078219, 0x21038545, + 0x07821b05, 0x03824620, 0x3b824820, 0x07821d20, 0x03854920, 0x82210521, 0x854a2007, 0x26052103, 0x4b200782, 0x05210385, 0x20078230, 0x2103854c, + 0x07823305, 0x03854d20, 0x82380521, 0x854e2007, 0x83052003, 0x824f2073, 0x2103820b, 0x07824705, 0x03855020, 0x4f830520, 0x0b825120, 0x05200382, + 0xef210382, 0x820b8252, 0x54052103, 0x53200782, 0x05210385, 0x8307825a, 0x2103820f, 0x0b826005, 0x03825520, 0x9b825620, 0x07826320, 0x03855720, + 0x82660521, 0x85582007, 0x68052103, 0x59200782, 0x5a200382, 0x6f202382, 0x5b200782, 0x05210385, 0x20078275, 0x2103855c, 0x07827c05, 0x03855d20, + 0x827e0521, 0x855e2007, 0x80052103, 0x5f200782, 0x05210385, 0x83078290, 0x2167826f, 0x0b829305, 0x03856420, 0x82980521, 0x82652007, 0x82672003, + 0x829b205f, 0x206f8307, 0x200b8269, 0x200b82a1, 0x2103856a, 0x0782a405, 0x03856b20, 0x82ac0521, 0x826c2007, 0x826e2003, 0x82ae2023, 0x82938307, + 0xb7052103, 0x70200b82, 0x05210385, 0x200782b9, 0x21038571, 0x0782cd05, 0x03857220, 0x82d00521, 0x85732007, 0xd2052103, 0x74200782, 0x05210385, + 0x830782d9, 0x210382cf, 0x0b82dc05, 0x03857620, 0x82e00521, 0x85772007, 0xe7052103, 0x78200782, 0x05210385, 0x200782ea, 0x210385a7, 0x07826d05, + 0xd6246383, 0x13060000, 0xd8200b82, 0xda200382, 0x1e200b82, 0xdb200782, 0xeb200382, 0x22200b82, 0xec200782, 0x05210385, 0x20078223, 0x200382ed, + 0x201782ee, 0x20078233, 0x200382ef, 0x200b82f0, 0x20078236, 0x200382f1, 0x200b82fa, 0x20078239, 0x200382fb, 0x240b82ff, 0xf0000047, 0x20038200, + 0x200b8206, 0x2007824e, 0x21038507, 0x07825606, 0x03820920, 0x17822020, 0x07825720, 0x03822120, 0x0b822520, 0x07827020, 0x03822820, 0x0b823420, + 0xf021c782, 0x200b8235, 0x200b8240, 0x20078284, 0x20038241, 0x200b8243, 0x20078291, 0x20038244, 0x200b8245, 0x20078295, 0x20038247, 0x200b824b, + 0x20078298, 0x2003824c, 0x200b8255, 0x8307829e, 0x825b2063, 0x82aa200b, 0x855c200b, 0xf8052103, 0x5d200782, 0x5f200382, 0xb0201782, 0x60200782, + 0x61200382, 0xb4200b82, 0x62200782, 0x6c200382, 0xb7200b82, 0x6d200782, 0x6e200382, 0xc3200b82, 0x6f200782, 0x07210385, 0x8307820f, 0x8275209f, + 0x82c72017, 0x209f830b, 0x200b8277, 0x200b82ce, 0x2003827a, 0x200b827b, 0x200782d0, 0x2003827c, 0x200b827e, 0x200782d3, 0x8203827f, 0xd70621bb, + 0x85200782, 0x88200382, 0xde201782, 0x89200782, 0x06210385, 0x200782e3, 0x2003828c, 0x8217828f, 0x90f021db, 0xdf820b82, 0xc7830620, 0x0b829220, + 0x05200382, 0xf021ab82, 0x820b8297, 0x83062103, 0x99200782, 0x9a200382, 0xc5202f82, 0x9b200782, 0x06210385, 0x200782d6, 0x210385a8, 0x0782c005, + 0x0385ac20, 0x82b60621, 0x82e78307, 0xc1052103, 0x33830b82, 0x05210382, 0x200b8244, 0x210385cf, 0x07827405, 0x0385d120, 0x828d0521, 0x85d22007, + 0x82052003, 0xdcf02187, 0x03820b82, 0x5b830520, 0x0b82e220, 0x05210382, 0x200782d3, 0x210385eb, 0x07828e05, 0x0385ec20, 0x82cb0521, 0x85f52007, + 0x18052103, 0xfa200782, 0x05210385, 0x2007829f, 0x210385fb, 0x0782df05, 0x0385fc20, 0x82e80521, 0x85fd2007, 0xa0052103, 0xfe200782, 0x05210385, + 0x2007828c, 0x250385ff, 0x00002705, 0x038500f1, 0x82570521, 0x85012007, 0x82052003, 0x02f121ef, 0x03820b82, 0x823e0521, 0x85042007, 0x52052103, + 0x06200782, 0x05210385, 0x2007829e, 0x21038507, 0x0782a505, 0x03850820, 0x82580521, 0x85092007, 0x6e052103, 0x0a200782, 0x05210385, 0x2007822e, + 0x2103850b, 0x07825005, 0x03850c20, 0x82730521, 0x850d2007, 0xab052103, 0x0e200782, 0x05210385, 0x2007825d, 0x2103850f, 0x07822f05, 0x03851120, + 0x82cf0521, 0x85122007, 0xd1052103, 0x14200782, 0x05210385, 0x200782e2, 0x21038516, 0x07825e05, 0x03851b20, 0x82620521, 0x857d2007, 0x56052103, + 0x7e200782, 0x05210385, 0x200782a6, 0x24038281, 0x05000082, 0x20078209, 0x21038584, 0x07820005, 0x03858720, 0x824c0521, 0x85892007, 0x6a052103, + 0x8a200782, 0x05210385, 0x2007826c, 0x2103858b, 0x07826905, 0x03858c20, 0x826b0521, 0x789b2007, 0x052105ef, 0x20078215, 0x2003829d, 0x205f829e, + 0x20078224, 0x2103859f, 0x07823105, 0x0385a020, 0x823f0521, 0x85a12007, 0x41052103, 0xa2200782, 0x05210385, 0x20078245, 0x210385a3, 0x07824905, + 0x0382a420, 0x4782a720, 0xa820af83, 0x03820b82, 0x82860521, 0x85a92007, 0xca052103, 0xaa200782, 0x05210385, 0x200782dd, 0x210385ab, 0x0782e605, + 0x0385ac20, 0x82420521, 0x85ad2007, 0xde052103, 0xae200782, 0x05210385, 0x200782ce, 0x200385af, 0x20f78305, 0x820b82b0, 0x32052103, 0xb1200782, + 0x05210385, 0x200782e3, 0x210385b2, 0x0782c405, 0x0385b320, 0x82350521, 0x85b42007, 0xbd052103, 0xb5200782, 0x05210385, 0x200782bc, 0x210385b6, + 0x0782b105, 0x0385b720, 0x82040521, 0x85b82007, 0xb4052103, 0xb9200782, 0x05210385, 0x2007827b, 0x210385bb, 0x07829905, 0x0385be20, 0x82d70521, + 0x85bf2007, 0x36052103, 0xc0200782, 0x05210385, 0x20078253, 0x210385c1, 0x0782c205, 0x05210386, 0x200b82b5, 0x210385c3, 0x0782eb05, 0x0382ab83, + 0x82c50521, 0x2103860b, 0x0b82a705, 0x0385c620, 0x82da0521, 0x85c72007, 0x83052003, 0x82c82037, 0x2103820b, 0x0782db05, 0x0385c920, 0x82b60521, + 0x85ca2007, 0xaa052103, 0xcc200782, 0x05200385, 0xcd209783, 0x03820b82, 0x82020521, 0x85ce2007, 0x8f052103, 0xcf200782, 0x05210385, 0x20078228, + 0x210385d0, 0x07822c05, 0x0382d120, 0x0000d224, 0x0782d405, 0x05210386, 0x200b8292, 0x210385d5, 0x07828805, 0x0385d620, 0x82850521, 0x85d82007, + 0x48052103, 0x93830782, 0x05210382, 0x200b8265, 0x210385dc, 0x07822905, 0x0385df20, 0x82370521, 0x82e02007, 0x82e22003, 0x8289205f, 0x82e32007, + 0x82e52003, 0x20eb830b, 0x820b82e6, 0x82052003, 0xe8f1210f, 0x03820b82, 0x82e90521, 0x20038607, 0x20678305, 0x820f82ea, 0xbe052103, 0xef200782, + 0x05210385, 0x2007827d, 0x210385f1, 0x07827f05, 0x0385f220, 0x824b0521, 0x85f32007, 0xc9052103, 0xf4200782, 0x05210385, 0x2007821a, 0x210385f5, + 0x0782b205, 0x0385f620, 0x82460521, 0x85f72007, 0x2d052103, 0xf8200782, 0x05210385, 0x20078222, 0x250385fc, 0x0000cc05, 0x038500f2, 0x824d0521, + 0x85012007, 0xb3052103, 0x02200782, 0x05210385, 0x2007825c, 0x21038503, 0x0782e405, 0x03850420, 0x82710521, 0x85052007, 0x4f052103, 0x06200782, + 0x05210385, 0x200782ad, 0x2103850c, 0x0782ec05, 0x03851720, 0x82ee0521, 0x85182007, 0xf5052103, 0x1a200782, 0x05210385, 0x200782f2, 0x2103851b, + 0x0782f405, 0x03821c20, 0x00001d24, 0x0782f605, 0x03851e20, 0x82ed0521, 0x851f2007, 0xef052103, 0x20200782, 0x05210385, 0x200782f9, 0x21038521, + 0x0782f105, 0x03852220, 0x82f30521, 0x85232007, 0xf0052103, 0x27200782, 0xa2820385, 0x28f20022, 0x03820b82, 0x82040621, 0x85292007, 0x83062003, + 0x822b20df, 0x2103820b, 0x07820706, 0x03852c20, 0x82060621, 0x852e2007, 0xfb052103, 0x30200782, 0x05210385, 0x200782fc, 0x21038532, 0x07820506, + 0x03853320, 0x82fe0521, 0x85342007, 0xfd052103, 0x35200782, 0x05210385, 0x200782ff, 0x21038536, 0x07820806, 0x03853720, 0x82010621, 0x853a2007, + 0xfa052103, 0x3b200782, 0x06250385, 0xf8000002, 0x21038540, 0x0782b408, 0x03854620, 0x82b30821, 0x82482007, 0x00492403, 0x82b10800, 0x855c2007, + 0xaa082103, 0x67200782, 0x6a200382, 0xab201782, 0x6b200782, 0x08210385, 0x200782b0, 0x2103856e, 0x0782af08, 0x03857920, 0x82a90821, 0x85862007, + 0xa8082103, 0x8c200782, 0x8d200382, 0xa6203b82, 0xa0200782, 0x08210385, 0x200782a5, 0x210385ce, 0x07828b08, 0x0382cf20, 0x2382d020, 0x0782a120, + 0x0385d120, 0x828e0821, 0x85d22007, 0x99082103, 0xd3200782, 0x08200385, 0xd5204383, 0xd6200b82, 0x8c202f82, 0xd7200782, 0xe0200382, 0x8f200b82, + 0xe1200782, 0xe6200382, 0x9a200b82, 0xe7200782, 0x08210385, 0x200782a3, 0x210385e8, 0x07828808, 0x0385ea20, 0x82870821, 0x85eb2007, 0x81082103, + 0xec200782, 0x08210385, 0x20078289, 0x200382ed, 0x204782ef, 0x20078282, 0x210385f0, 0x07828a08, 0x0382f120, 0x1782f220, 0x07828520, 0x0385f320, + 0x827b0821, 0x85f42007, 0x7a082103, 0xf5200782, 0xf7200382, 0x7e202382, 0xf8200782, 0xf9200382, 0x78200b82, 0xfd200782, 0x08210385, 0x20078277, + 0x200382fe, 0x241782ff, 0xff10007c, 0x2b0384fd, 0x00f60400, 0x00f60e04, 0x02480200, 0x7d0a1882, 0x39004800, 0x7a005f00, 0x0de004e0, 0x15e011e0, + 0x21e019e0, 0x2ce024e0, 0x39e031e0, 0x74e053e0, 0x89e076e0, 0xbfe0bce0, 0xf0e0c4e0, 0x3ee138e1, 0x95e179e1, 0x9ce199e1, 0xa2e19ee1, 0xc6e1c3e1, + 0xd3e1c8e1, 0xdbe1d5e1, 0xebe1e2e1, 0x6ce202e2, 0xc4e286e2, 0xcce2c9e2, 0xe7e2dbe2, 0x08e3ece2, 0x3ae318e3, 0xe0e399e3, 0x13e4eee3, 0x40e42ee4, + 0xd9e4cae4, 0x03e5ebe4, 0x18e515e5, 0x25e521e5, 0x7de536e5, 0x95e591e5, 0xe1e59ae5, 0x09e6fae5, 0x49e620e6, 0x61e65ce6, 0x6be666e6, 0xb1e675e6, + 0xb8e6b3e6, 0xdae6c5e6, 0xdfe6dde6, 0x1ce7e1e6, 0x3ae729e7, 0x49e73ce7, 0x67e764e7, 0x70e769e7, 0xa3e79ce7, 0xb0e7ade7, 0xd3e7d0e7, 0xe6e7e2e7, + 0x01e8e9e7, 0x1ae80ee8, 0x39e82be8, 0x42e83be8, 0x73e851e8, 0xcee8b6e8, 0x06e900e9, 0x43e90fe9, 0x7de945e9, 0x82e97fe9, 0x8be989e9, 0x92e98fe9, + 0x96e994e9, 0x9be998e9, 0xa3e99de9, 0xa8e9a5e9, 0xade9aae9, 0xb4e9b2e9, 0xbde9b7e9, 0xc5e9c3e9, 0xd4e9cfe9, 0xdde9d9e9, 0xe4e9e1e9, 0xe9e9e6e9, + 0xefe9ede9, 0xf9e9f6e9, 0xfee9fce9, 0x24ea02ea, 0x39ea25ea, 0x49ea3fea, 0x59ea4fea, 0x69ea5fea, 0x74ea6eea, 0x7eea79ea, 0x87ea81ea, 0x96ea8eea, + 0x9dea9bea, 0xa3eaa0ea, 0xc3eab3ea, 0xcdeacaea, 0xe0eadbea, 0xeceae4ea, 0x1febfbea, 0x3aeb29eb, 0x54eb4ceb, 0x62eb5aeb, 0x77eb6beb, 0xaceb88eb, + 0xbeebb6eb, 0xf4ebc6eb, 0xfeebf7eb, 0x31ec20ec, 0xa7ef78ef, 0xdaefd6ef, 0xf0efebef, 0x07f0faef, 0x25f020f0, 0x40f034f0, 0x4bf045f0, 0x61f055f0, + 0x77f06cf0, 0x8ff089f0, 0x97f092f0, 0xa8f09bf0, 0xb0f0acf0, 0xcff0c5f0, 0xdcf0d2f0, 0xecf0e2f0, 0x02f1f5f0, 0x0ff104f1, 0x14f112f1, 0x1bf116f1, + 0x82f17ef1, 0x87f184f1, 0xb9f18cf1, 0xcaf1bbf1, 0xd6f1d2f1, 0xdcf1d8f1, 0xeaf1e6f1, 0xf8f1eff1, 0x06f2fcf1, 0x18f20cf2, 0x29f223f2, 0x2ef22cf2, + 0x37f230f2, 0x40f83bf2, 0x49f846f8, 0x6af85cf8, 0x6ef86bf8, 0x86f879f8, 0xa0f88df8, 0xd6f8d3f8, 0xe8f8e0f8, 0xfff8f9f8, 0x0000ffff, 0x5f003000, + 0x00e06100, 0x0fe00ae0, 0x19e014e0, 0x23e01be0, 0x2ee028e0, 0x3be033e0, 0x75e055e0, 0xafe089e0, 0xc3e0bee0, 0x38e1c6e0, 0x45e13ee1, 0x494290e1, + 0xa0340806, 0xc4e1a3e1, 0xcae1c8e1, 0xd8e1d5e1, 0xebe1e0e1, 0x26e2fee1, 0xbce286e2, 0xcce2c6e2, 0xe6e2dbe2, 0x07e3eae2, 0x1ae30ae3, 0x9de399e3, + 0xf1e3e2e3, 0x30e415e4, 0x08054942, 0xe5f3e423, 0xe518e508, 0xe524e51c, 0xe539e52d, 0xe595e583, 0xe5c3e598, 0xe609e6fa, 0xe623e60e, 0xe65fe65c, + 0x0a494263, 0x4942c420, 0x42420810, 0x66e760e7, 0x6de769e7, 0xa2e798e7, 0xafe7ade7, 0xd3e7c8e7, 0xe4e7e1e7, 0xeee7e9e7, 0x0fe80be8, 0x34e82be8, + 0x42e83ae8, 0x53e84de8, 0xb8e875e8, 0x02e9d0e8, 0x11e908e9, 0x47e945e9, 0x82e97fe9, 0x494288e9, 0x9a22080c, 0xa1e99de9, 0xa7e9a5e9, 0xade9aae9, + 0xb4e9b0e9, 0xbae9b6e9, 0xc5e9c0e9, 0xd1e9c8e9, 0xdde9d6e9, 0x4942e0e9, 0xe9ec2406, 0x42f2e9ef, 0x90080649, 0xea09ea00, 0xea26ea25, 0xea40ea3a, + 0xea50ea4a, 0xea60ea5a, 0xea70ea6b, 0xea7eea75, 0xea87ea80, 0xea96ea8d, 0xea9dea98, 0xeaa2ea9f, 0xeac2eaa6, 0xeacceac6, 0xeaddeacf, 0xeae6eae2, + 0xeb1bebee, 0xeb2ceb28, 0xeb4eeb3b, 0xeb5feb56, 0xeb6feb64, 0xeb8aeb7a, 0xebb8ebb6, 0xebc8ebc4, 0xecfcebf6, 0xef31ec08, 0xefa7ef38, 0xefd8efcd, + 0xefecefdb, 0xf0fbeff1, 0xf021f009, 0xf035f028, 0xf047f041, 0xf056f04c, 0xf06df062, 0xf08cf07a, 0xf097f090, 0x0a494299, 0xdcf0d130, 0xebf0e2f0, + 0xfaf0f5f0, 0x06f104f1, 0x494211f1, 0x7d3e0806, 0x84f181f1, 0x89f187f1, 0xbbf19bf1, 0xccf1bef1, 0xd8f1d4f1, 0xdff1dbf1, 0xeff1e8f1, 0xfcf1f1f1, + 0x0cf200f2, 0x1af217f2, 0x2bf227f2, 0x30f22ef2, 0x3af232f2, 0x46f840f8, 0x5cf848f8, 0x494267f8, 0xf88c3908, 0xf8cef8a0, 0xf8d7f8d5, 0xf8eaf8e1, + 0xfffffffd, 0xffaeffd3, 0x002820ad, 0x2d080084, 0x13201420, 0x0f201220, 0x0d200e20, 0x0b200c20, 0x1a279c25, 0xd01fd11f, 0xcc1fcd1f, 0x5b262526, + 0x621f781f, 0x5c1fc326, 0x00001525, 0x0382561f, 0x00005238, 0x471f9a24, 0x4225431f, 0x051f281f, 0xb61eda25, 0xb31eb51e, 0x4e83f723, 0x1e791e37, + 0x23771e78, 0x1e151e4b, 0x1e121e14, 0x23101e11, 0x226e237c, 0x211b83a8, 0x0583de21, 0x241d3408, 0x0000221d, 0x79218d21, 0x2921dd1c, 0xb11c1b21, + 0xa01eaf1c, 0xae1eae1e, 0xbf1ebe20, 0x73207420, 0x351ca91e, 0x1e1c4d20, 0x1c1c1d1c, 0xd01de71d, 0x8220ee1f, 0x213b8373, 0x0584cd1f, 0x9a1fa222, + 0x7f300784, 0x0000721f, 0x111b151b, 0x0000081b, 0xea1a391f, 0x3c080582, 0x1ad71a25, 0x1ad51ad6, 0x1ad31ad4, 0x1ad11ad2, 0x1acf1ad0, 0x1acd1ace, + 0x1ac61acb, 0x1ac21ac5, 0x1abf1ac0, 0x1abd1abe, 0x1abb1abc, 0x00b71ab8, 0x1ab41a00, 0x1ab01ab2, 0x1aae1aaf, 0x340d82ac, 0x1aa41aa6, 0x1aa21aa3, + 0x1a9d1a9f, 0x1a9a1a9b, 0x1a961a98, 0x2c178295, 0x1a8e1a90, 0x1a8c1a8d, 0x1a4f1d86, 0x200f8285, 0x2003827f, 0x20038279, 0x24038273, 0x1c00006d, + 0x200382f5, 0x200382e2, 0x200382c9, 0x919d83d2, 0x1e1a2103, 0x19211383, 0x890583a7, 0x531c2103, 0x00220b89, 0x4f821c00, 0x16c61523, 0x24018246, + 0x16000047, 0x23038248, 0x164f164e, 0x09820382, 0x52165122, 0x55200582, 0x15202f83, 0x1533b982, 0x150000ec, 0x150a1618, 0x147f1411, 0x140000a5, + 0x82f114cc, 0x82232005, 0x834e2003, 0xce142423, 0x82144814, 0x88132545, 0xc5137c13, 0x13211183, 0x230583de, 0x70130000, 0x8e200786, 0xd0200b82, + 0xe0200382, 0x00250f85, 0x13cd1300, 0x3b0b83cc, 0x6d107410, 0x4e106910, 0x45104410, 0x30104110, 0x1a102210, 0x00000510, 0xb80fb70f, 0x03821f83, + 0x03820120, 0x02250284, 0x02460240, 0xa40a844a, 0x22022504, 0x24020000, 0x26200382, 0x02212e95, 0x961d8322, 0x0210221b, 0x22398230, 0x83520248, + 0x5002211f, 0x03ab0583, 0x023c0223, 0x233b834a, 0x58025202, 0x5c224184, 0x07845e02, 0x05836a20, 0x02000023, 0x21078368, 0x05837a02, 0x022103ab, + 0x212d8b4c, 0x0d8b4202, 0x02210b89, 0x830b8932, 0x2c022509, 0x34020000, 0x3c200382, 0x44200382, 0x48200382, 0x4e200382, 0x5234038a, 0x56025402, + 0x72027002, 0x7c027a02, 0x9a029402, 0xaa029e02, 0xc2221f82, 0x0582c402, 0xea02de2b, 0xf802f202, 0x16030603, 0x2f598203, 0x80037403, 0xdc038403, + 0xe203de03, 0x10040000, 0x03836183, 0x00880425, 0x838e0400, 0x21038309, 0x05849e04, 0x0000a226, 0xca04b604, 0xe6200582, 0xe8200382, 0x03851383, + 0x3b820420, 0xe0201182, 0xee210386, 0x22168505, 0x85fc0400, 0xf8042b08, 0x0000fe04, 0x50053805, 0x07825c05, 0x60055e24, 0x07826e05, 0x03827020, + 0x03827c20, 0x88058625, 0x84059a05, 0x9c052363, 0x3385a605, 0x0521058f, 0x24118392, 0xa6059805, 0x0dc78205, 0x061006c5, 0x060e06e5, 0x0609060a, + 0x060d060b, 0x060c060f, 0x067506e2, 0x06970694, 0x06dd0655, 0x06c20690, 0x011b01a8, 0x011d011c, 0x089d061e, 0x061d065d, 0x063506cd, 0x06a90621, + 0x06e80638, 0x06ef06ea, 0x060d07f9, 0x07f106e9, 0x06e6060b, 0x060107fe, 0x07ec06f0, 0x07f7060c, 0x06080700, 0x06ed06e7, 0x06f306f2, 0x06f506f4, + 0x06fa06f8, 0x070507fb, 0x07070706, 0x060a0709, 0x07ff06eb, 0x06030702, 0x07fc06fd, 0x07ee0604, 0x071c071d, 0x07210716, 0x07180717, 0x071b0715, + 0x071f071a, 0x071e0720, 0x07190710, 0x072b0714, 0x07320731, 0x072a072c, 0x072e0730, 0x0739072f, 0x07330735, 0x07340738, 0x0737073a, 0x073d073e, + 0x073b073c, 0x073f0743, 0x07400741, 0x07480742, 0x07500746, 0x074a074d, 0x074b074f, 0x0751074e, 0x0749074c, 0x0758075a, 0x07590757, 0x03170355, + 0x03190318, 0x031b031a, 0x071d031c, 0x075c0756, 0x070e075b, 0x0471075e, 0x0578055d, 0x047a0579, 0x0485046a, 0x04660786, 0x05880487, 0x0508051c, + 0x0540052b, 0x05720555, 0x05b805a9, 0x059a0510, 0x054e052a, 0x055b05a3, 0x05770559, 0x0720050c, 0x07630772, 0x05700776, 0x05ba05e1, 0x04bb0567, + 0x076007ff, 0x076b0775, 0x076d0761, 0x07680765, 0x07770762, 0x076a076e, 0x077e076c, 0x07800778, 0x07790782, 0x077c0781, 0x077b077d, 0x07830785, + 0x077f077a, 0x078c0784, 0x07980790, 0x078b0794, 0x078d0791, 0x0796078a, 0x078f0792, 0x07970787, 0x07860788, 0x079c0789, 0x079b0795, 0x079a079e, + 0x07a4079d, 0x07a107a2, 0x07a507a0, 0x079f07a6, 0x07a707a8, 0x07ba07a9, 0x07b607b9, 0x07bb07b0, 0x07ab07ae, 0x07b807af, 0x07b707b4, 0x07aa07ac, + 0x07b507b1, 0x07ad07b3, 0x057605b2, 0x07c10797, 0x07d007d4, 0x07cb07c3, 0x07be07d3, 0x07c007cd, 0x07c907d1, 0x07c607bd, 0x04c807c2, 0x07f504f4, + 0x07d207c4, 0x07ca07ce, 0x07cf07c7, 0x07c507bf, 0x07bc07cc, 0x07e207e3, 0x07da07e0, 0x07dc07e1, 0x07d707e4, 0x07db07dd, 0x07e907e8, 0x07d807d5, + 0x07df07de, 0x07e607e5, 0x07d607e7, 0x070208d9, 0x07f507f0, 0x08f407ef, 0x07f90700, 0x07ed07f7, 0x08f607f1, 0x07ec0701, 0x07fb07ff, 0x07fa07f2, + 0x07ea07f3, 0x07f807fe, 0x08fc07fd, 0x07ee0703, 0x081808eb, 0x080a0813, 0x0816080f, 0x0815081e, 0x080e0812, 0x08050807, 0x081f080c, 0x08170820, + 0x0814081d, 0x081b0819, 0x08060808, 0x081a081c, 0x0821080d, 0x08040810, 0x080b0811, 0x08290826, 0x0824082d, 0x082e082f, 0x08280825, 0x08230827, + 0x082c082a, 0x082b0830, 0x08370822, 0x0836083f, 0x083d0838, 0x0844083b, 0x08450832, 0x08310843, 0x08390834, 0x08330841, 0x0835083e, 0x083c0842, + 0x083a0840, 0x0856084c, 0x08570849, 0x08500855, 0x0853084d, 0x084f0852, 0x0848084e, 0x084a0851, 0x0854084b, 0x0859085a, 0x085b0858, 0x086a085e, + 0x08760869, 0x08740875, 0x08720873, 0x08700871, 0x086e086f, 0x086c086d, 0x0868086b, 0x08660867, 0x08640865, 0x08620863, 0x045f0861, 0x04f804f7, + 0x04fb04fa, 0x05fe04fd, 0x05050501, 0x05070506, 0x0517050b, 0x051b0519, 0x051e051d, 0x0521051f, 0x05300526, 0x05380533, 0x05470543, 0x0551054a, + 0x055a0554, 0x05630560, 0x05660564, 0x056f0568, 0x05750570, 0x057e057c, 0x05900580, 0x05940593, 0x05960595, 0x059b0598, 0x059d059c, 0x05a205a1, + 0x05ac05a4, 0x05af05ae, 0x05b705b0, 0x05cd05b9, 0x05d205d0, 0x05dc05d9, 0x05e705e0, 0x062305ea, 0x06340633, 0x06370636, 0x06480647, 0x064a0649, + 0x064e064b, 0x0650064f, 0x06520651, 0x06540653, 0x06910656, 0x06930692, 0x06960695, 0x06ab06aa, 0x06ad06ac, 0x05af06ae, 0x06b006f8, 0x06b206b1, + 0x06b506b4, 0x07c406c3, 0x06c7060f, 0x06c906c8, 0x06cb06ca, 0x06ce06cc, 0x06d006cf, 0x06d306d1, 0x06d506d4, 0x06d806d7, 0x06da06d9, 0x06dc06db, + 0x06df06de, 0x06e106e0, 0x064c06e3, 0x065f054d, 0x06c606c5, 0x058d05d6, 0x058e0591, 0x059f05cb, 0x05e805df, 0x058c05a0, 0x05570527, 0x053e05d6, + 0x05a5059e, 0x056e0558, 0x0550052e, 0x05ab0573, 0x052f055d, 0x05d105cf, 0x05a60556, 0x056c056a, 0x056b0569, 0x05160515, 0x05250524, 0x053f0531, + 0x05450541, 0x05810549, 0x05830582, 0x05860584, 0x05dd05ca, 0x054205e6, 0x05ce05de, 0x05320587, 0x05c405e3, 0x05bd0535, 0x05b105bc, 0x05b40504, + 0x05d7057b, 0x05530536, 0x05b505c2, 0x05c505eb, 0x05da05a7, 0x05db05c3, 0x05aa05b6, 0x050205bf, 0x0528058f, 0x05d4052c, 0x059205d5, 0x05850588, + 0x05290565, 0x05890537, 0x058b058a, 0x05c705c6, 0x05e505c8, 0x05d805e9, 0x057f05be, 0x05c9054b, 0x05b2051a, 0x052d0546, 0x054d0522, 0x055c05b3, + 0x057105e4, 0x05ad054f, 0x05f505ee, 0x05f405f2, 0x05f705f6, 0x05ef05ed, 0x05f105f9, 0x06f005f3, 0x06040600, 0x06070603, 0x05050606, 0x05fd05fe, + 0x060806ff, 0x06fa0501, 0x088b0802, 0x08a208a1, 0x0899088e, 0x089a08a0, 0x089c089b, 0x089e089d, 0x08a3089f, 0x08870888, 0x08890881, 0x08830882, + 0x088a0884, 0x08860885, 0x087a087b, 0x087f087e, 0x08780880, 0x08770879, 0x487d087c, 0x0a2e0611, 0x2c001e00, 0x616c0100, 0x08006e74, 0x15820400, + 0xffff0024, 0x07820100, 0x6c720124, 0x13826769, 0x0d850020, 0x04201b82, 0x11821583, 0xef014808, 0xee220076, 0xed32ee94, 0xec2ced98, 0xec96ecfe, + 0xec4aec70, 0xcd54d924, 0xab5ebaa6, 0x91b4a280, 0x86088e50, 0x814082d2, 0x72d27dca, 0x5f126764, 0x49be5c08, 0x3efa4792, 0x11b41b38, 0x08740f38, + 0x00e20032, 0x824a00a8, 0x00442c53, 0x001a0032, 0x00d2030a, 0x821c0007, 0x001a2a01, 0x0016000d, 0x00d4071b, 0x820f8b0b, 0x001a2615, 0x031d000e, + 0x877f82d3, 0x001c2827, 0x02210022, 0x880c008d, 0x87118429, 0x0200272b, 0x06001000, 0x6582e306, 0x1f000e28, 0xcd031100, 0x29821400, 0x21002222, + 0x0f223782, 0x27821200, 0x05822020, 0x10221b83, 0x09821500, 0x11821120, 0x21821320, 0x001fa008, 0x0740074b, 0x060e0722, 0x06c406e8, 0x068a06ae, + 0x065e0670, 0x063a0644, 0x050c0626, 0x05f005fc, 0x05d005de, 0x059405ba, 0x0530055a, 0x04e80412, 0x04ba04cc, 0x049204a6, 0x045a0478, 0x042a0440, + 0x030a0414, 0x03da03f4, 0x03b403c4, 0x03740398, 0x03580362, 0x033a0348, 0x0212032a, 0x02e202f6, 0x02d402da, 0x02a002bc, 0x027c028e, 0x02400260, + 0x021c022c, 0x01f80104, 0x01c201d8, 0x019c01a8, 0x01700188, 0x015a0164, 0x012e013e, 0x0006011a, 0x00c600ea, 0x089800a6, 0x0006007d, 0x8219000e, + 0x00122601, 0x00c90321, 0x820d890f, 0x001424bb, 0x82130016, 0x821020dd, 0x821f2015, 0x00ca22ef, 0x201f8c11, 0x20e3821a, 0x2433821a, 0x001f0012, + 0x24f18220, 0x031d0016, 0x883782cb, 0x200b8251, 0x221b8221, 0x8223000e, 0x01192429, 0x86090012, 0x821d203f, 0x821d2007, 0x081f2213, 0x20138421, + 0x240b821f, 0x001c0015, 0x24478222, 0x002a0012, 0x20718407, 0x247f821b, 0x0614001b, 0x204782db, 0x8647820e, 0x860d840f, 0x41052077, 0x7d82058d, + 0x00ab0123, 0x28358205, 0x00100021, 0x00f40315, 0x820b870b, 0x8419202d, 0x21a5820b, 0x6d84a607, 0x17822384, 0xdd821c20, 0xdc061322, 0x1f823786, + 0x00e40523, 0x822b870c, 0x20ed831f, 0x260f821a, 0x07120014, 0x8c0a0043, 0x821f2019, 0x041d22ad, 0x22fd828c, 0x8221000e, 0x821f20bd, 0x20f7854b, + 0x8481830d, 0x002122bf, 0x205b84ee, 0x221f8223, 0x843a0720, 0x85232093, 0x205d82d3, 0x24238215, 0x0211001b, 0x20ed823d, 0x20d3840f, 0x22498222, + 0x823e021c, 0x220f83a3, 0x82190010, 0x00222663, 0x02260011, 0x8367823f, 0x00162213, 0x205d821b, 0x2405820e, 0x00120011, 0x200b8220, 0x220b8212, + 0x82460221, 0x221f853f, 0x8216001f, 0x231b8a31, 0x08008d04, 0x0d203d82, 0x71832d82, 0x02213782, 0x20118840, 0x243d8222, 0x0426001b, 0x223f868e, + 0x82240021, 0x0014223f, 0x217b8215, 0x07830016, 0xdd062122, 0x0f20b782, 0x1b851f82, 0x1f861920, 0xec022124, 0x7f820200, 0x03005d22, 0x0f228982, + 0xb5827400, 0x67841220, 0x69820e20, 0x13822020, 0x0d072122, 0x138e3582, 0x21077541, 0x55822207, 0x20221b85, 0xe7822100, 0xb582b783, 0x00030823, + 0x204f8407, 0x26138215, 0x0718001c, 0x82060075, 0x8210200f, 0x820e2091, 0x84e32027, 0x0012221d, 0x26138218, 0x0511001b, 0x820400e5, 0x21418209, + 0xd3821603, 0x83001521, 0x82202023, 0x001c262b, 0x00e60521, 0x20098211, 0x201f8212, 0x83a78219, 0x0016221b, 0x207f821f, 0x20c1821d, 0x24418210, + 0x001d0022, 0x200f82ef, 0x20218215, 0x2003821f, 0x2287840d, 0x8223000d, 0x00212479, 0x82130112, 0x8216206b, 0x82142043, 0x0021261b, 0x007e0820, + 0x2039820a, 0x20258211, 0x2a358215, 0x00220013, 0x08190019, 0x8a0c007f, 0x841b2015, 0x821a20c9, 0x08192287, 0x202f8c80, 0x22258424, 0x82ed0212, + 0x001626b1, 0x08160013, 0x821f8446, 0x204d8209, 0x20038204, 0x2235820f, 0x8a47081f, 0x87052015, 0xe7052115, 0x2b856584, 0x43431020, 0x00162606, + 0x0614001b, 0x840d82de, 0x8c2b824f, 0x220f8219, 0x8ce80706, 0x05714237, 0xcf821b20, 0xd3071924, 0x91820900, 0x05835185, 0x11001b24, 0x138a2401, + 0xc9821920, 0x18001026, 0x0800f702, 0x1c202788, 0x1322b782, 0x5982e907, 0x1d207187, 0x20247d82, 0x24002000, 0x1f262d82, 0xe8051100, 0x2d881400, + 0x1f001d22, 0x23054941, 0x21001000, 0x11207382, 0x26061f45, 0x00220021, 0x8a25011d, 0x221d83b7, 0x82150021, 0x431f2023, 0x0721051d, 0x90478a9e, + 0x2047821d, 0x835b8212, 0x061f225d, 0x876382df, 0x82299c8d, 0x24318335, 0x001b0022, 0x22698211, 0x82e00611, 0x84399b05, 0x760823ed, 0x93840a00, + 0x1d20bd83, 0x24206b82, 0x1f243582, 0x0600e106, 0x1c261586, 0xe9052400, 0x0d840800, 0xaf411220, 0x99072307, 0x2b820500, 0xe3821a20, 0xa3081b24, + 0x0b870700, 0x05241f82, 0x0c007607, 0x1c200f82, 0x10200b82, 0x1a201784, 0x1026f784, 0x77071200, 0x47410900, 0x1d002305, 0x15821f00, 0x20002026, + 0x0400cc03, 0x18221384, 0x37845e08, 0x18001f22, 0x15203982, 0x20216f82, 0x05374300, 0x12042622, 0x1c217f82, 0x84198500, 0x130421b5, 0x1c222b8a, + 0x29822200, 0xa1851920, 0x82480721, 0x222b85fd, 0x821d0020, 0x8277829f, 0x206f854f, 0x2423821a, 0x061a0022, 0x8ff382e2, 0x04202223, 0x20399293, + 0x203b8220, 0x22358213, 0x82190019, 0x041122af, 0x90058295, 0x8c238239, 0x60012183, 0x1f20e782, 0x1d207b82, 0x21201982, 0x25243182, 0xea052100, + 0x1f200f82, 0x1b22e982, 0x15821400, 0x20057d42, 0x20b7820e, 0x27138316, 0x0700eb05, 0x20002600, 0x24206982, 0x8a080782, 0x07420014, 0x07220734, + 0x06fa060a, 0x06c006d4, 0x069206aa, 0x065a0672, 0x0636064a, 0x05020618, 0x05ce05e4, 0x05b005c2, 0x0580059c, 0x054e0568, 0x05200538, 0x04f4040c, + 0x04c204de, 0x049c04b0, 0x0460047a, 0x042c0442, 0x03f2030a, 0x03c003d6, 0x038003a8, 0x03460360, 0x021a0334, 0x02e002fc, 0x02b202c8, 0x027a0290, + 0x02300254, 0x0106021a, 0x01ba01e8, 0x0172019a, 0x0020014c, 0x00d800f4, 0x00ac00c6, 0x07860098, 0x8208005d, 0x001022b5, 0x26978210, 0x0012001b, + 0x822f0820, 0x000e22d9, 0x240b821d, 0x0013000d, 0x2407821f, 0x00300812, 0x2025820c, 0x8323841d, 0x001f22db, 0x2401821c, 0x0520001a, 0x223f82e0, + 0x821f0012, 0x82132019, 0x00122403, 0x82bb0311, 0x82118cfb, 0x0513470f, 0x5d011f22, 0x20062143, 0x202b8221, 0x20518210, 0x221b8219, 0x8219000e, + 0x0014220d, 0x200b821b, 0x2255820f, 0x82210021, 0x011a2205, 0x202b9e5e, 0x20998210, 0x822b821b, 0x5f01216b, 0x07820b82, 0x16200d82, 0x5183c982, + 0x5d840d20, 0x85001621, 0x22518357, 0x8212061d, 0x20258fcf, 0x207b8211, 0x83378220, 0x000f22c1, 0x25098222, 0x00740812, 0x278f000f, 0x8d822020, + 0x11000e22, 0x20221782, 0xe9847508, 0x6d8c1f20, 0xc7821f8a, 0xd3821020, 0x20001c22, 0x11222d82, 0x89821704, 0x1d204d91, 0x2124f584, 0x0900dc02, + 0x0f224d82, 0x25821f00, 0x09822120, 0x1b001c26, 0x0a007b00, 0x6b830982, 0x11451c20, 0xd7062109, 0x17477d82, 0x20158705, 0x20a5841a, 0x2023820e, + 0x243d820f, 0x06180010, 0x971182d8, 0x82132023, 0x225d8363, 0x8ea50821, 0x8415205f, 0x0056227b, 0x20758c10, 0x20a1821c, 0x204f8219, 0x82e78410, + 0xff072139, 0x1320378c, 0x1f832d82, 0x0b007c22, 0x1920378a, 0x0f204b82, 0x19223582, 0x97825600, 0x19208b89, 0x1f24e588, 0xe1052600, 0x1b892582, + 0x2f822020, 0x65842120, 0x14001b28, 0xd9062000, 0x518a0c00, 0x19822020, 0x0f000e24, 0x25821900, 0x08005722, 0x10201988, 0x1a224382, 0x2b8a5800, + 0x0d281185, 0x13001c00, 0xaf011300, 0x63873382, 0x2b841420, 0x91821220, 0xd9470e20, 0x820c2008, 0x821f9a25, 0x2147842b, 0xdf84bc03, 0x24001222, + 0x14203d84, 0x1b2a8582, 0x0e001100, 0x0a00bd03, 0x0d821600, 0x1f221785, 0x63821f00, 0xbe032622, 0x2d85f584, 0x1f208f83, 0x22208d82, 0x12247382, + 0xbf031900, 0x1020498a, 0x192a1782, 0x1a002200, 0x3b021b00, 0x49881000, 0x1a201783, 0x1c209982, 0x21204f82, 0xf7845182, 0x6b892182, 0x26222187, + 0x1f82e507, 0x15888187, 0x1926a584, 0x3c022100, 0x558e0c00, 0x22052b45, 0x90e60721, 0x8719866f, 0xe707233b, 0x3b8c0900, 0x26002726, 0x0800c003, + 0xff821388, 0xc1201182, 0x1522eb8a, 0x8d821200, 0x19001122, 0x1b242382, 0x8b041200, 0x220a1d41, 0x841b0016, 0x081f2259, 0x0a014100, 0x2f821820, + 0x0f001b22, 0x03210583, 0x836f8ac2, 0x00202441, 0x8ac30321, 0x001a262b, 0x0011001c, 0x225d8222, 0x8ac40312, 0x821e2059, 0x82162013, 0x05212215, + 0x20ed8ae2, 0x06234220, 0x1f225b83, 0x478ac503, 0x21002024, 0xa9841f00, 0x01081a22, 0x2120bd8a, 0x1a203182, 0x7b831782, 0x12001b24, 0x8f8ac603, + 0x17822420, 0x18001224, 0xff844502, 0xcb821420, 0x45821220, 0x12002126, 0x05002107, 0x19263782, 0x0e001900, 0x9584c703, 0x0f207983, 0x16201384, + 0x26222382, 0xdd82c803, 0x8e001621, 0x07594215, 0x82dd0221, 0x821c2033, 0x8210202d, 0x000d2461, 0x82150010, 0x0421222d, 0x89058218, 0x001c2215, + 0x201d8223, 0x2133871f, 0x9982a500, 0x1a201d87, 0x19285d84, 0x07004508, 0x19001c00, 0x0e204182, 0x1c229d82, 0xf1825900, 0x22210f83, 0x22d38300, + 0x8211000d, 0x0024261d, 0x0042071b, 0x0875420f, 0x51821220, 0x09821786, 0x3d820e20, 0x5a002122, 0x1a22378e, 0xc5822200, 0x5b001222, 0xad42a784, + 0x22378305, 0x8213001c, 0x845c2001, 0x26158989, 0x041d0022, 0x861200dd, 0x841b2061, 0x00122239, 0x205d841f, 0x200d8210, 0x22c98216, 0x82200016, + 0x82a62093, 0x821d20af, 0x000d22a9, 0x222f8218, 0x82020826, 0x410f8a77, 0xde23081f, 0x85000800, 0x054b4717, 0xda061826, 0x1f000600, 0xe7851382, + 0x01132008, 0x01ac01b4, 0x01860194, 0x01560176, 0x01360148, 0x0006011e, 0x00c800e0, 0x008a00a2, 0x826c0080, 0x004024d1, 0x821f0828, 0x820d205f, + 0x82222081, 0x821b203b, 0x8219205d, 0x00132675, 0x00200821, 0x210d820c, 0x17870021, 0x4c001f21, 0x0520062f, 0x1a227983, 0x2f820f00, 0x19001222, + 0x0e220182, 0xed82e100, 0x0e001b22, 0x10221182, 0x27821500, 0x43822320, 0x0400de22, 0x1124c582, 0xb3021c00, 0x1b246182, 0x1c001300, 0x11202b82, + 0x20246186, 0xa1082000, 0x17922582, 0x11202182, 0x22202b82, 0x2105d544, 0x3d8eb402, 0x1b821a20, 0x12001f24, 0x3d8ea208, 0x3d8d1786, 0x84080621, + 0x821d203d, 0x820f20c5, 0x0016227d, 0x249f8220, 0x00110012, 0x201784b7, 0x22178420, 0x82100020, 0x821620b9, 0x0612266f, 0x000800d5, 0x220f821d, + 0x821a001c, 0x001b26c7, 0x00f30314, 0x20118206, 0x24dd8211, 0x06120021, 0x20258211, 0x213f821d, 0x0d82000e, 0x16226b84, 0x1b822000, 0x57825d83, + 0x00df0523, 0x202d8207, 0x204f8214, 0x2225820e, 0x84d60612, 0x8219203d, 0x210f82b3, 0x75828a04, 0x87821d20, 0x31821c20, 0x3d821120, 0x23062546, + 0x03002301, 0x0f224582, 0x3d820b07, 0x61822020, 0x0806a545, 0x0a6c00e3, 0x0a480a60, 0x0a340a3a, 0x09040a18, 0x09be09e0, 0x097c099c, 0x09520966, + 0x09360940, 0x091e092e, 0x08fc0816, 0x08d408ec, 0x089a08bc, 0x0862087e, 0x08300844, 0x07f4070c, 0x07ac07e0, 0x078c0796, 0x07700780, 0x074a0754, + 0x072c0740, 0x0610071c, 0x06f406fe, 0x06d406e8, 0x06b206be, 0x069e06aa, 0x06640686, 0x06320650, 0x05020622, 0x05e405f0, 0x05be05d2, 0x059405a2, + 0x055c057a, 0x0520053a, 0x04e8040e, 0x04b404ca, 0x047e0494, 0x044e046c, 0x042e043e, 0x03ee0314, 0x039c03c8, 0x0342036c, 0x02080324, 0x02d802f0, + 0x02ac02bc, 0x0280029a, 0x024e0260, 0x02260238, 0x0110021c, 0x01d801f6, 0x01bc01c4, 0x018801a6, 0x0164017a, 0x012c014e, 0x00000114, 0x03da00e2, + 0x000300ab, 0x030f000e, 0x820582ac, 0x0d002b07, 0x1b002200, 0x12002000, 0x03821900, 0x21001022, 0x11240582, 0x09009707, 0x22085b41, 0x820f000d, + 0x011f240b, 0x8a0b006a, 0x00102213, 0x260d8215, 0x0721001f, 0x8a100098, 0x001f2217, 0x204d8212, 0x22118221, 0x821f0022, 0x001b2605, 0x00d60521, + 0x26218c0a, 0x0024001c, 0x8cd70520, 0x00232215, 0x24398216, 0x00a60124, 0x222b8806, 0x86a70121, 0x209b83a5, 0x20ab8221, 0x20ab820e, 0x20578211, + 0x222d821c, 0x8aa80111, 0x201d8341, 0x222d821a, 0x84840410, 0x021422e1, 0x20c38431, 0x20358214, 0x82178313, 0x0420225d, 0x204f84e1, 0x200b8218, + 0x20f7821c, 0x06474221, 0x4d821b20, 0x14001b26, 0x0c00da02, 0x1d201f82, 0x0d246788, 0x19001d00, 0x26241182, 0x0500d805, 0x0e261984, 0xcc062000, + 0x0b820400, 0x18002026, 0x0800cd06, 0x31840985, 0xe9821920, 0x9184d920, 0x4f822520, 0x19820d20, 0x1f24b583, 0x72072100, 0x12202782, 0x12224982, + 0xbb821400, 0x1a000e26, 0x0f008407, 0x1a208382, 0x12205f84, 0x0f203d82, 0x11248d82, 0x15001100, 0x20203982, 0x85203182, 0x12218982, 0x831f8900, + 0x821b2017, 0x0722221f, 0x204b84fe, 0x221b821f, 0x831b0016, 0x86022363, 0x4b820700, 0x59841f20, 0x07211382, 0x234f82a4, 0x00250012, 0x1222dd85, + 0x19821000, 0x29821220, 0x12002026, 0x0b006701, 0x1b852b82, 0x16001322, 0x19200b82, 0x20225582, 0x178cdd00, 0x31821c20, 0x31821a20, 0xa5072122, + 0x5b824b8a, 0x04214b8b, 0x8721820a, 0x001f2267, 0x436f821c, 0x2226079b, 0x0b041d00, 0x69881400, 0x39461d8d, 0x086b4b05, 0x000c0423, 0x20299217, + 0x20518216, 0x207d821b, 0x22e5820e, 0x82190014, 0x06174621, 0x000d0423, 0x832fa415, 0x820e2085, 0x87a39129, 0x2051875b, 0x20259c0f, 0x2489841b, + 0x00da0512, 0x2077880c, 0x22958220, 0x821d0016, 0x82122001, 0x00a422f7, 0x26198607, 0x001a0020, 0x88320220, 0x0022280f, 0x0412001f, 0x840e00d9, + 0x051f41b3, 0x9f4e1f20, 0x00122808, 0x03260011, 0x8c0800ad, 0x0620241d, 0x840a00ce, 0x821f2011, 0x431c204d, 0x2124064d, 0x0f00cf06, 0xdd521591, + 0xae032109, 0x22203584, 0x0f203382, 0xdb861582, 0x841c0321, 0x84158e7b, 0x00192435, 0x82850421, 0x001521b7, 0x1c221d91, 0x01821300, 0x2205c342, + 0x84af0321, 0x262587a1, 0x031d0022, 0x820c001d, 0x88118a8b, 0x00862251, 0x8d199010, 0x8ab0204d, 0x82202091, 0x894f8237, 0x430821af, 0x1b225986, + 0x9b821100, 0xfd841f20, 0x1f001c34, 0x73071a00, 0x16000600, 0x21001800, 0x18001c00, 0x3382db02, 0xeb821620, 0x07821220, 0x0d221183, 0x2f821900, + 0x23000e28, 0x33021200, 0x39490900, 0x000e2208, 0x2243821d, 0x82f20312, 0x202f85c3, 0x201b8219, 0x2225821b, 0x86050036, 0x021f2225, 0x201d8834, + 0x264f821f, 0x06030004, 0x870f00d0, 0x5111851d, 0x19200663, 0x23052545, 0x07003502, 0x06221f8a, 0xd582d106, 0x1f205f85, 0x06202982, 0x37202d8e, + 0x33499188, 0x41072308, 0x41821000, 0x0d209d83, 0x1b203b82, 0x0d22ef82, 0xad822200, 0x0d821120, 0x65822120, 0x2e082024, 0x21820b00, 0x0b821f20, + 0x83000d21, 0x841d2005, 0x011f2263, 0x20b98469, 0x29f18321, 0x0300b103, 0x10001c00, 0x1382b203, 0x43821c20, 0x26000e26, 0x0a008704, 0x14221382, + 0x21831400, 0x1c268982, 0x13001300, 0x83828804, 0x13821c20, 0x1b221589, 0x35847407, 0x61821820, 0xb3031b24, 0x35820400, 0x19001926, 0x08003802, + 0x1b200982, 0x19206d82, 0x21247f82, 0xdb052600, 0x1d202784, 0x10220d82, 0xf9825c08, 0x8f821c20, 0x11241f83, 0xe3031c00, 0x22205784, 0x1520cd82, + 0x0e266b82, 0x1d001d00, 0x4b84dc05, 0x1f002224, 0x0984a901, 0x20002624, 0x1d82b403, 0x53821f20, 0x18001022, 0x10220982, 0x0b821500, 0x8f821b20, + 0x20001224, 0x53828702, 0xa7821b83, 0x02216383, 0x836f8292, 0x0016240f, 0x8293021b, 0x220b8341, 0x8289081a, 0x220983d7, 0x4820001b, 0x02230939, + 0x82190094, 0x000e218d, 0x13201583, 0x1f20c982, 0x24205d82, 0x1520b784, 0x1b200582, 0x0d209384, 0x21203182, 0x2109cb4e, 0xb3823902, 0x13204987, + 0x1f26eb82, 0x20071a00, 0x47880b00, 0x47821420, 0x81421b20, 0x9b022105, 0x2b870782, 0x21001622, 0x12204f82, 0x21206b82, 0x12226984, 0x63822500, + 0xb5032122, 0x19204f8a, 0x12226784, 0x0782d206, 0x23203783, 0x19202982, 0x25213584, 0x05834800, 0x12001f24, 0x1182b603, 0x49820782, 0xa5841120, + 0x03431420, 0xb7032109, 0x13201b92, 0x0e22e582, 0x1b822100, 0xa5821020, 0x37898183, 0x61821b20, 0x99822220, 0x19226d83, 0xc784b803, 0x2224218d, + 0x9d021d00, 0x16201784, 0x0d208382, 0x1622f184, 0x79831400, 0x00b00823, 0x20518207, 0x205f821c, 0x24478219, 0x005d0826, 0x220f840c, 0x820f0022, + 0x00122413, 0x82150020, 0x001c262f, 0x00d30621, 0x22198203, 0x82440826, 0x00202431, 0x821b0022, 0x001a24e1, 0x82dd0516, 0x00212617, 0x003a0226, + 0x24158404, 0x00d40612, 0x20098408, 0x203d8214, 0x24558221, 0x0019081b, 0x08d14a09, 0x13266783, 0x1a082100, 0xe54a0a00, 0x1b082111, 0x22207782, + 0x1b226782, 0x3d820d00, 0x63821520, 0xb3841f20, 0x1c223587, 0x35881000, 0x0e209b83, 0x1d202b82, 0x274b2b82, 0x1d082108, 0x1920218c, 0x1420e582, + 0x2120c382, 0x220a634b, 0x8a11001e, 0x88218b43, 0xb9032145, 0x1220b188, 0x0d202d82, 0x1b224582, 0x4382ba03, 0x13889b85, 0x1b301182, 0x21001c00, + 0x0200aa01, 0xf6022300, 0x23000600, 0x1c2a1382, 0x13001300, 0x0b008904, 0x1d822400, 0x05820d20, 0x12001522, 0xc5830182, 0x8a081f22, 0x26202182, + 0x1220d582, 0x1d20e384, 0x10201782, 0x1a205f82, 0x5c0a0782, 0x2223011b, 0x223e2262, 0x21e42122, 0x217e21ac, 0x21502164, 0x21222134, 0x20042118, + 0x20d020ea, 0x209c20b8, 0x2048207e, 0x1ffc1f1a, 0x1fd01fe2, 0x1f981fb0, 0x1f641f7a, 0x1f301f46, 0x1efa1e24, 0x1ec41ed8, 0x1e801e96, 0x1e4c1e6a, + 0x1e201e3c, 0x1dea1d10, 0x1da41dbc, 0x1d7c1d88, 0x1d5a1d68, 0x1d2a1d3e, 0x1cfa1c0e, 0x1cb81cea, 0x1c7c1c88, 0x1c4a1c6a, 0x1c261c34, 0x1bfe1b10, + 0x1bdc1bf2, 0x1ba61bb2, 0x1b721b96, 0x1b501b5a, 0x1a081b34, 0x1aae1ada, 0x1a741a80, 0x1a541a68, 0x1a1c1a36, 0x19dc1908, 0x19ba19c4, 0x199c19ac, + 0x19521976, 0x1924193c, 0x18f21816, 0x18ba18d6, 0x188618a0, 0x184a1860, 0x17041822, 0x17c817e8, 0x178c17a4, 0x174e176c, 0x160c1730, 0x16d616ec, + 0x16bc16c8, 0x168e16a4, 0x16661682, 0x16261642, 0x15fa150a, 0x15b415d8, 0x15781598, 0x155c1564, 0x15301546, 0x14081514, 0x14e014fa, 0x14bc14d8, + 0x149a14b2, 0x1470147a, 0x14421458, 0x14181432, 0x13ec130a, 0x13c413da, 0x13a013bc, 0x1374138a, 0x13461360, 0x1210132a, 0x12d812ec, 0x12aa12c6, + 0x127a1296, 0x125c1272, 0x121a1238, 0x11f61108, 0x116411c0, 0x100c112c, 0x10a410c4, 0x10521076, 0x0f06102e, 0x0fae0fdc, 0x0e280f80, 0x0e9c0ed0, + 0x0e400e68, 0x0de80d14, 0x0dc20dcc, 0x0d900da6, 0x0d720d80, 0x0d4a0d5c, 0x0c060d34, 0x0cca0cea, 0x0ca00cb0, 0x0c800c8e, 0x0c5e0c76, 0x0c400c50, + 0x0bfc0b22, 0x0bda0bf0, 0x0ba40bc2, 0x0b500b72, 0x0a120b30, 0x0ad00af4, 0x0a7c0aa4, 0x09180a4a, 0x09c609ea, 0x098809a4, 0x093a0960, 0x08de080a, + 0x089e08b0, 0x085a088c, 0x07f20722, 0x07a607ca, 0x07600778, 0x07340750, 0x06fc0614, 0x06b606de, 0x068a0694, 0x065e0680, 0x06380648, 0x05de0508, + 0x05ac05be, 0x05880596, 0x05560572, 0x05400546, 0x04000526, 0x04d004ea, 0x047c04a4, 0x0432045c, 0x03dc0308, 0x03ba03c6, 0x039c03aa, 0x0372038e, + 0x03460360, 0x032a0336, 0x0200031a, 0x02de02f0, 0x02b802d4, 0x029002a4, 0x02620280, 0x00520848, 0x000e000c, 0x00120013, 0x00260021, 0x0010000d, + 0x240b8215, 0x06180010, 0x8b1782a8, 0x00112119, 0x2005054f, 0x241f8211, 0x0000071f, 0x221f8207, 0x82190016, 0x001b2615, 0x00f70514, 0x200f8209, + 0x200d821b, 0x20038221, 0x21238327, 0x13848402, 0x0b822120, 0x27841920, 0x07210982, 0x206382c8, 0x206b820e, 0x20118212, 0x202d8419, 0x08c34f12, + 0x0400d922, 0x23204382, 0xe9222f82, 0x09860800, 0x21065d48, 0x6f84e207, 0x11831b83, 0x97042022, 0x0f83b784, 0xf75d1120, 0xa906210d, 0x162c2986, + 0x14001b00, 0xe3072000, 0x10000500, 0x19244d82, 0xa0011200, 0x0b831b82, 0x1b821b20, 0x1f001224, 0x45826d01, 0x21200f83, 0x1f209184, 0x1d204982, + 0x1c249782, 0x8a032100, 0x0b418182, 0x06bb5105, 0x41900421, 0x1186081d, 0x1b267786, 0x01071100, 0x63820600, 0x12001528, 0x0e001a00, 0x0d861403, + 0x1c001c26, 0xb8051900, 0x16207384, 0x1b201b82, 0x12222382, 0x8f846e01, 0x1f001c28, 0x2b081200, 0x13820a00, 0x00210b84, 0x202d820f, 0x2415820e, + 0x00140111, 0x82158215, 0x2033841f, 0x2291840d, 0x82180010, 0x8219206f, 0x001b24c7, 0x82200011, 0x000e221f, 0x20d1821d, 0x20e38215, 0x20358210, + 0x202b9012, 0x204f821d, 0x06ef451f, 0x21001624, 0x29981601, 0x2009794b, 0x22338216, 0x8217011b, 0x8e538b8b, 0x5308231f, 0x9f8c1300, 0xe74c1f8e, + 0x8eb92008, 0x822020c7, 0x20e183a3, 0x20178210, 0x20c5820d, 0x20c78212, 0x20a18218, 0x22c9821c, 0x8c0c00ae, 0x82202053, 0x242b8323, 0x00aa0612, + 0x83198a0a, 0x001c2417, 0x825b0821, 0x86a3894b, 0x20798215, 0x20c1831a, 0x82ef8200, 0x081f2207, 0x2055842c, 0x20cf8222, 0x421b820e, 0x1b2c07c1, + 0x7c041400, 0x11000200, 0x0700d202, 0x0d208782, 0x0e265f82, 0x11001f00, 0x2584ab06, 0x0d820f88, 0x19000e24, 0x1b821200, 0x18012122, 0x11208782, + 0x20201182, 0x1f2ab184, 0x14000e00, 0x8b031200, 0xd5890600, 0x82ba0521, 0x82122023, 0x821f2019, 0x82152051, 0x001c282b, 0x01130013, 0x820800a1, + 0x00102223, 0x26478222, 0x00210016, 0x82ac0626, 0x82122091, 0x82118823, 0x0022212b, 0x2208b950, 0x8200ad06, 0x821f995b, 0x8214202d, 0x821c20df, + 0x00ae22b1, 0x8d5b8d17, 0x200d8249, 0x0bcb5f24, 0x82190421, 0x821220f1, 0x821a205d, 0x821b2035, 0x84da208b, 0x06af4ab1, 0x1922ef86, 0x7b82bb05, + 0x19001222, 0x0d24bd82, 0x1a001600, 0x1f209982, 0x23206f82, 0x37863382, 0x00af0623, 0x06d74304, 0x0984db20, 0x11001b24, 0x35849204, 0x1b4f0982, + 0x0c75520a, 0x009d0723, 0x85358213, 0x00212121, 0x2005094b, 0x06154d0d, 0x1b001224, 0x13822000, 0x1b001c24, 0xb382f805, 0x20059b48, 0x20a3820d, + 0x06d7411c, 0x1d820f20, 0x0523a982, 0x820b00bc, 0x222d8333, 0x821f001c, 0x8211201b, 0x2309829b, 0x0f007208, 0x1c20178c, 0x10228f82, 0xbd822200, + 0x17821620, 0xbd051122, 0x65852b82, 0x24203785, 0x8b834f82, 0x24001c26, 0x07000207, 0x20223b8a, 0x638c0307, 0x51572020, 0x82172008, 0x05d94933, + 0x1b20bd85, 0x0d229f82, 0x15821100, 0xbd822020, 0x0d820e20, 0x07821620, 0x25841320, 0x18031122, 0x2d911982, 0x200d8949, 0x06134119, 0x85070f41, + 0x00202151, 0x00234b8e, 0x841700b9, 0x20279fa1, 0x2539820d, 0x03210019, 0x6783001a, 0x91841b20, 0x8206b541, 0x822320c5, 0x001f2243, 0x081b5326, + 0x03236790, 0x9218001b, 0x90378967, 0xbe052331, 0x31820800, 0x53822120, 0x07821a20, 0x19000e24, 0x11868c03, 0x45002121, 0x06210685, 0x200982b0, + 0x888b8212, 0x222d8211, 0x8210000e, 0x00122201, 0x0f655620, 0x008d0323, 0x0d575915, 0x1d262d84, 0x19001d00, 0x33821600, 0x2508995c, 0x8e032000, + 0x2b901700, 0x83000f21, 0x0018225b, 0x22318222, 0x821f000d, 0x07b5431f, 0x8f031222, 0x898f0d82, 0x57820f20, 0x17822220, 0x1c002122, 0x21260182, + 0x91031500, 0x55921300, 0x2108f749, 0x53841b00, 0x90032022, 0x4d8f9982, 0x19431020, 0x83438205, 0x82212009, 0x060541f5, 0x83087541, 0x000e26c7, + 0x00920326, 0x83659011, 0x8215204d, 0x841f2015, 0x03212263, 0x12394193, 0x1d204f83, 0x2120dd82, 0x0e205182, 0x21202782, 0x1b202f82, 0x0e240782, + 0x18009403, 0x2d8b5190, 0xdf821020, 0x1d001a22, 0xc1830582, 0x21001b24, 0x31a89503, 0x89822020, 0x03216982, 0x121b4196, 0x1520638b, 0x1a24d582, + 0x97031600, 0x8b12c541, 0x00202227, 0x20518223, 0x22af8211, 0x4198031c, 0x1c201209, 0x122c1f82, 0x20001f00, 0x0e001000, 0x99031b00, 0x6b410582, + 0x821d200f, 0x821c2063, 0x031222f9, 0x231d949a, 0x0024001c, 0x03234382, 0x410f009b, 0x1f201017, 0x1a231182, 0x82001c00, 0xb10621d3, 0x5b8f6382, + 0x22002024, 0x01821400, 0x81821220, 0x19012122, 0x22122741, 0x4c260020, 0x1a2206bb, 0xc1820d00, 0x0f820e20, 0xb1821120, 0x8b821220, 0x9c031a22, + 0x23209192, 0x16206f82, 0x08236b83, 0x820b003f, 0x6223207f, 0x102008fd, 0x19261982, 0xa0081100, 0xd3820a00, 0x1d000e22, 0x0d241982, 0x16001900, + 0x1522dd84, 0x15840500, 0x12001f24, 0x19820407, 0x5b821520, 0x21841f20, 0x6f820e20, 0x25821f20, 0x11822320, 0x85821920, 0x0b822120, 0x12001a24, + 0x0f82b206, 0xd15f2589, 0xaf08230e, 0x4f820700, 0x5f821220, 0x20248183, 0x06007d04, 0x16200f82, 0x83825182, 0x82820721, 0x8215209b, 0x201f8347, + 0x20538211, 0x269b821a, 0x031b001c, 0x8204009d, 0x001c2425, 0x84b3061d, 0x8209822f, 0x0305241d, 0x8508009e, 0x247f8417, 0x071c0024, 0x835f846f, + 0x0016281f, 0x05260013, 0x860c00bf, 0x841d2021, 0x821420d1, 0x820f2029, 0x031424a1, 0x940f009f, 0x00202219, 0x228d8218, 0x82a00321, 0x82152029, + 0x001d217f, 0x10203989, 0x2122fd84, 0x4b82fb07, 0xad491b96, 0x82102008, 0x001c2847, 0x01210022, 0x840a0066, 0x001f2269, 0x09f96021, 0x86b40621, + 0x201583bb, 0x21278310, 0x2786fd02, 0x81502420, 0x211b8208, 0xf186b506, 0x95822420, 0x4f001f22, 0x2220df84, 0x1326db82, 0x12001900, 0x33847e04, + 0x39820f88, 0x1b001c24, 0xbb844d02, 0x6f822220, 0x35842120, 0x20000d22, 0x1220c582, 0x11240b82, 0x0400f905, 0x9d82bd82, 0x82400821, 0x00162425, + 0x821b0014, 0x82192007, 0x821b20d9, 0x8222200b, 0x00142407, 0x82c00512, 0x201b85b1, 0x2267820e, 0x8210000d, 0x8219203b, 0x82222009, 0x000e2203, + 0x2031821f, 0x06494103, 0x1a011f22, 0x07202ba0, 0x2a202b88, 0x579db982, 0x21226f83, 0x67824108, 0x436527a2, 0xa842200c, 0x87052033, 0xb606248f, + 0x9d002b00, 0x00102467, 0x821b001c, 0x00122801, 0x00210010, 0x82110012, 0x821b203b, 0x820d2013, 0x841b2037, 0x841f2011, 0x4121201d, 0x1b200c13, + 0x3f4157cc, 0x821c2009, 0x85af9d75, 0x8220209b, 0x061a2227, 0x222da4b7, 0x820e0011, 0x010e24c7, 0x4114001d, 0x1b281e0b, 0x19002200, 0x1e011900, + 0x2020c541, 0x2421821c, 0x00c10513, 0x20518c11, 0x200d8224, 0x21038213, 0x3d42000d, 0x981f2009, 0x83f58923, 0x89f58bcd, 0x20238847, 0x08af4c00, + 0x00b80623, 0x2075960f, 0x24e9820f, 0x00b90611, 0x411f9623, 0x07222beb, 0x67982101, 0x0623fd84, 0x961b00ba, 0x00202267, 0x24898221, 0x00220021, + 0x43438220, 0xc988054f, 0x00bb0623, 0xac37aa2d, 0xbc0623b3, 0x5baa1a00, 0x2306ef41, 0x0800fc07, 0x1d223586, 0xb3821c00, 0xa2012122, 0x1a211184, + 0x08b34c00, 0x82d30221, 0x821620d1, 0x14c54c5d, 0x00bd0623, 0x8a418211, 0x0951542f, 0x82190021, 0x000e2653, 0x00c70411, 0x2023820a, 0x0819561b, + 0x12000f28, 0xbe061100, 0x15820300, 0x05071d22, 0x18203182, 0x21206382, 0xb34e1582, 0x282f8608, 0x00090050, 0x00160018, 0x2023821d, 0x241f821b, + 0x00210025, 0x852f8451, 0x001d2213, 0x2015821f, 0x26218223, 0x0022001c, 0x82060720, 0x821920bd, 0x84112011, 0x001b2495, 0x822c0214, 0x82192041, + 0x8211201f, 0x00202815, 0x001c0015, 0x82730024, 0x209b831d, 0x47498224, 0x162005af, 0x1b201782, 0x3f480d82, 0xc2052308, 0xf3820c00, 0x5f820e20, + 0x17822120, 0x45000f21, 0x1c240573, 0xbf061b00, 0x19873584, 0x5b821120, 0x1d002022, 0x0e24eb82, 0xc0062600, 0x2021358c, 0x08514e00, 0x82c10621, + 0x821a2087, 0x072b46e5, 0x26001c26, 0x0a00a301, 0x77486388, 0xf1042108, 0x1c201584, 0x1220f782, 0x13206982, 0x1222e184, 0x7584f204, 0x16241583, + 0x14001b00, 0x1f200d82, 0x1c20b382, 0x20243f82, 0x0300d402, 0xd5200784, 0x20203984, 0x0e203584, 0x19289782, 0x11001200, 0x08007007, 0x0e223182, + 0x8d821d00, 0x81821520, 0xc3052122, 0x1b200582, 0x1d201f82, 0x12211382, 0x20df8300, 0x224b8213, 0x82110019, 0x001f242f, 0x82060052, 0x821c202f, + 0x00272411, 0x82070712, 0x821b20d1, 0x5024200b, 0x9b41094f, 0x59072305, 0x27840700, 0x0f862420, 0x7d820820, 0x1a202985, 0x0f232f82, 0x82001600, + 0x0907237f, 0x25860b00, 0x15002022, 0x12201782, 0x05232d85, 0x820400c4, 0x2195820d, 0x5984c206, 0x17821020, 0x41059146, 0x21200551, 0x1024a384, + 0x73081200, 0x1c204182, 0x69089d46, 0x002108b3, 0x204184dc, 0x20bf821f, 0x20f1825f, 0x08a9411c, 0x0d822620, 0x1d214983, 0x23ed8200, 0x03005408, + 0x20226782, 0xc7825207, 0x22001c24, 0x1d821d00, 0x6b821820, 0x10002122, 0x12241f82, 0xc5051b00, 0x1983ef82, 0x11821f20, 0xc6051224, 0x2f820500, + 0x55822220, 0x5a071522, 0x2008e968, 0x24538415, 0x0012001a, 0x243b821f, 0x050e0010, 0x20ed82c7, 0x204f821c, 0x20458221, 0x2617820d, 0x0020000e, + 0x8cc80521, 0x82242015, 0x21158217, 0x8382f304, 0x0e001d26, 0x09005b01, 0x0e207f82, 0x596a6783, 0x82292008, 0x09b769fd, 0xf5821120, 0x51822020, + 0x21080743, 0x29825508, 0x21201f83, 0x20081f41, 0x2075820e, 0x240d8211, 0x0056081c, 0x924f8411, 0x2635821b, 0x0013001c, 0x82570813, 0x203f8d6d, + 0x83c38221, 0x41182083, 0x01230589, 0x820700a4, 0x82122045, 0x82182079, 0x011f22af, 0x887184a5, 0x200d820f, 0x06995714, 0xa1031d22, 0x1b201b90, + 0x2305ef4a, 0xfa032000, 0x378b8d84, 0xb1631b88, 0x909e2008, 0x09f7423f, 0x05007f22, 0x12268784, 0xa2031100, 0x0b840a00, 0x19001922, 0x1520bf82, + 0x10269782, 0xc3061800, 0x15820b00, 0x2005e553, 0x095b4320, 0x84710721, 0x001c2839, 0x04120018, 0x820600b5, 0x821c2023, 0x002124b1, 0x84c90520, + 0x410d8647, 0x04230773, 0x890f00ca, 0x20158623, 0x28638220, 0x000e000f, 0x04190019, 0x8dc984ab, 0x83202035, 0x2100215d, 0x23853982, 0x2b82ac20, + 0x20071153, 0x20438220, 0x20718210, 0x82938216, 0x21002383, 0x1d8ead04, 0x20001222, 0x04217189, 0x227f8eae, 0x821c0013, 0x205b8901, 0x89e784af, + 0x8214207f, 0x0019241d, 0x8e2d0813, 0x00142697, 0x001a0026, 0x206b821b, 0x83998220, 0x0420227d, 0x205b8eb8, 0x201d8215, 0x8737821b, 0x82b020db, + 0x20b78bab, 0x205b8215, 0x22db8410, 0x8eb90426, 0x821820b5, 0x2037830f, 0x243f8211, 0x00ba0716, 0x0c354113, 0x1d821a20, 0x77841f20, 0x19000e22, + 0x11455582, 0x04202205, 0x0e7341b1, 0xa3821a20, 0xb2040e24, 0x3d8e1200, 0x3b821c20, 0x1941e383, 0x00b3220b, 0x24258c0c, 0x0022001f, 0x22d18214, + 0x8ec40626, 0x00202219, 0x24b98210, 0x0412001f, 0x20d18eb4, 0x20d18420, 0x226f8210, 0x8eb7041f, 0x8221201b, 0x001b2815, 0x0016001b, 0x41b60420, + 0x23200e4d, 0x19203782, 0x1222c982, 0xe5412600, 0xc9072507, 0x1e000600, 0x0e218382, 0x22698300, 0x890b00c8, 0x2059820d, 0x05b74113, 0x82e40721, + 0x822020f1, 0x4b112053, 0x04210bdf, 0x225f8280, 0x820e0021, 0x821820a7, 0x201b8375, 0x200d820f, 0x0c034c1f, 0x19820720, 0x1920238d, 0x1b204782, + 0x0d201582, 0x15203782, 0x21252f84, 0x0700fd07, 0x20258300, 0x241b8211, 0x051a0022, 0x839582ca, 0x8216200f, 0x03202495, 0x84040022, 0x071f221d, + 0x839f820e, 0x22638317, 0x821c000f, 0x8211201d, 0x061f2449, 0x851500c5, 0x8a7b8221, 0x220d8217, 0x8222001d, 0x001d2225, 0x28278219, 0x00030008, + 0x00230303, 0x832b8809, 0x0019267f, 0x000f0713, 0x6d13880c, 0x06210cf9, 0x20a182c6, 0x83038221, 0x214b9071, 0x4b8acb05, 0x29841f20, 0xa3031224, + 0x4b860500, 0x89072021, 0x0021220b, 0x83db829f, 0x82262049, 0x84102095, 0x821f2095, 0x821b2093, 0x820d202b, 0x000e219d, 0x210ca556, 0xd186a000, + 0xa7562d93, 0xa100210e, 0x1d20598a, 0x1622ed82, 0xb1841a00, 0xff563b83, 0xa2002110, 0x2d8f598a, 0x0521598e, 0x20ab82cc, 0x235d8221, 0x00180010, + 0x1b244d83, 0x21001c00, 0x0d20b582, 0x5322e382, 0x0b820400, 0x1d001c26, 0x0b00cd05, 0xd9840985, 0x81821620, 0xd1821020, 0xaf001224, 0x17881100, + 0xab562020, 0x22012315, 0x1d560700, 0x82a4200c, 0x82212059, 0x001f2665, 0x00850212, 0x201b8614, 0x83598212, 0x821920d3, 0x820d2057, 0x20638355, + 0x85518212, 0x04262429, 0x880a0098, 0x82132029, 0x001c267f, 0x0621001b, 0x244b88c7, 0x0018081a, 0x22218208, 0x740e001f, 0x2d20080d, 0x118a3384, + 0x1b24d782, 0x06008104, 0x12202784, 0x1a222982, 0x23869002, 0x1b821220, 0x23002122, 0x12263b82, 0x5c012400, 0x23840f00, 0x18001622, 0x15201784, + 0x22207184, 0x1520ad82, 0x2022a782, 0x6b86ce05, 0xad821c20, 0x21821920, 0x2e021f22, 0x26208984, 0x12260f82, 0x1700b602, 0x41822200, 0x4d821120, + 0xc589e582, 0x20066144, 0x20fd821f, 0x09535d24, 0x82b70221, 0x532fa365, 0x03230869, 0x840700a5, 0x82172061, 0x0010267b, 0x00cf0521, 0x0c176809, + 0xbd821d20, 0x61826f20, 0x20205583, 0x39837f82, 0x13821d20, 0x79821620, 0x20001b24, 0x2f865400, 0xa1822120, 0xb3832120, 0x05200023, 0x8a2f86d0, + 0x08b96913, 0x06009122, 0x24265f84, 0x26000e00, 0x3d84c806, 0x42001a21, 0x16260583, 0x12002700, 0xff825b07, 0x1b002222, 0x26220182, 0x49845c07, + 0x09820b84, 0x13822020, 0x24001c22, 0x1b266982, 0xd1051400, 0x49820b00, 0xb7821d20, 0x87821f20, 0x86001021, 0x09042199, 0x22211f82, 0x20178500, + 0x200b8223, 0x20218220, 0x09697011, 0x210d7742, 0x1d82a603, 0x1c202d8d, 0x0d204982, 0x10209d82, 0x1c20ed82, 0x1b266182, 0xd2052100, 0x09820700, + 0x55821d20, 0x21221d83, 0x4f84d305, 0xff6d0f88, 0x0721220a, 0x222b840a, 0x8513001f, 0x550021a7, 0x22204b82, 0x1f225382, 0x4d841c00, 0x2d821120, + 0x0b882020, 0x0a00a322, 0x0e20d182, 0x0d205982, 0x0e226f82, 0x01821900, 0xa7032022, 0x1520158a, 0xdb832b82, 0x03042722, 0x24205182, 0x1d204d82, + 0x15884182, 0xa1821d82, 0x19201582, 0xa822d98e, 0x59880900, 0x12002322, 0x21228182, 0x6382a903, 0x13864187, 0xa922358e, 0x358f1400, 0x10207582, + 0x04235f91, 0x82050082, 0x82162029, 0x071222b9, 0x84af84ca, 0x09f14c0b, 0x82cb0721, 0x82242035, 0x821d203d, 0x000d217d, 0x210e536c, 0x338ccc07, + 0x23821920, 0x21001324, 0x338ccd07, 0x53821586, 0x19000e22, 0xce221d82, 0x73870b00, 0xc5421382, 0xcf072308, 0x17930f00, 0xd0223788, 0x1f8a0800, + 0x1d002226, 0x0c00d107, 0x2b88118d, 0x818cd220, 0x210e2967, 0xcf825307, 0x314b2420, 0x07274208, 0x20001222, 0x0d200182, 0x97410382, 0x00212405, + 0x82220010, 0x005422af, 0x8365841a, 0x05354b0f, 0x19821020, 0x81842d96, 0x11001124, 0x81868304, 0x1c20358d, 0x1b245182, 0x2f022100, 0x21085b63, + 0x53830010, 0x2d821020, 0x12001a28, 0x0e001f00, 0x1f41d405, 0x41398706, 0x0521063f, 0x87ed86d5, 0x08394117, 0x8e300221, 0x08f34d19, 0x00830727, + 0x00260009, 0x245d821b, 0x001c0014, 0x247d8214, 0x00d60212, 0x24138404, 0x009e0410, 0x70098508, 0xd7200855, 0x26220982, 0xdf821b00, 0x20057545, + 0x22398220, 0x8219000f, 0x07112299, 0x204b86bb, 0x09bf5010, 0x82d80221, 0x202f8779, 0x21bd821d, 0x2d85001c, 0xc9061a24, 0xf9551600, 0x5b20200c, + 0x06211b83, 0x567382ca, 0x2d9c0b27, 0xcd837f82, 0x11001c26, 0x1e00cb06, 0xe95b65a9, 0xd902210f, 0x2022ed84, 0x9b822100, 0x155c1a20, 0xaa03230d, + 0x598c1100, 0x410a7b5c, 0x2382072d, 0x239a1020, 0x0021c608, 0x095f0023, 0x098609ae, 0x09580970, 0x0946094e, 0x092a093c, 0x090e091c, 0x08e40802, + 0x08a208c2, 0x08700888, 0x081a0846, 0x07de0700, 0x07c407d4, 0x077c07a6, 0x07440760, 0x071e0736, 0x06fa060a, 0x06ba06e0, 0x068a06aa, 0x065c0674, + 0x062e064a, 0x05f60514, 0x05b605e0, 0x059405a8, 0x055e0588, 0x0538054c, 0x04160524, 0x04e404fa, 0x04c204d0, 0x049a04aa, 0x04580470, 0x0318043a, + 0x03dc03f4, 0x039403b0, 0x036e0386, 0x033e035e, 0x03260334, 0x02040318, 0x02cc02f0, 0x029c02b8, 0x02720282, 0x0236025a, 0x02140222, 0x01ec0104, + 0x01c201d6, 0x018c01a8, 0x013e015e, 0x00f2001c, 0x00da00e6, 0x009f06c0, 0x0d595c0c, 0x0011002b, 0x0021000e, 0x00a0060e, 0x83098205, 0x001f220d, + 0x260b864a, 0x031c0016, 0x84140021, 0x500b8217, 0x6d560d65, 0x0012260c, 0x00200311, 0x24299810, 0x0013001c, 0x4b4b8213, 0x4b9305ab, 0x1b001c22, + 0x16204182, 0x22224198, 0x674d1b00, 0x12002509, 0x74041100, 0x0e268182, 0x19001600, 0x35822400, 0x0d842620, 0x19821920, 0x21001f24, 0xe782d704, + 0x1a000e22, 0x1b200d82, 0x11201782, 0x1b202582, 0x14240384, 0x09001208, 0x1a222d82, 0x17821d00, 0x13262d83, 0x13082100, 0x13880a00, 0x22098543, + 0x820b0082, 0x052d4915, 0x49821f20, 0x23063d48, 0x0700a106, 0x24201782, 0xd5843f82, 0x00a20623, 0x220f8806, 0x82af051b, 0x8412205f, 0x820d20c5, + 0x001c217f, 0x07233982, 0x82110028, 0x820e203f, 0x820d20a9, 0x00202207, 0x22578821, 0x8414000e, 0x082122a3, 0x226d82b3, 0x820f0012, 0x82202019, + 0x20278311, 0x22b18211, 0x82850321, 0x8212206d, 0x001222f9, 0x22b38216, 0x82b00521, 0x840f8ad9, 0x001c22c5, 0x2047821b, 0x850b824b, 0x05934a19, + 0x99480e20, 0x04202208, 0x79958475, 0x1b2409fd, 0xef031100, 0x13839584, 0x09821f20, 0x59000d21, 0xd98408a7, 0x85822320, 0xc7071f22, 0xb1833786, + 0x63821b20, 0x12001924, 0x13863907, 0x5f822620, 0x55411920, 0x6e072305, 0x2f820600, 0x47821120, 0x21001624, 0x0d868603, 0x13821220, 0xd2001a24, + 0x1b840400, 0xf6051c22, 0x1220df82, 0x22202382, 0x12203982, 0x10206582, 0x1d20ed82, 0x10210382, 0x23358200, 0xb2022600, 0x1322eb84, 0x2f821f00, + 0x15002026, 0x0b00a306, 0x12224184, 0x39841a00, 0x33821f20, 0x11821a20, 0x5f84d320, 0x1c001a22, 0x1222b382, 0xf784d400, 0x0d200d87, 0xc14a5b82, + 0x00d52209, 0x85418415, 0x201b8d29, 0x233f820d, 0x00210022, 0x1222c385, 0x6d867604, 0x11202b87, 0x1b201f82, 0x72203d82, 0x8183b182, 0x9f4a1787, + 0x821a2005, 0x001e2275, 0x821f8222, 0x77042103, 0x238b7582, 0x11208d83, 0x1f201b82, 0x2120dd82, 0x1f224782, 0x09822802, 0xe383218b, 0xb9841120, + 0x12002624, 0x7b8e5a08, 0x33821f20, 0x11000e26, 0x1400f803, 0x2020bf8c, 0x2010375a, 0x26578210, 0x0321001f, 0x820700d1, 0x08514d29, 0x84880821, + 0x851d2051, 0x1600211d, 0x22081d4a, 0x8206004c, 0x821d2027, 0x000e2603, 0x00780421, 0x590d8909, 0x002305c1, 0x900a004d, 0x04122213, 0x86ab8479, + 0x20298637, 0x20078612, 0x2053864e, 0x226d8219, 0x86640026, 0x260d8553, 0x0004000d, 0x8e650003, 0x82062013, 0x00662213, 0x87678408, 0x04082227, + 0x21ed847a, 0x1187001d, 0xb7821020, 0x10001f22, 0x69830f82, 0xf57b1320, 0xd6002309, 0x3b860500, 0xd7002622, 0x26205b88, 0x0e208f82, 0x19222d82, + 0x9186d800, 0x1f001c26, 0xa4062100, 0x0d845786, 0x14222382, 0xa9821a00, 0x57841620, 0x21821f20, 0x1f201783, 0x11224f82, 0xfb86e800, 0x1c262987, + 0x13001300, 0x2d828703, 0x21091b50, 0x1947000d, 0x0006220d, 0x423b820c, 0x2022050b, 0x5f822100, 0x2f821d20, 0x12001424, 0x0b82b105, 0x8b001221, + 0x200b8319, 0x2223821c, 0x847b0412, 0x822020fd, 0x82212039, 0x00212625, 0x00a50623, 0x081d440b, 0xcb86b582, 0x8e022122, 0x20209384, 0x0e223582, + 0xad822200, 0x1b000e28, 0x83022100, 0x51720f00, 0x20338211, 0x2615821a, 0x0322001b, 0x60070088, 0x04210b03, 0x200d8208, 0x08356e12, 0x24054f41, + 0x001c001f, 0x207d841a, 0x24b1821f, 0x03150020, 0x20cb84f9, 0x088b4d20, 0x0e26eb83, 0x12001400, 0x4f84a606, 0x27060345, 0xb2052000, 0x16000900, + 0x26082754, 0x0024001c, 0x829d0019, 0x821620c1, 0x8214209d, 0x05ab5053, 0x5f822220, 0x14081224, 0xc3510600, 0x08212208, 0x201d8215, 0x2039821c, + 0x20fb8618, 0x207b8219, 0x05dd4522, 0x84700821, 0x8219201b, 0x8212204b, 0x05bb49e9, 0x11000e22, 0x20222982, 0x87827108, 0x19821c20, 0x0d821920, + 0x27821f20, 0x2118c37b, 0x51822a08, 0x1820298d, 0x21211182, 0x219b8400, 0xc982b305, 0x1c001c24, 0x0f851300, 0x00890323, 0x240d8204, 0x051a001c, + 0x839582b4, 0x7e1a2019, 0x1320089f, 0x12206b84, 0x12259d84, 0xf0042000, 0xa9451800, 0x84202009, 0x4123201b, 0x02230505, 0x71150029, 0x0c220ceb, + 0x45820300, 0x23821120, 0x1f001422, 0x20067b41, 0x245f820d, 0x07240010, 0x46c98481, 0x2b970905, 0x2a022424, 0x558c0b00, 0x2106b146, 0x87842b02, + 0xb5464189, 0x16082308, 0x31820f00, 0xb1822220, 0xf3821120, 0x21200b85, 0x200aeb46, 0x91e38417, 0x2141881f, 0x3782f003, 0x18001c21, 0x8208b540, + 0x8210203b, 0x821f2051, 0x00122451, 0x5696071f, 0x1224087d, 0x06009f01, 0x21206b84, 0x1f22df82, 0x0d84f103, 0x55412420, 0xb1002505, 0x20000800, + 0x0d220182, 0xfd841300, 0xa7061124, 0x0f820400, 0x1d00232c, 0x03005f04, 0x21002100, 0x1182b505, 0x82002221, 0xb60521d3, 0x0984e782, 0x13206d82, + 0x19225382, 0x35821100, 0xb7051f24, 0x89840a00, 0x210cb945, 0x5382ff06, 0x8f822220, 0x099d4518, 0x21227583, 0x3d821500, 0x1f001222, 0x2606d143, + 0x00f10220, 0x82230009, 0x82152013, 0x001c2251, 0x08498218, 0x0f001d24, 0x82018c01, 0x44016c01, 0xf8001801, 0xd400e000, 0x9800b800, 0x64008000, + 0x30004400, 0xac052000, 0x3f820700, 0x1c206f83, 0x06218383, 0x20438210, 0x0603411f, 0x93821120, 0x05000d26, 0x0f00ad05, 0x1d82238b, 0x69002021, + 0x03210a63, 0x22118283, 0x82120022, 0x82262023, 0x820f2009, 0x82162077, 0x21d184e5, 0xe984fe06, 0x20211b87, 0x05c34100, 0x84032022, 0x33835382, + 0xe3731183, 0x0020220b, 0x21498324, 0x5386fa07, 0x1a221f8b, 0x63820e00, 0x48001824, 0x89460500, 0x49002107, 0x4b835f86, 0x1a000d22, 0x20221782, + 0x9d821600, 0x5f867120, 0x63451785, 0x821b2009, 0x8225205d, 0x009b2285, 0x22a78415, 0x86180010, 0x841b20ed, 0x8210209b, 0x82202005, 0x82112011, + 0x820e2045, 0x22b983c5, 0x9c13009c, 0x451a202b, 0x0523055d, 0x880a00ae, 0x451f2027, 0x062307af, 0x8404009e, 0x07272215, 0x20b7846d, 0x09c3821c, + 0xa9000e5b, 0x02131a13, 0xc412d412, 0xa012ae12, 0x6c128212, 0x42125212, 0xe2110c12, 0xae11ca11, 0x84119011, 0x52116c11, 0x24114211, 0xd6100611, + 0x9c10b010, 0x78108410, 0x54106610, 0x26103010, 0x04101610, 0xec0ffa0f, 0xbe0fd00f, 0x9a0fac0f, 0x5e0f7a0f, 0x020f360f, 0xc20edc0e, 0x8e0eaa0e, + 0x4a0e720e, 0x020e240e, 0xd40dea0d, 0xb20dbe0d, 0x860daa0d, 0x640d7a0d, 0x420d540d, 0x140d3a0d, 0xdc0cf00c, 0x880cae0c, 0x560c6a0c, 0x420c4a0c, + 0xe20b120c, 0x940bb00b, 0x540b7a0b, 0x160b300b, 0xf20afe0a, 0xb40ad20a, 0x7a0a980a, 0x460a5a0a, 0x120a2c0a, 0xde09f809, 0xa209c209, 0x68098609, + 0x1a094a09, 0xf208fe08, 0xd608e008, 0x9408ae08, 0x56087608, 0x12083a08, 0xd207f607, 0x9e07bc07, 0x60078807, 0x20073e07, 0xf8060a07, 0xd406e606, + 0xa806c606, 0x74068a06, 0x28065806, 0xe2050606, 0x9405b605, 0x64057405, 0x30054605, 0x10052205, 0xe004f004, 0xbc04ca04, 0x9a04aa04, 0x4a047404, + 0x08042204, 0xec03fc03, 0xc403da03, 0xa203ba03, 0x44036c03, 0xee021203, 0x8c02b602, 0x2e025602, 0xe8010c02, 0xbc01d601, 0x9c01aa01, 0x82018c01, + 0x64017001, 0x6c045401, 0x0e000700, 0x08695c00, 0x000a0323, 0x05994605, 0x03200025, 0x86080075, 0x00232a0b, 0x00120016, 0x00910624, 0x24118204, + 0x02110016, 0x2037841c, 0x28158219, 0x00210021, 0x00ae0812, 0x85491806, 0xf5032109, 0x1b223984, 0x1b820d00, 0x1c001c28, 0x10081900, 0x1f820c00, + 0xbb46118a, 0x861d2008, 0x05e3412b, 0x0e001a26, 0x11001e02, 0x11882b84, 0x13202b82, 0x20218182, 0x05bd4300, 0x12002622, 0x4d432382, 0x21239305, + 0x21830012, 0x13001f22, 0x7d514590, 0x93052212, 0x21738200, 0xa5821b00, 0x2f821f20, 0x0d200b83, 0x57836782, 0x27001622, 0x240ca551, 0x00120020, + 0x26038219, 0x04210010, 0x9014006d, 0x841d205d, 0x82212037, 0x00202133, 0x12260b83, 0x12001f00, 0x5b826e04, 0x5f8e0e20, 0xf7742994, 0x4120200e, + 0xd5501205, 0x9405230e, 0x85901800, 0x558e238e, 0x15412120, 0x00242212, 0x206b8216, 0x83298212, 0x831420a7, 0x950521e3, 0x92121541, 0x235d8d27, + 0x0b00fa06, 0x1f208f82, 0x45830382, 0x16205583, 0x1424f982, 0x0400d604, 0x18241784, 0x0a000b03, 0x21220984, 0x3b822600, 0x1c001a22, 0x06237983, + 0x82080092, 0x00202415, 0x82240020, 0x001f2611, 0x00930611, 0x26118207, 0x00210021, 0x821f0012, 0x00412243, 0x200f8205, 0x24218222, 0x00940612, + 0x530b870c, 0x00210d05, 0x84dd8442, 0x20198e25, 0x2019820d, 0x06194816, 0x43001124, 0x41961400, 0x210ef14b, 0x7f82b600, 0x87000e21, 0x821d2051, + 0x8312208b, 0x20918283, 0x209f8421, 0x22af8216, 0x8476031b, 0x002622ad, 0x242d821a, 0x0521001b, 0x88cf8496, 0x2000250f, 0x06006b07, 0x26222f82, + 0x05821d00, 0x97051924, 0x29820a00, 0x0b831120, 0x0f28a782, 0x18001600, 0x98051200, 0x12204582, 0x11205982, 0x23051f47, 0x0f009905, 0x0f864f84, + 0x0e222982, 0xa54b1000, 0x07202208, 0x836582c4, 0x2089832f, 0x20878414, 0x2065820c, 0x26098212, 0x0019001d, 0x84a70412, 0x821c2065, 0x500d8273, + 0x0d2008c1, 0x23887582, 0x0f054718, 0x84c50721, 0x821f2083, 0x21598467, 0x83847703, 0x39611f20, 0x821a2008, 0x821f2091, 0x820d2041, 0x00162411, + 0x84780310, 0x201f8729, 0x0617411c, 0x0d20a583, 0x0e221982, 0x21821900, 0x33841520, 0x92055d61, 0x26e38621, 0x031f000e, 0x88110079, 0x8211202b, + 0x84212065, 0x82202069, 0x082f6a13, 0x8a7a0321, 0x82112071, 0x00232119, 0x07828782, 0x07820d20, 0x13001b24, 0x21821c00, 0x458a1720, 0x90001221, + 0x83002021, 0x410e20af, 0x03230749, 0x880d007b, 0x6c16202f, 0x21260a9b, 0x7c032600, 0x1b880a00, 0x1120fb83, 0x0e226582, 0x97827d03, 0x45841220, + 0x5d000d21, 0x458208fb, 0x20001a26, 0x7e031400, 0x20201d8a, 0x0e22ad82, 0x1b821b00, 0x39822420, 0x16001326, 0x06000e03, 0x20285184, 0x1b001c00, + 0x08009d08, 0x25820d89, 0x9e080522, 0x0622118e, 0x118e9f08, 0x0f030722, 0x43849586, 0x0e203582, 0x1122b582, 0x77869a05, 0x1d84158c, 0x21001924, + 0x89829b05, 0xb3821220, 0x25821d94, 0x6f040424, 0x8b8c1300, 0x9d6b5584, 0x530e2008, 0x112206e7, 0x7d8efb06, 0x37821c20, 0x10031322, 0x635b7d8e, + 0x4102200c, 0x7d870747, 0x16001d26, 0x8c021b00, 0x938bb782, 0xb9431584, 0x9c05210d, 0x87069d41, 0x4e1f2039, 0x052109ed, 0x8ab18e9d, 0x82f7871b, + 0x05042207, 0x20438e9e, 0x28438220, 0x001f000e, 0x07150010, 0x06e14227, 0x0e225f85, 0x2b821900, 0x00239b82, 0x82220017, 0x02262221, 0x85d78cea, + 0x086d551f, 0x009f0523, 0x224b820c, 0x49210020, 0x1f260a11, 0x19001c00, 0x9b84a005, 0x29821992, 0x11202183, 0x1b263782, 0xed032100, 0x09820400, + 0x2000212c, 0x08009507, 0x16001500, 0x05842000, 0x14001b26, 0x05009900, 0x1c260b82, 0x12001b00, 0x37829b01, 0x59821520, 0xcd7f0b82, 0xcc02230f, + 0x27871700, 0xb76d1b82, 0x20138210, 0x0b1d6120, 0x82f80221, 0x204b89d3, 0x200d8210, 0x6ef78219, 0x0421061f, 0x201d8c70, 0x41918411, 0x042108fd, + 0x22878c71, 0x561b0012, 0x0223092f, 0x8a0f00cd, 0x82132087, 0x001f22ad, 0x221f8224, 0x8211001f, 0x021122e3, 0x203b8cce, 0x223b8216, 0x8421000d, + 0x0118247d, 0x8a0c009c, 0x4316203b, 0x02210957, 0x20198ccf, 0x08274e19, 0xd0021122, 0x1a20198c, 0x2020a984, 0xd1206984, 0x1d20198c, 0x22216382, + 0x23198400, 0x09009d01, 0x19206788, 0x1b243182, 0xa7001800, 0x1387b78a, 0x47820d20, 0x37821f20, 0xa8203583, 0x890a1141, 0x2189861f, 0xd58a9e01, + 0x1c221d89, 0x01821300, 0x3994a920, 0x77841f20, 0xaa001422, 0x20207794, 0x21267982, 0x1d002200, 0xff412202, 0x00212606, 0x0023021c, 0x085f480b, + 0x55820d20, 0x3b821920, 0x1a002224, 0xe9862402, 0x87822382, 0x19821020, 0x3f821a20, 0x0e001f26, 0x1100a105, 0x198a318a, 0x095f4a18, 0x82a20521, + 0x0015232b, 0x3d90001c, 0x13222382, 0x19821f00, 0x21001b24, 0x638c4b02, 0xbd821320, 0x99471920, 0x25022105, 0x3f85fb86, 0x0c134a18, 0x00420223, + 0x207f8a18, 0x20358220, 0x206d8227, 0x3143180d, 0x20c9830c, 0x204b8210, 0x22b78222, 0x42430219, 0x4d8506c7, 0x19203197, 0x1f262b82, 0x12001400, + 0x2fa44402, 0x1a002022, 0x19263182, 0xf8071900, 0x91820300, 0xfc061d24, 0x8d820500, 0x1b000e28, 0xfd061c00, 0x0b870900, 0x2008ed5c, 0x212f8226, + 0x97850016, 0xb3841f20, 0xb5820e20, 0x1d000d28, 0x13001100, 0x11827f03, 0xc9421d8d, 0x821d2005, 0x21338847, 0x0d82e103, 0x054b25a0, 0x84f92008, + 0x61122085, 0x95200c57, 0x16206d82, 0x470d4561, 0x02210faf, 0x8c8b84fa, 0x23238f37, 0x96061100, 0xa382f782, 0x00800223, 0x20958208, 0x2a21821b, + 0x001f0011, 0x071d001c, 0x86070037, 0x00122811, 0x0711001b, 0x860a0038, 0x8216200f, 0x8223200f, 0x00182623, 0x00c60712, 0x24158405, 0x04150010, + 0x83958472, 0x82212019, 0x18212047, 0x2014d744, 0x226f846c, 0x82810225, 0x82192037, 0x00102421, 0x82a30512, 0x200b8359, 0x22498214, 0x821f000e, + 0x00202405, 0x8644001a, 0x5f262015, 0x06240b19, 0x000b0097, 0x2213e153, 0x94100045, 0x09dd4917, 0x12004522, 0x1220219e, 0x4622bf82, 0x25961300, + 0x210cb546, 0x9582a405, 0x07458787, 0xd803210e, 0xe9441b8a, 0x000d2405, 0x821c0024, 0x061822d9, 0x20bf8a98, 0x22918219, 0x82200020, 0x001b2419, + 0x860c0047, 0x84192077, 0x842120ff, 0x821120f5, 0x88702091, 0x7a198fb7, 0x07210a7d, 0x853d8257, 0x47259a8f, 0x07210d3f, 0x93eb8858, 0x09075733, + 0xcf886a20, 0x1d202789, 0x0723ad85, 0x900f00f9, 0x0a6b47b7, 0x00a50523, 0x221f8208, 0x821a0022, 0x00162627, 0x0314001b, 0x20118611, 0x26558220, + 0x001b001c, 0x82990612, 0x821c2011, 0x00102ae9, 0x0020000e, 0x05200021, 0x831b84a6, 0x8421202f, 0x82132009, 0x82202005, 0x0019281d, 0x009d0412, + 0x821c0006, 0x00162853, 0x03260010, 0x84040012, 0x0819210d, 0x17835783, 0x1b842620, 0x12001b26, 0x07008003, 0x26201b84, 0x12247d82, 0xef041f00, + 0x23832b84, 0x6d829a20, 0x0c754d18, 0x43098549, 0x272008e9, 0x1f209584, 0x1f208f82, 0x16247982, 0xa6042100, 0x20201184, 0x0d201182, 0x11261182, + 0xeb021100, 0x61820500, 0x82002421, 0xad01235d, 0x0b870b00, 0x16204382, 0x1d28d982, 0x21002200, 0x0900f502, 0x1c26178a, 0x13001300, 0x31828103, + 0x84001c21, 0x65541837, 0x0be97508, 0x0027bd82, 0x009a0624, 0x821f0017, 0x00102429, 0x82200016, 0x001c2203, 0x202d821b, 0x207b821a, 0x2059821b, + 0x44078213, 0x59410753, 0x82ee2005, 0x202f8311, 0x20278214, 0x2003820e, 0x202d8221, 0x857b8224, 0x86ab2031, 0x6420201d, 0x4b450877, 0x000e2805, + 0x05190019, 0x6c0700a7, 0x1220086b, 0x9b227b82, 0x0f820c00, 0x21073f4b, 0x42180010, 0x06210857, 0x20e7829c, 0xc94c181f, 0x0012280c, 0x03180010, + 0x84050082, 0x001b2431, 0x84730421, 0x8616206b, 0x0e1f4383, 0x82f40221, 0x20418397, 0x222f841c, 0x82260021, 0x8215200f, 0x00142451, 0x86a80515, + 0x8423205d, 0x201983dd, 0x24198221, 0x0032071d, 0x832d8414, 0x44212017, 0x1c2006f9, 0x220adf70, 0x82230016, 0x234b8227, 0x1a009d06, 0x1c242982, + 0x22001100, 0x220a134d, 0x821e000d, 0x840e200f, 0x00162191, 0x19207385, 0x1a203182, 0x20223584, 0xff846e08, 0x1d001c22, 0x1b247782, 0x6f081200, + 0x0f88ff84, 0x2806cf44, 0x0518001b, 0x000a00a9, 0x26b38220, 0x00150010, 0x8219001c, 0x00142403, 0x82870826, 0x82159037, 0x820e2035, 0x03212821, + 0x00060013, 0x820f0022, 0x0016240b, 0x82aa0510, 0x7a0d8841, 0x5a2008f5, 0x15878182, 0x15002024, 0x99820506, 0xf3820f8a, 0x27601120, 0x46152008, + 0x1b22080d, 0x19821400, 0x80072024, 0x61820b00, 0xf1821b20, 0x97831b85, 0xad821020, 0x0800ab22, 0x4f821782, 0x1d203182, 0x34085182, 0x0216001b, + 0x0220023c, 0x01f60112, 0x01cc01da, 0x01aa01ba, 0x017c0190, 0x0144015c, 0x000a012a, 0x00d600fa, 0x009200b8, 0x0060007c, 0x042e0048, 0x000c0002, + 0x67018213, 0x0f2009b7, 0x2122f584, 0x7182db03, 0x5f84198d, 0x826b0421, 0x7c178d69, 0x0821089b, 0x22f9826d, 0x48190016, 0x1f220665, 0xbb821f00, + 0x59081922, 0x4d08695d, 0x21200b91, 0x0e201d82, 0x27097b5d, 0x0e00e902, 0x11001b00, 0x1a202b82, 0x0d210986, 0x096d4b00, 0x19828e20, 0x59821b20, + 0x23821620, 0xeb841220, 0x11205b83, 0x174f3f82, 0xec032508, 0x1d000700, 0x10203b82, 0x21261582, 0x72032600, 0x0f820f00, 0x31821220, 0x20051373, + 0x200f820d, 0x22dd821f, 0x82200024, 0x051f2265, 0x20fb828f, 0x839b861d, 0x000d2457, 0x82220013, 0x03192263, 0x8dfb8273, 0x821b2019, 0x06242227, + 0x845190f9, 0x080d7b17, 0x09007422, 0x24207188, 0x15228584, 0x65821f07, 0x15002122, 0x1f203f82, 0x15202782, 0x22207f82, 0x20227f84, 0xaf820406, + 0x21002222, 0x1c205382, 0x1124a382, 0x08009006, 0x0f857f82, 0x11832220, 0x00900523, 0x22118806, 0x82c60425, 0x8222203f, 0x8211202f, 0x001c2143, + 0x14204d83, 0x16200582, 0x0521b183, 0x201b8691, 0x831b8214, 0x441420cb, 0x16240649, 0x92051900, 0x19204586, 0x21228382, 0x2986e600, 0x2007f141, + 0x200f8211, 0x24438213, 0x0814000e, 0x20298629, 0x0875841d, 0xfa074988, 0xc607e207, 0x7a079c07, 0x30075607, 0xea060607, 0x9a06bc06, 0x7c068e06, + 0x60066a06, 0x20064806, 0xe4050206, 0xb805ce05, 0x8e05ac05, 0x52056a05, 0x22053a05, 0xf6041405, 0xb604d604, 0x8e04a404, 0x6c047e04, 0x18043404, + 0xf2030404, 0xca03e203, 0x9003a803, 0x56037803, 0x2c034003, 0x08031003, 0xe002f402, 0xb202cc02, 0x78029e02, 0x2c025202, 0xf8011202, 0xbe01da01, + 0x7a01a401, 0x4a016401, 0x18012801, 0xb3820201, 0xaa00c630, 0x94009c00, 0x03007c05, 0x21000e00, 0xa9821802, 0xa7820782, 0x12001f24, 0xc3821902, + 0x0b820d88, 0xe9821d20, 0x1d001c23, 0x23f18200, 0x0f001a02, 0x23243182, 0x14001600, 0x5b440782, 0x820f2005, 0x05b9471f, 0x1b021222, 0x1f8d3b84, + 0x1f821b20, 0x65822520, 0x0a007f22, 0x16283b8c, 0x1b001c00, 0x07008b02, 0x0e221f82, 0x39821f00, 0x12001a26, 0x10007d05, 0x374f0f8b, 0x008a2212, + 0x2221860c, 0x5826000f, 0x06210b87, 0x2061828b, 0x20638212, 0x83a5821f, 0x001c2619, 0x08130013, 0x05f5436c, 0x82210021, 0x8210202b, 0x441a201d, + 0x1f200619, 0x11204582, 0x20200b82, 0x0e261982, 0x11001b00, 0x59840f01, 0x24002122, 0x1f229982, 0x2f841800, 0xf7821220, 0xef021922, 0x12200b82, + 0x198b2782, 0x3f821520, 0x18001024, 0x5382cb02, 0x4f441b8d, 0x221f8206, 0x90280811, 0x001d2253, 0x226d8216, 0x90100114, 0x82242019, 0x00132419, + 0x823c0816, 0x75518d39, 0x5c18090b, 0x3d20094d, 0x0520259a, 0x21073544, 0x259a3e08, 0x79700620, 0x00242208, 0x20278209, 0x180f8224, 0x2009a756, + 0x839f843f, 0x821f2013, 0x8219201b, 0x430e2003, 0x0721056b, 0x222d86f7, 0x821d0020, 0x821d20fb, 0x051f2219, 0x2213847e, 0x82210025, 0x05ef4843, + 0xe2001b22, 0x2420138a, 0x182a8784, 0x03001101, 0x10001300, 0x27827f05, 0x14001624, 0x31841500, 0x07822020, 0x4d001221, 0x0421060d, 0x873782d5, + 0x0019221b, 0x242f8216, 0x008c0612, 0x8509820a, 0x8413832f, 0x80052309, 0x15911000, 0x0b0d5c18, 0x00c50423, 0x2021880b, 0x08ed4120, 0x8d062622, + 0x1c201782, 0x2408277e, 0x0022001c, 0x2289821b, 0x827c0820, 0x20178551, 0x20138211, 0x0c915019, 0x23831220, 0x86010621, 0x820f2039, 0x001024fb, + 0x851d0018, 0x81052407, 0x83000700, 0x82102039, 0x001926e9, 0x004f0819, 0x200f8608, 0x2421821f, 0x05150020, 0x20d78282, 0x2273821c, 0x821f0011, + 0x821b2093, 0x0220223b, 0x830f82f0, 0x205b8313, 0x20178210, 0x204f8226, 0x241d8221, 0x061b001c, 0x966f828e, 0x1b5b5f1b, 0x86830521, 0x00132279, + 0x20798619, 0x209b8684, 0x26918213, 0x0611001c, 0x840a0002, 0x8219209b, 0x001422e3, 0x24258214, 0x05120014, 0x20378685, 0x20c1821a, 0x243b820e, + 0x00030620, 0x8827840f, 0x20ad8411, 0x201b8222, 0x229b8216, 0x8af40412, 0x7e12201f, 0x0d20088b, 0x1c20c782, 0x1a223782, 0x59828605, 0xa957c183, + 0x82142009, 0x820e201b, 0x001526e3, 0x00980026, 0x205d8406, 0x22ef8220, 0x4187051a, 0x20200657, 0x1f204782, 0x19201782, 0x12246582, 0x88051f00, + 0x21201786, 0x1b243984, 0x13002000, 0x1f229f82, 0x17845008, 0x0f821620, 0x95821220, 0x24000e22, 0x1f266b82, 0x51081200, 0x3d821100, 0x10201787, + 0x1b200b82, 0x0d205188, 0x13240d82, 0xf8061300, 0x1f209784, 0x16222982, 0x3d821000, 0x19223b83, 0x87821800, 0x14001b2a, 0x05008905, 0x1f001c00, + 0x15243582, 0x0a008a05, 0x27820b87, 0x37821220, 0x21002024, 0x158c8b05, 0x8f822420, 0x8c201583, 0x21205584, 0x18085542, 0x20097d40, 0x20218219, + 0x491d8840, 0x122005eb, 0x21836182, 0x1b822120, 0x97021122, 0x1c20d582, 0x0d207182, 0xbb83f582, 0x5d181584, 0x8d20122d, 0x6383f584, 0xf1847182, + 0x7a222985, 0xa7820400, 0x03230b82, 0x85080071, 0x24878409, 0x06110011, 0x24118c8f, 0x01210019, 0x82e18471, 0x2000252d, 0x1000e406, 0x16202f84, + 0x16208182, 0x0cff4018, 0x5f820d20, 0x00233f82, 0x9816002c, 0x00162421, 0x411d001a, 0x0e260621, 0x21001b00, 0x77820503, 0x21001c22, 0x13203382, + 0x104f4118, 0x14000822, 0x20204996, 0x0c0f5718, 0x06031224, 0x299a1200, 0x1b821b20, 0x12001b26, 0x11000703, 0x5155259a, 0x98082005, 0x247383df, + 0x031b001c, 0x20959c09, 0x0af5521d, 0xdb841220, 0x31422420, 0x45192008, 0x01230901, 0x820b0013, 0x201b858b, 0x20978216, 0x2ac18214, 0x07200021, + 0x00070094, 0x551a0022, 0xea08081f, 0x0b3a0b6f, 0x0af60a18, 0x0ac00ad8, 0x0a960aac, 0x0a660a88, 0x0a2a0a4a, 0x09160a24, 0x09e609fc, 0x09bc09c8, + 0x099009ac, 0x0970097c, 0x0930095a, 0x08e60808, 0x089c08c2, 0x087a088e, 0x08500866, 0x083a0846, 0x071e0828, 0x07dc07fa, 0x07b007c0, 0x077c0790, + 0x07500770, 0x06180732, 0x06e406fa, 0x06a606ca, 0x06780692, 0x0650066e, 0x05120628, 0x05ea05f2, 0x059805c6, 0x056e0580, 0x053e0552, 0x041c052e, + 0x04da04fc, 0x04ae04d2, 0x048a049a, 0x04680474, 0x04400454, 0x04280436, 0x03ea030e, 0x03b203d4, 0x0376038a, 0x03280350, 0x020a0316, 0x02ce02e4, + 0x028002a4, 0x023e0260, 0x01020220, 0x01e201f4, 0x01bc01c4, 0x018201a0, 0x01560162, 0x013e014a, 0x012c0136, 0x00fe0012, 0x08e000f4, 0x00090099, + 0x0010000e, 0x751c001f, 0xd02208eb, 0x13820400, 0x19001624, 0x1d846a08, 0xdb420982, 0x00182408, 0x850c00ad, 0x662f841d, 0x07210a29, 0x2637841e, + 0x07120019, 0x82030093, 0x081b2423, 0x8305009a, 0x22298207, 0x889b0805, 0x0806220b, 0x240b889c, 0x007c0607, 0x2423840f, 0x0014000e, 0x12e34512, + 0x1d824c20, 0x1b000e22, 0x8205f544, 0x7161181f, 0x7d06210c, 0x1d893184, 0xe5562020, 0x7d022109, 0x1d228584, 0x41847e06, 0x20001d22, 0x1c223d84, + 0x23821a00, 0x2308b750, 0x08006805, 0x1d851f82, 0x83822220, 0x67041024, 0x11820600, 0x0b821f20, 0x1b001624, 0x0b826804, 0x1f000e24, 0x69841800, + 0x22224383, 0x0f821b00, 0x17821220, 0x69051122, 0x10221d8a, 0x0d821500, 0x27822120, 0x85841f20, 0x6a051124, 0x49841000, 0x1d893b83, 0x6b203f8b, + 0x5d85fd84, 0x99821220, 0x16000e24, 0x418a1900, 0x11006c22, 0x1f8b4188, 0x0821438a, 0x87a9820e, 0x4d178aa1, 0xe3440849, 0x00192605, 0x00d10021, + 0x8a4d860a, 0x70032127, 0x8383ad84, 0x1a203d8d, 0x2806e741, 0x001c000f, 0x00f50525, 0x280f8205, 0x00180020, 0x00000420, 0x200b8208, 0x20ab8225, + 0x05e1541a, 0x007f0623, 0x20458213, 0x200d8211, 0x5777820e, 0x1c20138d, 0x13222182, 0x25828006, 0xd3821220, 0x3f821620, 0xfb820d20, 0x18001921, + 0x820c6d45, 0x001c263b, 0x006d051b, 0x204d8809, 0x82538221, 0x4d082113, 0x10206188, 0x19203b82, 0x16222982, 0x13821b00, 0xd95a1c20, 0x6e05230d, + 0x3b861000, 0x91642787, 0x2000250c, 0x0a008106, 0x5f86218a, 0x82690721, 0x83998595, 0x82158637, 0x00192465, 0x821e0016, 0x001626a5, 0x00f50411, + 0x83bf840c, 0x0ccb7b1d, 0x69990121, 0x1f26087b, 0xaf022600, 0x27820400, 0x22001b24, 0xc9849f04, 0x49820982, 0x1c000f22, 0x18220182, 0x138a6904, + 0x1d001c22, 0x08232983, 0x8205000f, 0x001f2607, 0x01120014, 0x849f8457, 0x2235820b, 0x84260021, 0x00952223, 0x22218207, 0x82200020, 0x212582fd, + 0x45849600, 0x12210f83, 0x248b8300, 0x001f0012, 0x8dc38497, 0x0fdd5d13, 0x0300382a, 0x10001600, 0x10006f05, 0x61820783, 0x25001224, 0x7d842100, + 0x59411b20, 0x001c2806, 0x05130013, 0x9a0f0070, 0x001b2421, 0x86080039, 0x06e1451f, 0x823a0021, 0x821620a3, 0x83738357, 0x82712041, 0x200f83a3, + 0x20f7821f, 0x245b8224, 0x05120023, 0x22718272, 0x82190016, 0x75212039, 0x212008cd, 0x10247d82, 0x01041500, 0x1b205184, 0x23095742, 0x0b004e08, + 0x5f830d82, 0x37821f20, 0xe3821020, 0x20000e26, 0x73051500, 0x16201582, 0x10200982, 0x19203982, 0x0e224d82, 0x09821b00, 0x22001c22, 0x0d201382, + 0x12240382, 0x23001f00, 0x1f832382, 0x7e002024, 0x0b821100, 0x20051741, 0x4f478211, 0x5384085d, 0x3f820e20, 0xc902192a, 0x1a000300, 0x28012000, + 0x1c20f582, 0x1920f984, 0x0d225182, 0x49821300, 0x09821620, 0x43821b20, 0x26001926, 0x0a002901, 0x0f22cd82, 0x35821600, 0x09475e18, 0x2782b320, + 0x2020358b, 0x21151776, 0xf3828206, 0xef5d2789, 0x821c2009, 0x0613243f, 0x82040083, 0x0011265b, 0x00580112, 0x8409850c, 0x821c20a1, 0x841a2099, + 0x01212483, 0x88090059, 0x84122019, 0x062122d7, 0x20078284, 0x8303821c, 0x4513868f, 0x08210f9d, 0x20518a6b, 0x20858213, 0x2421841b, 0x06130013, + 0x20d18485, 0x20ed8411, 0x26d7821b, 0x00150014, 0x82510721, 0x22538723, 0x8213001c, 0x1821202d, 0x2109416c, 0x4d8a8606, 0x2508934d, 0x26000f00, + 0x37887405, 0x33881920, 0x83001621, 0x001b2457, 0x82680114, 0x821c2023, 0x0012220d, 0x20698221, 0x432b8227, 0x17820969, 0x009f0223, 0x20dd8205, + 0x228b821b, 0x84610126, 0x880b84e9, 0x888720ab, 0x4626203f, 0x0d2608af, 0x20001000, 0x33821f00, 0x75051124, 0x3f840700, 0x5f821620, 0x1f001c24, + 0x25846a07, 0x21207d83, 0x1f201782, 0x15200d82, 0x0e202782, 0x21222d82, 0xa9848806, 0x24201b8b, 0x16221b82, 0xff831400, 0x00150223, 0x20498411, + 0x205d821c, 0x202f8215, 0x0637461c, 0x24091d4b, 0x00030320, 0x26238204, 0x0311001c, 0x85080004, 0x20618209, 0x2257820f, 0x84760511, 0x821d20c9, + 0x02112251, 0x252784ca, 0x0212001f, 0xa14a00b0, 0x84122005, 0x25a18289, 0x27001600, 0xe9847705, 0x15821f82, 0x11822120, 0x29821a20, 0x138ab120, + 0x45822320, 0x21001f26, 0x06007f07, 0x20286582, 0x22001e00, 0x89061200, 0x1c201582, 0x21081b61, 0x998a000d, 0x0e204782, 0x21242382, 0x78051c00, + 0x6541c784, 0x26258d09, 0x0013001c, 0x82790513, 0x244999e3, 0x061b001c, 0x99278200, 0x08754921, 0x007a0523, 0x06e34914, 0x85823582, 0x27886d8d, + 0x03110025, 0x840a00eb, 0x001c2229, 0x207d821f, 0x26038226, 0x01120019, 0x5205009a, 0x07230727, 0x820900e0, 0x20fb830b, 0x24c3840d, 0x001b0024, + 0x215382e0, 0x1385001c, 0x0d82dd82, 0x15821620, 0x27820f20, 0xe1072524, 0x2f880700, 0x1d002224, 0x4b843b00, 0x16002328, 0x16021200, 0x1b840e00, + 0x33820b82, 0x73821020, 0x7b421220, 0xb4082109, 0x29848b84, 0x41431d82, 0x4a022306, 0x338a0c00, 0x230a015c, 0x0600f706, 0x1b341986, 0x6a041400, + 0x1d000200, 0x0f00fc02, 0x19002200, 0x16002100, 0x220aad53, 0x82150010, 0x001f2467, 0x827b0521, 0x201f8759, 0x2021821d, 0x200f8212, 0x242d8220, + 0x011d001c, 0x87fd820e, 0x0565431b, 0x18001022, 0x2006c341, 0x224f8211, 0x82bb041c, 0x00222471, 0x82120020, 0x021a2263, 0x20af8217, 0x200d8222, + 0x20378216, 0x20ff820d, 0x2447821c, 0x00500212, 0x201d8209, 0x202f8220, 0x081b4310, 0x0b006e22, 0xf744138a, 0x823c2009, 0x82262095, 0x0cbd5c25, + 0x20089959, 0x9357823d, 0x06c1461d, 0x3e207982, 0x1a202196, 0x02216d87, 0x8579827e, 0x4c1c2043, 0xee080ca7, 0x0b600b70, 0x0b360b46, 0x0af00a0e, + 0x0ac60ae0, 0x0ab00aba, 0x0a880a9c, 0x0a680a78, 0x0a480a58, 0x0a2e0a3c, 0x09100a1c, 0x09e209fa, 0x09b409c8, 0x0994099e, 0x0954096e, 0x0922093c, + 0x08dc0800, 0x08aa08c0, 0x0878088c, 0x08360856, 0x07f00714, 0x07c007d6, 0x079007a8, 0x07560772, 0x0724073e, 0x06f2060e, 0x06ae06c6, 0x06680690, + 0x05280644, 0x05e405fc, 0x059a05ca, 0x0566057c, 0x05300552, 0x0400051c, 0x04d404e2, 0x04b004c4, 0x0494049e, 0x046a0486, 0x044e0458, 0x041c0434, + 0x03f20306, 0x03ac03ce, 0x03820398, 0x035a0376, 0x031a033e, 0x02ee0202, 0x02c802e4, 0x028a02a2, 0x02600278, 0x02380246, 0x0116022a, 0x01e201f8, + 0x01b001be, 0x018a019e, 0x016e0176, 0x013e0152, 0x00ee000e, 0x006703e2, 0x000e0005, 0x0012000f, 0x82070419, 0x220b8607, 0x4d000d00, 0x0423107f, + 0x87170016, 0x451f932b, 0x04230fc5, 0x8a090064, 0x001c262f, 0x03130013, 0x89258268, 0x0ccd5b63, 0x00c30723, 0x222f8203, 0x8409021b, 0x0c8b7d37, + 0x8a3b0821, 0x82192013, 0x0011269b, 0x00690312, 0x774a1808, 0x9501230d, 0x11820600, 0x21001d2a, 0x1d001c00, 0x11009601, 0x77820d89, 0x45001021, + 0x1d42091b, 0x97012306, 0x238c0a00, 0x0d821a20, 0x98011022, 0x0e210582, 0x82478600, 0x00242439, 0x821b0016, 0x001c264d, 0x02200024, 0x708b84ba, + 0x03210c27, 0x2079846a, 0x82258222, 0x5d022165, 0x26240d84, 0x1f001200, 0x5e222f82, 0x4f820c00, 0x87840d86, 0x19821920, 0x1f000e26, 0x0b00ec05, + 0xcd820984, 0x93832982, 0x07820e20, 0x0a021122, 0x1220d982, 0x57433382, 0x00112405, 0x860b0211, 0x5b118329, 0xf4200bd9, 0x29833f82, 0x20056544, + 0x2233820f, 0x82200014, 0x000e2263, 0x28058221, 0x001c0015, 0x0512001a, 0x220b8262, 0x82140012, 0x001b222b, 0x200b8211, 0x20178221, 0x820f8214, + 0x0c022387, 0x17840400, 0x77062022, 0x1222d782, 0x3f841b00, 0x19000f24, 0x8b822200, 0x77823c20, 0x0f001622, 0x99830982, 0x4b792620, 0x82652008, + 0x76179247, 0x3d200c51, 0x238d0d82, 0x210b9343, 0x1b8d000d, 0x23088d43, 0x05007806, 0x2207d947, 0x5300f606, 0x0d20099d, 0x1c20cb82, 0x12227782, + 0xa982bc00, 0xbf821620, 0x21001522, 0x22209b82, 0x0f23ab82, 0x53005808, 0x0f2009b1, 0x1920bb82, 0x736e1982, 0xe003210c, 0x1421b384, 0x42358a00, + 0x07210fb3, 0x22598468, 0x8412001b, 0x822520e9, 0x03202287, 0x858384e9, 0x82202013, 0x82262071, 0x0312236f, 0xed4900ea, 0x20298305, 0x862f8224, + 0x6501238f, 0x35820c00, 0x6b561b20, 0x82202008, 0x000e2897, 0x00120019, 0x840400cf, 0x00182419, 0x860800e7, 0x000d2809, 0x0013001c, 0x82480213, + 0x0016246f, 0x8218001b, 0x62112027, 0x04230d27, 0x820600d3, 0x821e202d, 0x001c24d3, 0x846b031f, 0x82202045, 0x84ba2087, 0x21098345, 0x6183000d, + 0x92002122, 0x0b42bd84, 0x82152005, 0x00192649, 0x00e8021d, 0x853d8207, 0x00212413, 0x84790623, 0x8423204d, 0x0214227f, 0x20398261, 0xc16d181c, + 0x8210200a, 0x08c55b57, 0x825f0221, 0x241d8b89, 0x001f0016, 0x24b1821d, 0x0221001f, 0x8b6b8260, 0x0021241b, 0x8261021a, 0x46138d49, 0xd3470721, + 0x62022106, 0x0f20358c, 0x1f247d82, 0x0a006302, 0x10205382, 0x0d20c384, 0x13248b84, 0x64021200, 0x1d83998c, 0x8d821f20, 0x15822420, 0x15002026, + 0x17006502, 0x1c23338c, 0x83001b00, 0x821b20e3, 0x821220d7, 0x0010210b, 0x2009b346, 0x224d821f, 0x8a0c0078, 0x0a4d782f, 0x00660223, 0x20198c0b, + 0x2641821f, 0x0518001b, 0x8a150063, 0x82132017, 0x82478215, 0x82112081, 0x821d2059, 0x001f2485, 0x821a0021, 0x001b240b, 0x41670221, 0x13220c27, + 0x39821900, 0x31821f20, 0x1b822020, 0x11006822, 0x1420478a, 0x5f18bf84, 0x69220fb3, 0x238c1300, 0x0d841f20, 0x1f001224, 0x79472600, 0x217d8208, + 0x13416a02, 0x229f830c, 0x821d0020, 0x82212067, 0x02192217, 0x83c98c6b, 0x8221201d, 0x0219229f, 0x20c98c6c, 0x222b8219, 0x821b0022, 0x4c5d8795, + 0x02210a7f, 0x47c98c6d, 0x02210c71, 0x0ca7416e, 0x47821a20, 0x19001924, 0x59416f02, 0x05c3770c, 0x77821620, 0x70022022, 0x1c208f8c, 0x1320e382, + 0x1f221782, 0x638c7102, 0x20054b41, 0x24c58218, 0x0214001b, 0x20e18c72, 0x23b9821d, 0x001f000e, 0x10246b83, 0x73022600, 0xd969518c, 0x74022108, + 0x1622178e, 0x01822700, 0x75020e22, 0x1d21b18c, 0x22fb8300, 0x8c640526, 0x001d22b1, 0x2617821c, 0x00100016, 0x41760212, 0x19830cab, 0x21002022, + 0x85089f48, 0x42772023, 0x1d210ce3, 0x052f4200, 0x20202583, 0x1c26ad82, 0x77021d00, 0xcd410f00, 0x8721890a, 0x8c78201f, 0x55681841, 0x79022112, + 0x220c2543, 0x82120020, 0x417a209b, 0x4b830c19, 0x1d001622, 0x16260182, 0x14001b00, 0xe98c7b02, 0x2b822120, 0x16002524, 0x69410203, 0x09534b08, + 0x16001022, 0x2622d382, 0xeb880c01, 0x23601b89, 0x887c200f, 0x522389a9, 0x00210cd3, 0x084b4193, 0x1c222189, 0x01821300, 0x93419420, 0x0c354d08, + 0x92650521, 0x821d2031, 0x011b2293, 0x49e7820d, 0x0d210d7f, 0x0a235300, 0x00262383, 0x006c0314, 0x25830004, 0x66051822, 0x1820f386, 0x1022e582, + 0x15851900, 0x416d0321, 0x1583063b, 0x1d001c22, 0x1b225382, 0x73866e03, 0x07541385, 0x7b08210a, 0x1983a586, 0x1f202b83, 0x1c247182, 0xa2071b00, + 0x1f205b8a, 0x20204382, 0x21240382, 0x05006705, 0x14206582, 0x07238983, 0x8408009c, 0x821c200b, 0x8211207d, 0x0423241d, 0x86060066, 0x21618211, + 0x2b840e02, 0x18001c28, 0x0d022000, 0x19820700, 0x00250b84, 0x0206000d, 0x220f8c0f, 0x8c100207, 0x0208220f, 0x220f8c11, 0x84120209, 0x823f87d3, + 0x1200239f, 0x138c1302, 0x24002122, 0x37226182, 0x67840400, 0x14021d22, 0x22207d84, 0xe520ff84, 0x2420fd84, 0x8b427982, 0x08f16105, 0x846f0321, + 0x00262a67, 0x0019000e, 0x06260021, 0x2209827a, 0x7e120021, 0x7b22165f, 0x25821300, 0x1d201d83, 0x22222f82, 0x27952000, 0x82ff0521, 0x00222255, + 0x20018214, 0x2203820e, 0x82d40412, 0x0619497f, 0x2a0ec97d, 0x00060069, 0x001f0026, 0x82100016, 0x1d3e084d, 0xd003e003, 0xa003be03, 0x66038603, + 0x1e033e03, 0xd0020203, 0x62029802, 0x02022c02, 0xb601e001, 0x70019401, 0x26014a01, 0xd400fc00, 0x9200ac00, 0x70008000, 0x4e006800, 0xf4063c00, + 0xbb820800, 0x03822620, 0x21064944, 0x75826707, 0xd14a1220, 0x000d2106, 0x230af145, 0x03008e07, 0x2622e382, 0xa782f607, 0x7f821220, 0x1c000d28, + 0x13001300, 0x43828a01, 0x0f821220, 0x21088749, 0x43847606, 0x45822620, 0x59821c20, 0x45821f20, 0x21066947, 0x31828b01, 0x46182b8c, 0x11200e39, + 0x24245382, 0x8c011b00, 0x1920279e, 0x13268982, 0x8d012100, 0x09821400, 0x1f22698f, 0x47841f00, 0x07820d20, 0x21821620, 0x29821520, 0x85828e20, + 0x2224799b, 0x8f011d00, 0x238f4b82, 0xc1820f20, 0x18001026, 0x1d002000, 0x12220984, 0x49929001, 0x1b821020, 0x23821d20, 0x77821920, 0x07232d82, + 0x901000a0, 0x82102097, 0x001a221b, 0x2429821a, 0x0711001b, 0x8cb992a7, 0x0d002321, 0x43831800, 0x96b00221, 0x08455b4b, 0x96a80721, 0x8721884b, + 0x8f07214b, 0xe18f7f82, 0x97821120, 0x0f002224, 0x6d821900, 0x9d820d20, 0x41093d41, 0x0721068d, 0x8335ac90, 0x00132547, 0x00910721, 0x4205d751, + 0x70180817, 0xf9410d0f, 0x521f200e, 0x92200895, 0x3d42f785, 0x24a3990c, 0x011d0022, 0x8f4b8291, 0x821520d5, 0x0011244f, 0x82a10712, 0x231b8f47, + 0x001d001c, 0x21065d45, 0x6942a907, 0x411f8a12, 0x01210739, 0x22479292, 0x8212001f, 0x00222647, 0x011b001f, 0x12f34293, 0x0e002126, 0x94010f00, + 0x818f0582, 0x08714018, 0x00c40423, 0x22a98208, 0x8214001b, 0x000f2869, 0x04110012, 0x820700ee, 0x00212411, 0x82150010, 0x061b240f, 0x840b00f5, + 0x0012230f, 0x6b830020, 0x2f861320, 0x60000526, 0x36004c00, 0x0c241382, 0x0a00f507, 0x23206582, 0x20200382, 0x1f203782, 0xe1822182, 0x00b60725, + 0x841c0009, 0x08fd632d, 0x82b70721, 0x22138729, 0x821b0016, 0x00122401, 0x8ab8071f, 0x07bf4129, 0x298ab920, 0x08089d41, 0x04270051, 0x0480048a, + 0x044a046c, 0x030a0426, 0x03de03f2, 0x03a803bc, 0x03580376, 0x03260338, 0x02e8020c, 0x02ac02d0, 0x0268028c, 0x021e024a, 0x01f80104, 0x01d401de, + 0x018001a4, 0x01500174, 0x00140134, 0x00d400ee, 0x008600ac, 0x0068007a, 0x82f30650, 0x821020dd, 0x820d20e7, 0x821820dd, 0x842120bf, 0x041424af, + 0x820800dc, 0x841220c9, 0x821220cd, 0x021a2617, 0x00050006, 0x2609821a, 0x02120014, 0x87120007, 0x0d00210b, 0x1d20f584, 0x10221182, 0x0d822100, + 0x45861f20, 0x5e051c24, 0x258a1300, 0x1c001b22, 0x20241f84, 0x1d002200, 0x2608235d, 0x02110012, 0x8a0c004f, 0x0a3b4727, 0x8a630421, 0xd1621867, + 0x0a115f0d, 0x0f20cd82, 0x1d203f82, 0x1f205f82, 0x200c9f60, 0x20bd820e, 0x20d78221, 0x5d958290, 0x0d200995, 0x25205382, 0x03237f87, 0x5d1100e2, + 0x2d820fb1, 0x220b0174, 0x82ce0020, 0x001b22f9, 0x225f820f, 0x82400725, 0x821b202f, 0x841c2057, 0x82192035, 0x8221204b, 0x0db14d03, 0x1700da24, + 0x27821b00, 0x8d821220, 0x1f001222, 0x16202982, 0x0e200f82, 0x29830d84, 0x31821520, 0x18001022, 0x53846782, 0x00630323, 0x261f8204, 0x031c0013, + 0x850c0064, 0x0fe14d09, 0x84650321, 0x001d2683, 0x01210022, 0x20258450, 0x87458220, 0x001522ef, 0x2467820e, 0x006f0121, 0x923f8215, 0x234f8f19, + 0x51011100, 0x1b213382, 0x572b8b00, 0x52200b03, 0x1d8bbf82, 0x5f821120, 0x23001622, 0x1323eb84, 0x82001600, 0x530123f9, 0x6d8c0f00, 0x1a001224, + 0xe5821c00, 0x10001622, 0x1b220782, 0x438e5401, 0x2d821620, 0x3b822320, 0x230ae376, 0x0b005501, 0x1920438c, 0x1b241f82, 0x8d071800, 0x1d203b8e, + 0x82057942, 0x820f20c7, 0x82122089, 0x0118220d, 0x0e074156, 0x23080955, 0x08005f05, 0x16245584, 0x15001400, 0x20229182, 0xab86de07, 0x19207b83, + 0x0d20bd82, 0x0d136518, 0x82df0721, 0x001b2251, 0x202b8220, 0x201d820e, 0x0d234819, 0x00600523, 0x204f8218, 0x20fd8221, 0x817b1814, 0x840d200c, + 0x203583ad, 0x0c316a1f, 0x50072024, 0x31860900, 0x35821f20, 0x20242183, 0x10005e07, 0x1d201388, 0x5183c584, 0x6b861f20, 0x27821120, 0x3584f120, + 0x09822320, 0x21001b24, 0x23821c00, 0x75062624, 0x254e0b00, 0x82138608, 0x03052231, 0x21058266, 0x4b18001b, 0x1c200bb7, 0x1c20b982, 0x20223382, + 0xdd829100, 0x0d201b97, 0x13225782, 0x3f821300, 0x3f958d83, 0x1b242383, 0x09006105, 0x20202b82, 0x20216782, 0x05614200, 0x1d071224, 0x61820400, + 0x1b001c28, 0x03000802, 0x1f822000, 0x074c9b08, 0x0724072c, 0x070e0718, 0x06ec0604, 0x06c206d6, 0x069c06a8, 0x06620680, 0x051c0642, 0x05e205fa, + 0x05c605d6, 0x058405a4, 0x05440558, 0x0408051c, 0x04de04f6, 0x04b404d4, 0x049c04a4, 0x046c0492, 0x04440454, 0x03140436, 0x03dc03f8, 0x03ae03c8, + 0x03800396, 0x03660370, 0x0334034c, 0x031c032a, 0x02ee0208, 0x02bc02cc, 0x02880298, 0x02580270, 0x02220248, 0x01fa010c, 0x01d201e4, 0x01a801b6, + 0x017a018a, 0x01320152, 0x011a0120, 0x00f60008, 0x00d800e2, 0x069a00b4, 0x48180066, 0x67221773, 0xd5821100, 0x211c0f4a, 0xe9826104, 0x16000e2c, + 0x27081900, 0x0e000900, 0x33821b00, 0x26050741, 0x05120018, 0x86080050, 0x00262213, 0x2109831a, 0x1184d204, 0x25821f20, 0x0f822420, 0x12001f2a, + 0x02005e00, 0x68061100, 0x11221782, 0x2f581f00, 0x69062309, 0x25820f00, 0xef7a118a, 0x5105230d, 0x1f861300, 0x75821220, 0x67841520, 0x4f821020, + 0x2020b383, 0x23092d7c, 0x07000102, 0x1c202786, 0x13223182, 0x29826a06, 0x0f846985, 0x0223558d, 0x88060002, 0x061b222d, 0x871d826b, 0x8d1b202b, + 0x6c062129, 0x2141b188, 0x03022306, 0x3b860a00, 0x21002022, 0x2305ff41, 0x04021400, 0x24202788, 0x0e249582, 0x6d061800, 0x12202782, 0xe54e8584, + 0x20002308, 0x1d826e06, 0x73821590, 0x8b7b0f20, 0x0126220a, 0x85cd8288, 0x82202025, 0x0121222f, 0x08655489, 0x2f820f84, 0x16001a26, 0xb1011000, + 0xed841790, 0x86050221, 0x0541443f, 0x6f061422, 0x4f83b182, 0xb1821920, 0xdb761520, 0x000d2208, 0x20758220, 0x23618313, 0x35002600, 0x26086d69, + 0x001b0016, 0x69520514, 0x0f84086d, 0x23116d69, 0x0c008c07, 0x7945eb84, 0x000f2605, 0x001c001f, 0x24118218, 0x0068081b, 0x20198409, 0x2a358221, + 0x0022001d, 0x041d001a, 0x5306009c, 0x03230963, 0x8204005c, 0x0019240d, 0x8453051d, 0x820982c3, 0x8210202b, 0x821b2013, 0x001224a3, 0x84d0031f, + 0x5617855d, 0x06210c65, 0x243b8470, 0x07100023, 0x20b384c2, 0x20c58225, 0x267b8214, 0x0071061b, 0x8416000a, 0x820d20eb, 0x06a14707, 0x82720621, + 0x20158761, 0x22278220, 0x841f0022, 0x823620db, 0x05154561, 0x1e000d22, 0x0e23a582, 0x4f001900, 0x64200559, 0x68089d54, 0x5420094f, 0x2d859f82, + 0x976e1388, 0x945d2008, 0x001c261b, 0x03130013, 0x08d5545d, 0x0dc96f18, 0x1a001222, 0x23268b82, 0xf2061200, 0x77820600, 0x03821820, 0x14001b24, + 0xd3825e03, 0x46181620, 0x26220823, 0xbd845505, 0x44002021, 0x122009ef, 0x2224e182, 0x12005605, 0x178b3182, 0x73182183, 0x07230e57, 0x8204007e, + 0x00232625, 0x00f20712, 0x22df8203, 0x82f30720, 0x8219205f, 0x820d205f, 0x239f827d, 0x0f001b07, 0x91570982, 0x000e2205, 0x20c98226, 0x20318223, + 0x262b8219, 0x0014000e, 0x825f0312, 0x001c2641, 0x0412001a, 0x84898262, 0x18238209, 0x230a0748, 0x08007306, 0x21824182, 0x1a281782, 0x25000e00, + 0x09007406, 0x1628118a, 0x16001b00, 0x13005705, 0x74181388, 0x33820a2f, 0x210c3161, 0x3b8a8f04, 0x31822420, 0x18001f26, 0x15000f06, 0x16200984, + 0x0e2f4018, 0x82181120, 0x05211189, 0x20cf8458, 0x1819821f, 0x220d5b40, 0x8222001f, 0x041224d3, 0x94100015, 0x0020224b, 0x05ff411d, 0x00ed0423, + 0x20218207, 0x20998221, 0x24338221, 0x005c020f, 0x260f8405, 0x07190012, 0x870b0031, 0x201f820b, 0x26318210, 0x0020000e, 0x84590520, 0x00222455, + 0x8714001f, 0x9b831813, 0x5a05230d, 0x39821200, 0xaf51218f, 0x6003210e, 0x258fbd84, 0x1a001222, 0x21269d82, 0x61032600, 0x45920e00, 0xdb841320, + 0x5b051922, 0x1c207382, 0x858d0b82, 0x31822120, 0xc3041d22, 0x2228c584, 0x12002000, 0x0c005c05, 0x0b824584, 0x20233182, 0x83001600, 0x001b2687, + 0x001c0714, 0x20198809, 0x2609820f, 0x0021000e, 0x4e0a00ec, 0x212006c3, 0x0d220782, 0xc9821f00, 0xed001424, 0x158c0b00, 0x17412320, 0xf4072505, + 0x21000400, 0x1922af82, 0x0984d403, 0x1d002124, 0x7b826203, 0x15822120, 0x20001d2c, 0x03006607, 0x0f002200, 0x1d825d05, 0xcd822320, 0x00105808, + 0x0336032a, 0x03160324, 0x02e60200, 0x02be02d2, 0x029e02b2, 0x027c028e, 0x0248025a, 0x022a0236, 0x01080214, 0x01e601f8, 0x01ca01da, 0x019a01ae, + 0x01740186, 0x014c0164, 0x01380142, 0x011e012e, 0x00060116, 0x00d200f6, 0x00b200c6, 0x009800a4, 0x00700088, 0x465e0656, 0x032117f1, 0x20b982f7, + 0x208d820d, 0x247d821f, 0x0020001b, 0x26078219, 0x01120021, 0x82070087, 0x821a2009, 0x821d20dd, 0x00112207, 0x20b58234, 0x26c9820e, 0x06200012, + 0x1806005f, 0x24087741, 0x00670812, 0x220d8209, 0x840d0020, 0x233b821d, 0xdf031f00, 0x23282d84, 0x19001200, 0x11002f07, 0x1b200782, 0x1f200382, + 0x8209474c, 0x0021222d, 0x0521451c, 0xcd207582, 0x59826d82, 0x00210029, 0x001f0022, 0x84590312, 0x8221200f, 0x000e2e25, 0x031d001d, 0x000300d9, + 0x07130016, 0x82178245, 0x064d4207, 0xdd072524, 0x17820400, 0x65821f20, 0x09841a20, 0x12002124, 0x0982f604, 0x69831c20, 0x82ec0421, 0x821c20db, + 0x821320d1, 0x8210202f, 0x245b836d, 0x06120020, 0x22458260, 0x841d001d, 0x000e2645, 0x00610611, 0x830d8208, 0x8214200f, 0x821c2025, 0x82622011, + 0x202185d3, 0x2649821a, 0x000f0026, 0x84090112, 0x82202013, 0x82132035, 0x82252073, 0x011122cf, 0x200d820a, 0x22bf821d, 0x821b000d, 0x8c212039, + 0x840b201b, 0x2a2f8365, 0x0013001c, 0x005a0313, 0x821f0005, 0x8211204d, 0x82fd204b, 0x200b8571, 0x24478216, 0x0521001b, 0x872d824e, 0x001b2411, + 0x86fe0114, 0x0016262d, 0x000e011b, 0x2239840a, 0x8215001d, 0x82102079, 0x00122465, 0x864f051e, 0x00202421, 0x84630620, 0x0016224f, 0x261b8211, + 0x00250006, 0x8a640606, 0x82072011, 0x06072411, 0x82100065, 0x20238545, 0x20ad8214, 0x202d8219, 0x4db78212, 0x01210897, 0x84338aff, 0x000221b3, + 0x33859584, 0x1b001c26, 0x09006004, 0x23204388, 0x12248b82, 0x00032400, 0x1c268784, 0x1d002200, 0x1f840103, 0x89820b84, 0x61820e20, 0x30071122, + 0x5784138c, 0x00470723, 0x8747820c, 0x0a015c27, 0x845b0321, 0x201987eb, 0x26a78224, 0x0518001f, 0x880600fe, 0x0820222f, 0x85a78497, 0x82202023, + 0x08052267, 0x09118e98, 0xa0000650, 0x30115011, 0x00111a11, 0xc610ea10, 0x9210a810, 0x5c107010, 0x30104610, 0x14102010, 0xe60f0a10, 0x8c0fc40f, + 0x2a0f540f, 0xf60e120f, 0xc20edc0e, 0x700ea20e, 0x140e460e, 0xc20dea0d, 0x780da60d, 0x260d4a0d, 0xdc0c000d, 0xaa0cc20c, 0x600c840c, 0x0e0c360c, + 0xe60bfc0b, 0xc40bd20b, 0x8c0bb00b, 0x4e0b700b, 0x1a0b380b, 0xe60afe0a, 0xb40ad00a, 0x8e0a9c0a, 0x700a820a, 0x460a600a, 0x160a2e0a, 0xf209fe09, + 0xbc09d609, 0x74099c09, 0x4c096a09, 0x1a093409, 0xfa080c09, 0xc008de08, 0x9a08ae08, 0x78088408, 0x54086c08, 0x2c084a08, 0x08081e08, 0xde07f207, + 0xa607c807, 0x68078c07, 0x36075007, 0xfe061c07, 0xc206da06, 0x8206a206, 0x54066a06, 0x1e063806, 0xd805f605, 0xa405ba05, 0x76058805, 0x52056405, + 0x2e054005, 0x0a051c05, 0xe604f804, 0xb804d804, 0x8604a004, 0x4e047204, 0x0c042804, 0xd203f803, 0xaa03be03, 0x6e038203, 0x50035c03, 0x30034203, + 0x08032603, 0xda02e202, 0x9802b802, 0x74028602, 0x42025c02, 0x12022202, 0xea01fc01, 0x9201c201, 0x76018401, 0x5a016801, 0x42014c01, 0x04005103, + 0x10000e00, 0x92081200, 0x09850600, 0x000d0025, 0x8a930805, 0x0806220d, 0x220d8a94, 0x8a950807, 0x0808220d, 0x240d8a96, 0x00430509, 0x28458817, + 0x0012001f, 0x001c0021, 0x265f8222, 0x00160015, 0x8214001b, 0x821b205b, 0x0501441f, 0x19000e26, 0x13005606, 0x1c202f9e, 0x13242182, 0x0800fd05, + 0x0f202786, 0x1c265182, 0x44051800, 0x11840a00, 0xbf5d2120, 0x0b08230b, 0x15860700, 0x1f001c28, 0x45052600, 0x0f820f00, 0x7d821a20, 0x26001922, + 0x1f212982, 0x05814400, 0x45841f20, 0x32001a24, 0x1f820c00, 0x63182020, 0x401808eb, 0x3322095b, 0x19880b00, 0x24203583, 0x1122c184, 0x89849c02, + 0x13203183, 0x11224384, 0x11845203, 0x0d822320, 0x23821f20, 0x12002124, 0x75845303, 0x5e18118a, 0x1f820d5f, 0x5b821020, 0xf1491f8d, 0x9b07230c, + 0x21820300, 0x78002522, 0x1220af82, 0x20083141, 0x08b94c12, 0x83000e21, 0x821920cd, 0x8220206f, 0x827920bb, 0x62258f21, 0x0623088b, 0x84040057, + 0x03112245, 0x20a98254, 0x200b8212, 0x269f8411, 0x07180010, 0x82060019, 0x821a200f, 0x0019263f, 0x00460512, 0x260d8205, 0x0010001b, 0x84db0412, + 0x225d832b, 0x84230016, 0x0068221f, 0x206f8209, 0x2221820f, 0x820d001f, 0x00232689, 0x006c001f, 0x83138a13, 0x001b2247, 0x202d8422, 0x201d820d, + 0x20498212, 0x2207821c, 0x8c690011, 0x821b203b, 0x00242243, 0x20138c75, 0x2247821d, 0x826d001b, 0x82162019, 0x8212209d, 0x000d2335, 0x51830020, + 0xe1821f20, 0xeb204d8d, 0x19203984, 0x0d202b82, 0x1d246184, 0x7a012600, 0x16219382, 0x26138500, 0x001c0011, 0x821b0024, 0x821c200d, 0x0411228b, + 0x9455845e, 0x20c9841b, 0x222b821c, 0x82f00612, 0x204196d3, 0x073b4a00, 0x798ab420, 0x1d001c22, 0x1b245782, 0x0c009404, 0x5d85bb82, 0xf5841d20, + 0x17832020, 0x01210025, 0x880b007b, 0x82222019, 0x8219202d, 0x000e2497, 0x82a80811, 0x8a6987e1, 0x08d17917, 0x0600e822, 0x090f4118, 0x00e50123, + 0x820d8908, 0x01042223, 0x22118ee6, 0x8ee70105, 0x01062211, 0x22118ee9, 0x8eea0107, 0x01082211, 0x22118eeb, 0x8eec0109, 0x010a2211, 0x22118eed, + 0x8eee010b, 0x010c2211, 0x249582ef, 0x00190016, 0x061b4221, 0x5f4f0c20, 0x47052309, 0xbd8c0a00, 0x27830e20, 0x00be0723, 0x8815910e, 0x8ef020ff, + 0x4d0f201d, 0x24230ac1, 0x6600f101, 0x434d0a2b, 0x2a0d820d, 0x001c0013, 0x00220010, 0x41f20120, 0x95870697, 0x1f001122, 0x1a245782, 0xf3010e00, + 0x1320af8e, 0x12201986, 0xf4203582, 0x1522af8e, 0x1d821100, 0xc941ca20, 0x434b8706, 0x04210679, 0x06c9411c, 0x5c18178e, 0xbf200841, 0x1c201f98, + 0x1322c582, 0x578ef501, 0xbd821b20, 0x12001b24, 0x7582f601, 0x200b5141, 0x062d4121, 0x20000d24, 0x0b821500, 0x21001324, 0x2541f701, 0x8223200e, + 0x001b2217, 0x24158221, 0x03120014, 0x20fd8455, 0x2047821b, 0x1817840d, 0x21085353, 0x198a5603, 0x12001f26, 0x19001d00, 0x10203382, 0xde203382, + 0x1b218d84, 0x823f8200, 0x08055ef3, 0x18480521, 0x20083b61, 0x202f820d, 0x45638225, 0x222005cd, 0x8f835982, 0x1f001224, 0x55844905, 0x1f821f20, + 0xa1820d20, 0x31822620, 0x55821f20, 0x08238f82, 0x82100085, 0x41199227, 0x08230725, 0x880a0086, 0x82212021, 0x82222079, 0x04182431, 0x860900c2, + 0x21a18815, 0x2986b902, 0x210cc964, 0x15849604, 0x4f822120, 0x39822020, 0x12266983, 0x64071b00, 0x3f820600, 0x0f002122, 0x04210583, 0x208d82ea, + 0x20b98216, 0x22a1821b, 0x42200020, 0xcb240e37, 0x19000400, 0x14242182, 0x0b00b507, 0x40180985, 0x05230df3, 0x8405004a, 0x00182417, 0x86f80126, + 0x001f240b, 0x82f90112, 0x2239837b, 0x51150020, 0x012109e5, 0x89bb82fa, 0x001c2815, 0x01130013, 0x840800fb, 0x24298541, 0x061b001c, 0x87718258, + 0x0b2b4f25, 0x06212f84, 0x954f8259, 0x061b221d, 0x224b865a, 0x82240021, 0x21878243, 0xed825b02, 0x07234388, 0x820c004f, 0x0953786b, 0x2108b74d, + 0xdf84d603, 0x61831989, 0x11001b24, 0x8b84d703, 0x21201789, 0x18230f82, 0x84001200, 0xfc01238b, 0x4f840400, 0xbc041d22, 0x6783cb82, 0xf1631d20, + 0x08a1430d, 0x31821f20, 0x11001626, 0x0f00bd04, 0x27903185, 0x21821620, 0x57032022, 0x4783a186, 0x1c002122, 0x0f202582, 0x10247182, 0x58031800, + 0x61870b82, 0x13221985, 0x21821f00, 0x21001b26, 0x05003a08, 0x1c205582, 0x11220d82, 0xc984a408, 0x4d4c1c20, 0x20002305, 0x75451000, 0x5b062105, + 0x2f861795, 0x3b822220, 0x87050548, 0x84e5202f, 0x00222289, 0x08bf4421, 0x89821120, 0x1500202a, 0x07005c06, 0x11001a00, 0x2208434c, 0x8608005d, + 0x0014210f, 0x07218384, 0x228f8256, 0x8214001c, 0x01262401, 0x8206007c, 0x05714b15, 0x26081f22, 0x1c218582, 0x820d8600, 0x82102041, 0x001d241b, + 0x82c00726, 0x20178b0b, 0x20b58211, 0x26038219, 0x07120021, 0x890a00f1, 0x080d4541, 0x498e7d20, 0x1d001c22, 0x1b222f82, 0x498e7e01, 0x2308a755, + 0xc8021100, 0x658bc182, 0x33842020, 0x16001022, 0x19221782, 0x678ec107, 0x17822720, 0xf3051d24, 0x7d841000, 0xe54e1920, 0x82152008, 0x000d2267, + 0x221d8220, 0x821b0014, 0x84df2007, 0x001b2271, 0x47078221, 0x06220e63, 0x118300f1, 0x35841b94, 0x13001326, 0x09004b05, 0x260cc56d, 0x0718001b, + 0x41060065, 0x21220891, 0x21840c08, 0x18001f22, 0x19203382, 0x13247d82, 0x0d082100, 0x1385ad84, 0x8b841f20, 0x15821520, 0x0800ac22, 0x18223784, + 0x13821900, 0x01212782, 0x0cad7239, 0xcf420d20, 0x431b2008, 0x01230deb, 0x8414003a, 0x821a2039, 0x20c98321, 0x8341840e, 0x000d24e1, 0x82220017, + 0x842120e7, 0x01262251, 0x21d3843b, 0x2993001f, 0x01219d86, 0x73a5823c, 0x758d0923, 0x0123ad88, 0x8c0b003d, 0x820f2073, 0x0019260d, 0x003e0111, + 0x20178c0c, 0x208b8210, 0x22978212, 0x8e3f011f, 0x8410207b, 0x20698331, 0x06ff460d, 0x40011922, 0x238b7b8e, 0x2405e342, 0x01210012, 0x20499a41, + 0x05cf4521, 0x82420121, 0x22c58bf1, 0x821b0016, 0x82122035, 0xb78a1805, 0x9c432013, 0x183b832d, 0x220be58a, 0x8c0d0044, 0x001622e3, 0x069b4121, + 0x45011022, 0x200eb341, 0x20598219, 0x0675421b, 0x25821d20, 0x0f841020, 0x46011422, 0x180eb341, 0x24094f46, 0x0022000f, 0x22018219, 0x82210012, + 0x08112437, 0x8c1800b2, 0x8229986d, 0x820e2095, 0x011122e3, 0x215b9847, 0xab78001b, 0x00122409, 0x986c0111, 0x82298e5b, 0x001f285b, 0x07190021, + 0x8c0f00dc, 0x001c228d, 0x20a58223, 0x21af821f, 0xe7820016, 0x41480121, 0xf3830eff, 0x21221983, 0x198e4901, 0x22001e22, 0x21244982, 0x63011200, + 0x200e4f41, 0xc5781820, 0x01202208, 0x0e67424a, 0x16002024, 0x33822700, 0xe38e4b20, 0x68182020, 0x01211789, 0x4297824c, 0x21420b09, 0x08014806, + 0x11711020, 0x8219200a, 0x05a14589, 0x4d011f22, 0x1f2037aa, 0x19243788, 0x10004e01, 0x200c2141, 0x06794222, 0x20092341, 0x0ebf424e, 0x00252190, + 0x007d0711, 0x24458404, 0x008f0021, 0x26098405, 0x001a0022, 0x840700cc, 0x0024240b, 0x821f000e, 0x44612045, 0x0f870649, 0x35820d20, 0x62000322, + 0x06241590, 0x63000300, 0x89068944, 0x0508222b, 0x89ab864c, 0x0e237113, 0x844d0521, 0x20a1854b, 0x0729410e, 0x84eb0421, 0x0012227f, 0x0bc15c12, + 0x82130021, 0x00202415, 0x822e0721, 0x821f2099, 0x201d831b, 0x20138210, 0x2265821b, 0x82190012, 0x21418801, 0x57823607, 0xcb821f20, 0x53821b20, + 0x15000d22, 0x11242584, 0x0c00ad08, 0x1c20d782, 0x2006a543, 0x201f8219, 0x244b820e, 0x021f0012, 0x432f82ad, 0x11490517, 0xae02240a, 0x90000f00, + 0x28938215, 0x00250012, 0x01210016, 0x20f3824f, 0x414d8222, 0xa60809e3, 0x08510020, 0x089c08b0, 0x08600880, 0x08220840, 0x07e20704, 0x07ae07c0, + 0x07860796, 0x075c0774, 0x071e0744, 0x06f80610, 0x06c806e2, 0x069c06b2, 0x0670067c, 0x0642065a, 0x06140638, 0x05e40500, 0x05c405d8, 0x056c059c, + 0x052c0554, 0x04e60402, 0x04b004cc, 0x046e0496, 0x043c0456, 0x03fe031e, 0x03c203d6, 0x03a403b6, 0x035a037c, 0x02180336, 0x02e002fa, 0x02a802c4, + 0x027c028c, 0x02600270, 0x02400258, 0x011a022c, 0x01e001f4, 0x01a001bc, 0x01680184, 0x013e0148, 0x00000120, 0x00ee00f8, 0x00be00ce, 0x545006a4, + 0x062717f9, 0x00070051, 0x841f000e, 0x001124f7, 0x82520620, 0x5a0f8a09, 0x05230f87, 0x82040037, 0x0020362f, 0x00ba0421, 0x00100003, 0x0053061c, + 0x0011000f, 0x00120014, 0x20038220, 0x4505821b, 0x15200583, 0x21058946, 0x2f825406, 0x19261f93, 0x24001c00, 0x4f82de01, 0x29821120, 0x9a022122, + 0x16214784, 0x05714600, 0x7f432120, 0x000f2206, 0x82098222, 0x2b07215b, 0x29848b82, 0x22083377, 0x821b0012, 0x21ad8279, 0x1b8aa608, 0x57821120, + 0x35821020, 0x8d841a20, 0x8a022122, 0x7c181b8a, 0x06210e7b, 0x873f8255, 0x4c1b8e53, 0x2c2208a1, 0x25820900, 0x1b209785, 0x21056144, 0x5b82ee06, + 0x13853787, 0x0f7f1620, 0x04202410, 0x8808001e, 0x001c2639, 0x05130013, 0x204b8a38, 0x058d421f, 0x00a70823, 0x2225880b, 0x821e0020, 0x2dd182b9, + 0x8a071200, 0x14000300, 0x8b071400, 0x07830700, 0x2408595a, 0x000500ce, 0x247f8217, 0x05210010, 0x491b82f2, 0x19240741, 0xdb072600, 0x0f8a2582, + 0x24200d82, 0x1a266582, 0x1b000e00, 0x1b843905, 0x10001228, 0x1f002100, 0x07821600, 0x0f000d22, 0x18240782, 0x64081200, 0x1c221b94, 0x63821900, + 0x0c003a22, 0x378d0782, 0x51821020, 0x65081f22, 0x19200582, 0x51888985, 0xa9491a20, 0x1f002305, 0x1d943b05, 0x1d001c22, 0x11242182, 0x11003c05, + 0x95855590, 0x20001824, 0x3b821500, 0x3d052422, 0x5f8fa382, 0x13822020, 0x85411c20, 0x22638205, 0x8e13003e, 0x820e2045, 0x107f790f, 0x003f0523, + 0x20278408, 0x20578223, 0x263d8221, 0x008e001f, 0x821a0005, 0x0016260d, 0x002d0719, 0x200b8209, 0x20c38212, 0x209b8214, 0x2261821b, 0x824a0826, + 0x821a2059, 0x001f210d, 0x00201388, 0x280d6351, 0x001b0016, 0x004b0814, 0x823b8f0f, 0x08694a27, 0x82a80421, 0x821a2063, 0x00172271, 0x62178216, + 0x1c200903, 0x20243d82, 0x0c00a904, 0x1c213d82, 0x201d8700, 0x267f8423, 0x04200021, 0x8a0b00a0, 0x82132019, 0x820e20bd, 0x04202289, 0x879784a1, + 0x4a132031, 0x12210a2d, 0x203d8300, 0x246f821f, 0x04120014, 0x54598ca2, 0x12220953, 0x8782aa04, 0x1c209189, 0x1720bf82, 0x10217582, 0x20758300, + 0x20358ca3, 0x2217821d, 0x821d001c, 0x0412227b, 0x22358ca4, 0x82260020, 0x05a3499d, 0xa5042022, 0x51899982, 0x4e002121, 0x202005d7, 0x4508c564, + 0x082108a5, 0x20bd8266, 0x2055821b, 0x2031821f, 0x20518226, 0x24ad8220, 0x00160023, 0x200f821b, 0x200f8220, 0x241b8219, 0x0513000e, 0x83fd8240, + 0x20198313, 0x842f8412, 0xcf032323, 0x2b821700, 0x03461520, 0x0b737808, 0x2112bf59, 0x6f84ee02, 0x200d2360, 0x18418212, 0x230e3b45, 0x09003000, + 0x20067943, 0x208d8219, 0x22718427, 0x82050028, 0x001f22c9, 0x2005821c, 0x209b8229, 0x8307821f, 0x0ecf7c0b, 0x82410521, 0x0020223b, 0x20938210, + 0x075d4219, 0x00420524, 0x138e0011, 0x0f156b18, 0x009b0425, 0x83220004, 0xf6032153, 0x0984ed82, 0x59412382, 0x8f02250a, 0x23000a00, 0x13641384, + 0x4d03210a, 0x27429782, 0xc5022306, 0x21820f00, 0x3545d183, 0x42232005, 0x058205d1, 0x19000f26, 0xc6021200, 0x1f874184, 0x6f820f20, 0x02215f82, + 0x20158cc7, 0x054d431b, 0x00f00723, 0x244b8a0c, 0x0012001f, 0x2403821d, 0x0321000e, 0x202f8cd5, 0x20158620, 0x23b5824e, 0x00160025, 0xe5477983, + 0x820e2005, 0x041d2631, 0x0006001d, 0x26098225, 0x001b000e, 0x824e0711, 0x500d882d, 0x234d0d31, 0xab022109, 0x1d204b84, 0x087d4c18, 0x0025bb82, + 0x02200020, 0x20178eac, 0x20ab821a, 0x2251821f, 0x84080031, 0x82192063, 0x8210207f, 0x03212403, 0x8607004f, 0x001c2111, 0x04212182, 0x2039865d, + 0x20318619, 0x2407820d, 0x01130013, 0x203986df, 0x205f821c, 0x23298322, 0x1000e001, 0x11883984, 0x1a209782, 0x1b225382, 0x23822200, 0x04000d24, + 0x219ee101, 0x43820520, 0x43900e20, 0xa7821b20, 0x4b821420, 0x1d993f83, 0xe2010524, 0x3b900f00, 0x22097b63, 0x9ce30104, 0x0105221f, 0x226382e4, + 0x821d0025, 0x822020df, 0x82fb82b1, 0x05c1420f, 0x50031c24, 0x5b820900, 0x89822120, 0xcb821b20, 0x23821620, 0xef061b22, 0x138c2f84, 0x09080d71, + 0xc40e8108, 0xa20eaa0e, 0x800e9a0e, 0x500e780e, 0xf40d1c0e, 0xa40dc40d, 0x860d900d, 0x500d680d, 0x2a0d420d, 0xe40c000d, 0xb20cd20c, 0x860c980c, + 0x560c6c0c, 0x2a0c420c, 0xf80b120c, 0xdc0be60b, 0x940bb40b, 0x700b7e0b, 0x440b4e0b, 0x120b2a0b, 0xae0ad20a, 0x620a880a, 0x280a440a, 0xec090a0a, + 0xce09d609, 0x9409ac09, 0x64097c09, 0x30094209, 0x0c092009, 0xc208ea08, 0x8c08ac08, 0x32085808, 0xde071008, 0x9c07ba07, 0x42076807, 0x02072407, + 0xb806d606, 0x6e068c06, 0x20064006, 0xea050006, 0xc005ce05, 0x9a05aa05, 0x74058a05, 0x44056005, 0x1a052a05, 0xd804fc04, 0xa404c204, 0x5c047c04, + 0x2c044c04, 0xe4031404, 0xba03da03, 0x9003a803, 0x54037003, 0x1a033603, 0xe002fa02, 0xa402c202, 0x88029602, 0x70027e02, 0x3c025a02, 0x16022c02, + 0xd601f201, 0xa001b801, 0x68017e01, 0x2c014001, 0x04011801, 0x09005604, 0x40180e00, 0x1c2608d1, 0x20002200, 0x1384eb06, 0x18001f2e, 0x1a000d00, + 0x11001c00, 0x47031200, 0x7b181384, 0x04210c73, 0x06b34a57, 0x1f6c1520, 0x8310200c, 0x21002143, 0x1a203782, 0x23055d44, 0x0a008707, 0x21206382, + 0x0d200382, 0x1f220382, 0x05821f00, 0x3c072624, 0x15881000, 0xcd421220, 0x083f450a, 0x00880723, 0x4521880b, 0x06210ab9, 0x8315823a, 0x450e2025, + 0x12200853, 0xf3425382, 0x3b062106, 0x1d951582, 0x05081b22, 0x1b87cb82, 0x15002122, 0x12213582, 0x22d38300, 0x8219001c, 0x00162619, 0x0114001b, + 0x20ad8a05, 0x281d8222, 0x0014000e, 0x00830812, 0x268b8607, 0x00120020, 0x88840821, 0x820f8483, 0x00192173, 0x18203f83, 0x11221d82, 0x4386e603, + 0x17821220, 0x82051f46, 0xd9072343, 0x1d820600, 0x6b820f20, 0x1f002226, 0x0400c104, 0x10240d82, 0xdc011800, 0x15201784, 0x27245182, 0x48031200, + 0x19200d84, 0x21201b82, 0xfb200d82, 0x12201582, 0x73823182, 0x0d221182, 0xe1431300, 0x82232006, 0x031f220d, 0x5a1d8efe, 0x00230c35, 0x520c00e4, + 0x8982094d, 0x24002022, 0x12260f82, 0xdf041d00, 0x19840f00, 0x84001621, 0x26002147, 0x200ed570, 0x210f8206, 0x45430012, 0x84212005, 0x8219201d, + 0x001f2669, 0x08120014, 0x8b738407, 0x001a241b, 0x82110012, 0x002224fd, 0x9008081a, 0x00202139, 0x22054f5a, 0x84980219, 0x841d2075, 0x43212049, + 0x936e08bd, 0x49032308, 0x49820b00, 0x10002023, 0x4b761800, 0x0908230c, 0x17840800, 0x24050741, 0x05210010, 0x2049842e, 0x20738220, 0x49a58214, + 0x08231001, 0x8404007a, 0x04182431, 0x85170058, 0x21002509, 0x1d001c00, 0x0e7f4a18, 0xb7840d20, 0x91822020, 0x19000f22, 0x11222782, 0x83868301, + 0x2f881820, 0x1d821a20, 0x84011022, 0x17897186, 0x230c517b, 0x0700dd01, 0x21203f82, 0x16202b82, 0x20224982, 0x2f848501, 0x13822320, 0x77841920, + 0x8805a142, 0xec0623eb, 0x1b821300, 0xed531f98, 0x00062208, 0x4327920e, 0x01230695, 0x180a00ac, 0x260c9f60, 0x00220015, 0x8227010f, 0x001226d5, + 0x00160023, 0x201d8210, 0x20c9820d, 0x21078215, 0x3583001f, 0x0d822020, 0x21000e24, 0x5786b001, 0x22242387, 0x18001b00, 0x1c260382, 0x1b002400, + 0xcd840701, 0x20244187, 0x0c003908, 0x2020678a, 0x13209d82, 0x1924d582, 0xae011100, 0x6b890b82, 0x1c201983, 0x08236f87, 0x820900a9, 0x82242035, + 0x821d2021, 0x8216202d, 0x0021225d, 0x20b1828c, 0x207b8216, 0x28918419, 0x0020000d, 0x001d0016, 0x856f828d, 0x821d2015, 0x0711221b, 0x200f8689, + 0x2437821a, 0x0711001b, 0x213584ef, 0x6b180013, 0x06230c09, 0x8206003c, 0x841b203d, 0x04142203, 0x836782d0, 0x5c1b2063, 0x0d830891, 0x14220383, + 0x3f845202, 0x19821f20, 0x230acb4e, 0x0f005302, 0x158e3b82, 0x0f204582, 0x18241582, 0x56021200, 0x1c201f98, 0x2122a582, 0x27823d06, 0x09437a18, + 0xab841620, 0x3f842020, 0x1f831c20, 0x210d2566, 0x13825402, 0x22262d95, 0x3e062000, 0x8b961500, 0x498e1d82, 0x49965520, 0x17821020, 0x3f061f22, + 0x1d844996, 0x5620498e, 0x41088b59, 0x23840a17, 0x1f001222, 0x26220182, 0x6b962f05, 0x13001c28, 0x58021300, 0xb5941200, 0x35841f20, 0x24001922, + 0x26240782, 0x19004006, 0x998e25a1, 0x77968820, 0x22001f26, 0x57021b00, 0x20127f52, 0x20418220, 0x201d8220, 0x2275860f, 0x94180041, 0x8e238a75, + 0x41582073, 0x5618160d, 0x02210841, 0x4cef9659, 0x16240905, 0x42062100, 0x258cef96, 0x5a207b8e, 0x22166b42, 0x820e0024, 0x0518224d, 0x06c14230, + 0x28078d45, 0x001b0012, 0x00fc0520, 0x3b611813, 0x2255820d, 0x8226000f, 0x82112005, 0x821320a9, 0x8222203b, 0x0721223d, 0x44d9843d, 0x21820ae7, + 0x39842320, 0x77821620, 0x12001926, 0x0900c102, 0x10200f84, 0x35839784, 0x63071924, 0x13860700, 0x1f001c28, 0x25081100, 0x0f880800, 0x7f822220, + 0x0a082122, 0x1d205786, 0x08eb5c18, 0x0c496518, 0x08200025, 0x820b008f, 0x82232033, 0x001f228d, 0x20098220, 0x229d8421, 0x94900804, 0x08052217, + 0x22179491, 0x82c20206, 0x001b2269, 0x839d8411, 0x8224208d, 0x821f20db, 0x8420200f, 0x00202679, 0x004a0315, 0x26938203, 0x00430620, 0x821c000a, + 0x84112027, 0x002128ab, 0x001f0022, 0x8244060f, 0x8215902f, 0x820e2025, 0x0621223f, 0x261d9645, 0x0013001c, 0x82460613, 0x243b9327, 0x021b001c, + 0x203986c3, 0x2073821b, 0x82758f21, 0x841220b5, 0x871d948b, 0xf202227d, 0x84259d00, 0xf3022185, 0x8583ed82, 0x8d824b97, 0x82470621, 0x82239eeb, + 0x84212075, 0x073b50ab, 0x19001622, 0x1b287f82, 0x12001000, 0x0b003105, 0x2022af8c, 0x1b822100, 0x32051d24, 0x178c0c00, 0x2308c763, 0x04008601, + 0x10241982, 0x23071800, 0x1c204182, 0x22220382, 0x4f841a00, 0x69822120, 0x0f822020, 0x1b000e22, 0x12260182, 0xff021f00, 0x2b820600, 0x0e001a2a, + 0x1b001600, 0x0a00da07, 0x2b820d89, 0xdf820e20, 0xbb001124, 0x158c0f00, 0x230e1f6a, 0x13003305, 0x23211f8c, 0x18598200, 0x21114f51, 0x97844b03, + 0x12001b26, 0x08004c03, 0x0ad36418, 0x19001924, 0xcd84ff03, 0x49055758, 0x03210c31, 0x22ff84e7, 0x1822001b, 0x22084f81, 0x8214001f, 0x8ce82043, + 0x82202017, 0x000e21e1, 0x06234982, 0x82090048, 0x001c225b, 0x09af5c1f, 0x84490621, 0x5c1385d7, 0x062108a9, 0x8573844a, 0x82202015, 0x08716a3b, + 0x844b0621, 0x2019839f, 0x82cb820f, 0xc9042155, 0x22202b84, 0x82059943, 0x000e2259, 0x2401821f, 0x0624001c, 0x821382ed, 0x1b002307, 0xf3821500, + 0x1d822b82, 0x18002022, 0x16200b82, 0x14221382, 0x4b844c06, 0x0b822420, 0x1c001928, 0x11000e00, 0x21824d06, 0x620cfd62, 0x4e200ae1, 0x1b8fdb82, + 0x37821320, 0x1c22cd83, 0x5b181300, 0x062109ad, 0x8aff844f, 0x20718257, 0x223d821b, 0x820600c9, 0x820e2099, 0x00212429, 0x82620120, 0x821f2025, + 0x82142075, 0x82152063, 0x001b2207, 0x22e98211, 0x6a140412, 0x0d200839, 0x11203784, 0x10200582, 0x21201382, 0x07236b83, 0x8404002a, 0x02242443, + 0x820900c4, 0x00162409, 0x82120023, 0x00122641, 0x050e0021, 0x20f18234, 0x0641441f, 0x67820d20, 0x2205ad42, 0x821a000d, 0x2327823b, 0x17005904, + 0x82118d74, 0x8977183d, 0x0ce14109, 0x823e0721, 0x824f9a43, 0x821f2039, 0x04192277, 0x93b9825a, 0x821f2027, 0x821b209b, 0x841a20bb, 0x215b8ca3, + 0x5b8e5b04, 0x43821c20, 0x27821120, 0x55821f20, 0x230ad763, 0x03003505, 0x2624b382, 0x0c00d104, 0x1d820783, 0x29821020, 0x55821220, 0xe9821b20, + 0x14001b24, 0x21825c04, 0x1c002224, 0x07820801, 0x1f002324, 0x29829a04, 0x85002621, 0x05cb5477, 0x57821320, 0x11001224, 0x19923605, 0x55821c20, + 0x001a7c09, 0x133813b6, 0x12061318, 0x12d012ea, 0x129412b2, 0x125a1276, 0x1118123c, 0x11ee11f6, 0x11bc11d4, 0x118811a4, 0x114e116c, 0x1128113a, + 0x10041116, 0x10de10f2, 0x10ba10d4, 0x109610b0, 0x105e1076, 0x102c103a, 0x0f041014, 0x0fce0fe6, 0x0fa80fba, 0x0f7e0f9a, 0x0f320f4e, 0x0e020f14, + 0x0eb40ed8, 0x0e760e92, 0x0e440e5e, 0x0d1a0e32, 0x0dde0dfa, 0x0daa0dc4, 0x0d6c0d86, 0x0c2a0d44, 0x0cd20cfa, 0x0c9e0cb0, 0x0c7c0c8c, 0x0c360c54, + 0x0c160c26, 0x0be40b08, 0x0bba0bca, 0x0b920ba8, 0x0b500b68, 0x0b280b36, 0x0a0c0b16, 0x0aee0af6, 0x0ab60ad0, 0x0a880aa0, 0x0a560a74, 0x0a260a40, + 0x09f4091a, 0x09a609c4, 0x09780984, 0x09580964, 0x091c0934, 0x08e60810, 0x08ca08d8, 0x088608a4, 0x08540870, 0x0826083a, 0x07f6070a, 0x07b207cc, + 0x076e0782, 0x073a0762, 0x06180722, 0x06d806f6, 0x06ae06bc, 0x068e069a, 0x0642066a, 0x0618062e, 0x05ee0500, 0x05be05cc, 0x057a0598, 0x05620570, + 0x05420556, 0x040a052a, 0x04d804ee, 0x04ae04c2, 0x0460048a, 0x042a0438, 0x03fe0318, 0x03ce03e6, 0x039403b0, 0x035c037a, 0x03380346, 0x0204031a, + 0x02be02e8, 0x029002a6, 0x026a027c, 0x023a0260, 0x01ee0112, 0x01b201d0, 0x0194019e, 0x017a0186, 0x0015076e, 0x000e0005, 0x0016000f, 0x862d061b, + 0x0019240b, 0x69400312, 0x1528060f, 0x11001200, 0x0400fe02, 0x18262582, 0x20051200, 0x09820900, 0x10001926, 0x19002200, 0x21240982, 0x23081200, + 0x0e200782, 0xe9570d82, 0x06c74208, 0x21001b25, 0x83041500, 0x241d8f5f, 0x001c0021, 0x22358211, 0x84060426, 0x05c94507, 0x1f201183, 0x2206e147, + 0x82240012, 0x23238409, 0x13002e06, 0x5f8b7384, 0xb0182320, 0x1a20088f, 0x69844b82, 0x822f0621, 0x89698fab, 0x82242027, 0x0012241d, 0x84810018, + 0x821920cb, 0x008222af, 0x20578408, 0x85698219, 0x8683205b, 0x201183dd, 0x201b821a, 0x22338211, 0x880a0084, 0x821a2025, 0x001f220f, 0x22058214, + 0x8a0b0085, 0x00162215, 0x20018220, 0x20cb8212, 0x201d82b0, 0x087d770e, 0x0d201789, 0x2222a582, 0x1d822100, 0x2b431c20, 0x86002105, 0x29877582, + 0x2005cb4b, 0x062f4412, 0x87001122, 0xdf70738a, 0x77002108, 0x83066741, 0x8221209d, 0x820d204f, 0x08ff4a0f, 0x00c40123, 0xe1681806, 0xc5012109, + 0xaf854184, 0x95580e20, 0x84cf2008, 0x83158941, 0x087755f5, 0x00c60123, 0x8241890c, 0x09054633, 0x8d183020, 0x4d830a1f, 0x1b001624, 0x81821100, + 0x1f001c24, 0x538e3106, 0x86055b44, 0xc701231d, 0x538c0b00, 0x0e24e983, 0xc8011f00, 0x1c261790, 0x19001900, 0x838c3206, 0x18002021, 0x23089982, + 0x08002105, 0x1d204984, 0x16260582, 0x1b001400, 0xf184a602, 0x10001b24, 0x3b821200, 0x1300b522, 0x0d871982, 0x68000d21, 0x19820cc3, 0x16002122, + 0x1b22b182, 0x3b82be04, 0xbf820e20, 0x0d223585, 0x3f822000, 0x41821520, 0x11a59f18, 0x11008622, 0x82090d46, 0x24418327, 0x00180010, 0x8231840d, + 0x210025c5, 0x09004808, 0x1f202382, 0x1f201384, 0x20260982, 0xce041500, 0x13860a00, 0x57821f20, 0x21001b22, 0x19220d82, 0x158ccf04, 0x1f22c585, + 0x3982c903, 0x11204983, 0x14bfbd18, 0x47840f20, 0x1b821120, 0x49821a20, 0x096f5818, 0xcb821520, 0xcb031d24, 0x1f880b00, 0x0a755118, 0x86220521, + 0x751d2093, 0x04230995, 0x84050052, 0x0012269d, 0x00e70420, 0x280b8406, 0x001b0016, 0x0080011c, 0x220d8404, 0x82810121, 0x840e2007, 0x20e183e7, + 0x201d821c, 0x2041821b, 0x24bf8210, 0x05110012, 0x870b8223, 0x0013231d, 0xf383001c, 0x11001224, 0x4d182200, 0x07210bb7, 0x265b867a, 0x00190021, + 0x86e70612, 0x0010221b, 0x06f54215, 0x1d000d22, 0x18203b82, 0x6182cd84, 0x00960223, 0x20758208, 0x200f8221, 0x22538414, 0x82d80426, 0x831220d5, + 0x1800203d, 0x230c29b6, 0x0a000408, 0x3b482582, 0x82212005, 0x8224202b, 0x001f220d, 0x83eb82b8, 0x0019242d, 0x8224000d, 0x00132663, 0x00c90116, + 0x69f98913, 0x0b820b4b, 0xfb772020, 0xca012109, 0x22081b62, 0x8e1f0012, 0x265d8327, 0x0618000e, 0x82050033, 0x820e20bb, 0x061f2259, 0x206b8234, + 0x20ad8215, 0x202d8416, 0x22a3820e, 0x82160721, 0x821383ef, 0x210023ed, 0x45823506, 0x1b220d83, 0x81821400, 0x200d517d, 0x8b398241, 0xcd45181b, + 0x2405210c, 0x20085342, 0x08294114, 0x0e20ab83, 0x2208a760, 0x84040088, 0x00212489, 0x860b0096, 0x000d2409, 0x8222000f, 0x000f2203, 0x206f8219, + 0x83f78297, 0x82212061, 0x59178b85, 0x02210e0b, 0x20d384a7, 0x22718212, 0x841e0318, 0x7d0b84d3, 0x1f2208cb, 0x5f821700, 0x7b7d138c, 0x20798310, + 0x26d18219, 0x0318001b, 0x8a0c0042, 0x0010242f, 0x821f0016, 0x2391825b, 0x1400fd03, 0x4f8f1995, 0x8a250721, 0x4d192087, 0x07210501, 0x20258226, + 0x22d78215, 0x82180010, 0x421620df, 0x1f250699, 0x19002100, 0x222f8b05, 0x821c001f, 0x021a2201, 0x218786a8, 0x11830023, 0x3d821b20, 0x00258382, + 0x02210013, 0x894986a9, 0x821f2019, 0x249b8363, 0x00e80421, 0x20a3820a, 0x20618216, 0x20258211, 0x24d38210, 0x0412001f, 0x200782e9, 0x21238215, + 0x15830019, 0x0edd5518, 0x82430321, 0xd14e1895, 0x820d2009, 0x8212206f, 0x8211202f, 0x0a097d15, 0x007b0723, 0x20598206, 0x241d8222, 0x05150010, + 0x410d8226, 0x04230819, 0x41140053, 0x77820927, 0x23189f5e, 0x05004403, 0x2208ad76, 0x820b00ef, 0x836b830b, 0x821520dd, 0x821b2073, 0x0520229f, + 0x83058227, 0x000e21eb, 0x77068949, 0x00230f9d, 0x84c40020, 0x243b8347, 0x0089001f, 0x83478609, 0x820e20af, 0x0219220b, 0x201f84aa, 0x2429821c, + 0x00280512, 0x84138210, 0x09574f0b, 0x10201982, 0x1220e984, 0x2f206582, 0x19217b82, 0x41218500, 0x1d220737, 0x63452100, 0x29052305, 0x3f881700, + 0x6d4e1d90, 0x000e2208, 0x2485840f, 0x00540411, 0x262f9c12, 0x0013001c, 0x86730113, 0x002226a1, 0x00740111, 0x8231840c, 0x0daf5a0b, 0x00750123, + 0x22198a0a, 0x821c0011, 0x011222ad, 0x85af8676, 0x2015832f, 0x096d4c24, 0x00770123, 0x85338a09, 0x0078226d, 0x22138a0b, 0x8222001e, 0x210382a3, + 0x5f8cbc07, 0x26002022, 0x10224782, 0x8f8c7901, 0x210a354b, 0x798a5507, 0xab822620, 0x95182020, 0x46280c55, 0x1c000300, 0xab070500, 0x1c205582, + 0xb5461d82, 0x4503230c, 0x1d820400, 0x12001126, 0x0800e806, 0x23820985, 0x13001c28, 0x36061300, 0x11820600, 0x97820982, 0x37061222, 0x17847f82, + 0x23820d83, 0x75821a20, 0x0b821820, 0xcb011f22, 0x1c20c782, 0x0fdfba18, 0x02200025, 0x82140041, 0x5f19203f, 0x07540899, 0x001c230d, 0x43830018, + 0x18001f24, 0x9b84cc01, 0x2d821920, 0x53431f20, 0x001b2406, 0x84cd0120, 0x22158591, 0x82270016, 0x008a226b, 0x21bf1807, 0x001b2408, 0x842a0521, + 0x4f1a2093, 0x0f200a57, 0x1b269582, 0x44071800, 0x298b1100, 0x42200021, 0x07211113, 0x83df84ac, 0x0016243d, 0x88100421, 0x0022265b, 0x01120021, + 0x200f86ce, 0x05af431d, 0x82e50321, 0x821c2007, 0x180f8669, 0x240c1946, 0x009e0220, 0x836f8413, 0x8420201d, 0x8210206d, 0x0019222f, 0x0d634616, + 0x88350721, 0x821c2055, 0x04212225, 0x21e3841b, 0x9541001a, 0x01202207, 0x84118882, 0x1f002587, 0x1000e702, 0x1b205b82, 0x16216182, 0x3d771800, + 0x2483820c, 0x0022001b, 0x8321821a, 0x82219a7d, 0x00122685, 0x00f0051f, 0x22498417, 0x8212001b, 0x82212053, 0x8224203f, 0x002122a1, 0x83158215, + 0x860d206d, 0x49212069, 0x042305f7, 0x8c0c0055, 0x0012222f, 0x24338211, 0x07230021, 0x21ef844d, 0x4987001b, 0x09821620, 0x1b821420, 0x4f820e20, + 0xf15f1f20, 0x05202208, 0x4741862b, 0x22200515, 0x16207584, 0x08215383, 0x08076b8e, 0x15840e20, 0x93820d20, 0x200f6961, 0x863d869c, 0x0675428f, + 0x19001624, 0x1990fb05, 0xb3821d20, 0x43821420, 0x25829b20, 0x0de97818, 0x2308657f, 0x0f001a04, 0x4f89cf84, 0x0c674518, 0x00de0423, 0x201f8c0b, + 0x264f8219, 0x00200020, 0x8c08008b, 0x00202217, 0x5f7f88c5, 0x10200755, 0x1d242182, 0xc6002600, 0x19894388, 0x21002224, 0x9788c700, 0xb1831787, + 0x19822020, 0x61071222, 0x90087741, 0x2435821b, 0x061c0014, 0x082d41e9, 0x1c272193, 0x13001300, 0x82006207, 0x1b002329, 0x65522100, 0x82618808, + 0x82202045, 0x460e2015, 0x07210529, 0x21cf88bd, 0x7149001f, 0x827f2005, 0x841c2007, 0x821f203b, 0x6e1920c7, 0x01210d8b, 0x87bb88cf, 0x08b7581d, + 0x42d00121, 0x21200653, 0x1c215b82, 0x88398300, 0x2135821b, 0xa9440011, 0x82162005, 0x830e20e1, 0xab082199, 0x23244b86, 0x26001200, 0x1f206b82, + 0x0f200f82, 0x19260b82, 0x7c072100, 0x11820600, 0x18001c28, 0x12001600, 0xa5843806, 0x26001d22, 0x0e202182, 0x19245982, 0x0900dd03, 0x47066541, + 0x0523085d, 0x820b00f1, 0x821f2013, 0x821b2003, 0x822320c3, 0x001f2639, 0x05200022, 0x42d1842c, 0x7b84078b, 0x13204782, 0x2305cd43, 0x07001707, + 0x21203182, 0x0e269182, 0x12001400, 0x45842d05, 0x41002221, 0x1f20053d, 0x1c261782, 0x20001d00, 0x9182c800, 0x9d821f20, 0x01233f84, 0x8211007f, + 0x821220e5, 0x82212043, 0x820d2013, 0x0012222d, 0x09f35924, 0x1f221382, 0x49824603, 0xa3663183, 0x001f260b, 0x00ea0611, 0x8e3b840f, 0x283d8217, + 0x0013001c, 0x00390613, 0x221f8c0c, 0x84100020, 0x071224d7, 0x82040018, 0x00162419, 0x8449080f, 0x00162323, 0x03830020, 0x2d5a0d20, 0x01212208, + 0x262384d3, 0x011d001c, 0x820900d1, 0x8209822d, 0x82042059, 0x000d260b, 0x00d2010c, 0x20138808, 0x22178206, 0x8ad40105, 0x82082011, 0x01072211, + 0x20118ad5, 0x2211820a, 0x8ad60108, 0x82112011, 0x011b2271, 0x205b8ad7, 0x22ad8413, 0x82d80112, 0x821f2085, 0x821d20a9, 0x18192033, 0x20100dac, + 0x871582d9, 0x841c201d, 0x831420c5, 0x22278249, 0x8ada0119, 0x1995181b, 0x4702230e, 0xb1880b00, 0x5d821f20, 0x73412120, 0xdb012105, 0x2021178a, + 0x09256700, 0x0c003f22, 0x22282f82, 0x19001200, 0x26002100, 0x9f865982, 0x00ee072d, 0x00200003, 0x00240820, 0x82220010, 0x821f2023, 0x821b2023, + 0x2023830b, 0x208b820f, 0x200b8221, 0x2407821c, 0x00d8071b, 0x22219011, 0x82250012, 0x08554b1f, 0x82ad0721, 0x83458f87, 0x000e2169, 0x07215382, + 0x8f7782ae, 0x8219201d, 0x001f245b, 0x92af070e, 0x821d2039, 0x822220d9, 0x07112239, 0x201d92b0, 0x268d821f, 0x0019000f, 0x96b10712, 0x821d201d, + 0x071222cb, 0x8ffb82b2, 0x82262075, 0x071b2219, 0x208f92b3, 0x82558226, 0x620823ad, 0xed840800, 0x2605995d, 0x0820001b, 0x8d0f0063, 0x493d8211, + 0x112709a5, 0x07003808, 0x85002600, 0x821b2011, 0x6eae085f, 0x7c0b8e0b, 0x520b680b, 0x260b400b, 0x040b1a0b, 0xde0aea0a, 0xa20ac20a, 0x580a760a, + 0x120a3e0a, 0xca09ee09, 0x8c09ac09, 0x52096c09, 0x1e093809, 0xea080409, 0xb608d008, 0x6e089408, 0x46086608, 0x16083008, 0xe207fc07, 0xb007ca07, + 0x72078c07, 0x3c075807, 0x12072607, 0xd006f206, 0x9206b006, 0x66067806, 0x44064e06, 0x2a063a06, 0x00061806, 0xbc05e405, 0x76059c05, 0x2e054e05, + 0x06051a05, 0xde04ea04, 0xb404c204, 0x9804a804, 0x6e048804, 0x50046204, 0x28043804, 0xee030a04, 0xcc03d403, 0x9203b203, 0x5e037a03, 0x18034403, + 0x316bfc02, 0x702c0808, 0x38025402, 0x16022802, 0xd601f401, 0xb401c201, 0x9401a401, 0x6c017801, 0x44015201, 0x1e013001, 0xde000a01, 0x15001505, + 0x0f000e00, 0x0d20f182, 0x0142f382, 0x07e74607, 0x230c394d, 0x09003407, 0x10242b82, 0x0d001800, 0x1b263584, 0x16051100, 0x13860800, 0x07861d20, + 0x2588c220, 0x08a74f18, 0x003a0323, 0x261d8606, 0x051d0022, 0x180c0017, 0x200c27aa, 0x26818421, 0x04120019, 0x820500da, 0x0011220b, 0x200b8214, + 0x206582cc, 0x206b820e, 0x06235512, 0x5d001121, 0x072308cf, 0x820700aa, 0x05874327, 0x12001024, 0x0f861007, 0x1c001024, 0xcb821b00, 0x6f84ea20, + 0x19001922, 0x21220f82, 0x5b507001, 0x8215200a, 0x001f2437, 0x82aa0821, 0x820e2007, 0x20318359, 0xc3b71811, 0x000e2108, 0x1f240b83, 0x10001805, + 0x21201f82, 0x15200582, 0x15037218, 0x84240621, 0x002122f7, 0x20438215, 0x2265821c, 0x84c0041a, 0x26118383, 0x00220021, 0x8431080f, 0x002123bf, + 0xc1870021, 0x11820320, 0x57820f20, 0x32081f22, 0x04201b90, 0x33201b88, 0x05201b90, 0x34201b88, 0x06201b90, 0x35201b88, 0x07201b90, 0x36201b88, + 0x08201b90, 0x37201b88, 0x09201b90, 0x00211b87, 0x221b90f8, 0x8419000e, 0x002122cf, 0x20fb82f9, 0x0825750e, 0xcd512620, 0x09794f0a, 0x22001322, + 0x19242f82, 0x0c00fa00, 0x0b41f782, 0x2119860b, 0x61902506, 0x29822020, 0x63842320, 0x0b00fb22, 0x2020358e, 0x11236f82, 0x1800fc00, 0x820c2d48, + 0x0cbd6041, 0x82e50421, 0x8212206d, 0x00102239, 0x0def6115, 0x00260623, 0x22598203, 0x84270611, 0x41112021, 0x258207bb, 0x0f245183, 0x28062600, + 0x12210b82, 0x83198b00, 0x82162045, 0x061122c5, 0x8d538229, 0x821d201b, 0x05694511, 0x19052124, 0x5b830700, 0x1626a182, 0x12001a00, 0xbd82d607, + 0x21212d83, 0x820f8400, 0x001c2857, 0x02130013, 0x82080051, 0x00122427, 0x8415001b, 0x051224e5, 0x8205001a, 0x821b2009, 0x051c2239, 0x2299821b, + 0x82180016, 0x000d210f, 0x200dfd6b, 0x225f821c, 0x821c0016, 0x00122125, 0x06219382, 0x200f822a, 0x20378419, 0x22058211, 0x828d081f, 0x82192045, + 0x001b276b, 0x00600811, 0x0b860006, 0x08200023, 0x089d6461, 0x53821120, 0x934e0d20, 0x0011220a, 0x203584c3, 0x2113821c, 0xdb460518, 0x820b8405, + 0x84132031, 0x001d2241, 0x225d821d, 0x4d2b0611, 0x1c2206d9, 0x81821100, 0x15842620, 0x1384fd20, 0x1f822220, 0x97822120, 0x15249983, 0x0f00c002, + 0x138c3782, 0x0e224b82, 0x37822200, 0xfe21bd83, 0x8f578300, 0x4b10201f, 0xff20107f, 0x19215582, 0x5c278f00, 0x06210e0d, 0x226d942c, 0x561f0011, + 0x01210501, 0x186d9400, 0x21109157, 0xa382b701, 0x1f206d83, 0x10200782, 0x1f223b82, 0x7b821000, 0x0e001928, 0xb8011f00, 0xd1840b00, 0x45411f20, + 0x84122008, 0x00b92217, 0x20178808, 0x2467821c, 0x00ba0113, 0x24118a07, 0x0091041b, 0x24d78204, 0x03210019, 0x2409843b, 0x0518001c, 0x204d82ee, + 0x2015821c, 0x224d8218, 0x821b001c, 0x8216202f, 0x03122205, 0x854d823c, 0x831a2017, 0x1800255d, 0x0c001107, 0x3f4e2782, 0x5d43180a, 0x8c7f8308, + 0x2719872b, 0x11001200, 0x0f003d03, 0x11833790, 0x11001f22, 0x1f201f82, 0x10201f82, 0xc75a1f90, 0x1307210c, 0x43184192, 0x04230aaf, 0x8e090050, + 0x01202441, 0x820a002d, 0x84638613, 0x0019248f, 0x842e0119, 0x201589e5, 0x2223820f, 0x82210021, 0x011a2205, 0x89df842f, 0x09eb761b, 0x19903020, + 0x19001c22, 0x1f223382, 0xc3823101, 0x89001c21, 0x15491833, 0x32012112, 0x13643d8e, 0x33012308, 0xa38c0b00, 0x12001928, 0x21001300, 0x318e3401, + 0x24050d41, 0x011f0012, 0x26198e35, 0x0016001f, 0x82150014, 0x8e362033, 0x555f1819, 0x37012108, 0x830e0941, 0x011d23ed, 0xa0180038, 0xe1440d51, + 0x67c11805, 0xd7072308, 0x9b820300, 0x76002622, 0x1f249382, 0x1b000e00, 0xb983e982, 0x0d001424, 0x0f822400, 0x17842120, 0x24061b42, 0x1000cd04, + 0x05af4b00, 0xc1821820, 0x83000e21, 0x2158187d, 0xbb01210c, 0x8406434b, 0x204d82ad, 0x20238212, 0x224b8220, 0x96bc0104, 0x01052219, 0x221996bd, + 0x96be0106, 0x01072219, 0x221996bf, 0x96c00108, 0x01092219, 0x241996c1, 0x0001010a, 0x20d7820f, 0x05634116, 0x0e28b58a, 0x21002200, 0x02011c00, + 0x15201f96, 0x23059741, 0x0e000301, 0x19273f94, 0x24001c00, 0x44000401, 0x13410519, 0x0bbf680f, 0x23847820, 0x47821c20, 0x10001122, 0x59410582, + 0x821c2005, 0x000d228b, 0x82458215, 0x7908212b, 0x1f200982, 0x0e200b82, 0x238f2b82, 0x12001d22, 0x20208182, 0x1b201d82, 0x19223d82, 0xeb84c201, + 0x18001c22, 0x08ff7918, 0x17821a20, 0x12001424, 0xab842208, 0x00219782, 0x201b8220, 0x22f3820d, 0x4719000e, 0x2622065d, 0x63861e05, 0x1d842420, + 0x0d001f22, 0x1c208182, 0x15335518, 0x184c0721, 0x820d6f7a, 0x0022222b, 0x209b821d, 0x242f820e, 0x04110012, 0x211182e0, 0x5a18001f, 0x012314bf, + 0x820500c3, 0x822220af, 0x02152265, 0x20ab82fb, 0x08055722, 0x230a9d59, 0x0a003e03, 0x14203f82, 0x12204784, 0x082f5518, 0x3b823f20, 0x16002222, + 0x1122b382, 0x3b841f05, 0x2009fd55, 0x20558216, 0x24198210, 0x00140712, 0x207b8408, 0x21ef8214, 0xef820019, 0x844c0221, 0x421f204d, 0x1a2006b5, + 0x11261382, 0x51041200, 0x27820900, 0x3b442020, 0x82122006, 0x0021223f, 0x203b8480, 0x22638220, 0x8212001b, 0x0420222f, 0x209f82e6, 0x20098222, + 0x0a1d4216, 0x1b821020, 0xeb841b20, 0x001f6409, 0x12be12a3, 0x128c12aa, 0x125e1272, 0x122e1248, 0x11f2110e, 0x11b211da, 0x1170118a, 0x1144115a, + 0x1014112c, 0x10e410fe, 0x10b210cc, 0x108810aa, 0x103e1068, 0x0f021016, 0x0fbc0fe6, 0x0f700f94, 0x0f320f50, 0x0efe0e14, 0x0ece0ee8, 0x0eaa0ebe, + 0x0e700e90, 0x0e3c0e58, 0x0d020e26, 0x0dca0de6, 0x0d7c0d9c, 0x0d3e0d5e, 0x0cf40c18, 0x0caa0cd0, 0x0c760c8c, 0x0c500c60, 0x0c1e0c36, 0x0b020c14, + 0x0bdc0bf6, 0x0b980bba, 0x0b760b7e, 0x0b5a0b62, 0x0b2c0b40, 0x0a0e0b1c, 0x0ae20afa, 0x0aae0ac2, 0x0a820a9e, 0x0a480a6e, 0x09f0091c, 0x099609c2, + 0x095a0966, 0x09340948, 0x08140920, 0x08e408f4, 0x08a208c4, 0x084e0876, 0x081c082e, 0x07c80700, 0x07580792, 0x06ea0620, 0x067c06ae, 0x06500658, + 0x06240638, 0x05ee0518, 0x05c805e0, 0x059c05b6, 0x055a0580, 0x052e0540, 0x04f8040a, 0x04b604de, 0x0478049a, 0x044c045e, 0x04180434, 0x03ee0306, + 0x03b203c8, 0x038c039e, 0x0360037a, 0x033c0350, 0x03100328, 0x02000308, 0x02d402ee, 0x029e02b6, 0x02500270, 0x0114022a, 0x01d401f0, 0x019601ae, + 0x0160017a, 0x07480150, 0x000300eb, 0x0410000f, 0x000700e2, 0x000d0010, 0x001b0022, 0x00210016, 0x820c00f2, 0x4110200f, 0xab41058d, 0x000e2606, + 0x001a001f, 0x200d82f3, 0x221b8210, 0x82200012, 0x000d2401, 0x8219000e, 0x24198303, 0x00f40020, 0x22358c0b, 0x82160021, 0x06122231, 0x8b47821c, + 0x092b4933, 0x0a5f4f18, 0x8c250321, 0x82162059, 0x82162097, 0x248d835b, 0x00fc0326, 0x8c598a11, 0x2035821b, 0x245f821b, 0x00e40324, 0x24238e0a, + 0x04120019, 0x837b8c04, 0x66158239, 0x03210f5f, 0x206d8226, 0x243d8210, 0x0022001c, 0x20ff821b, 0x850f820d, 0x821b20d9, 0x03122215, 0x9ac98227, + 0x0d75181f, 0x0012240a, 0x41280321, 0x4d8b0607, 0x25001c26, 0x0e002903, 0x1789a184, 0x210afd59, 0x73414804, 0x221d8906, 0x821f0021, 0x041224bd, + 0x820800f8, 0x099d41ff, 0xbf022024, 0x11820300, 0xbd000f22, 0x11220784, 0x71824902, 0x23841120, 0x8b820e20, 0x15001d24, 0xc5821c00, 0xf5001c24, + 0x15820900, 0xc1411120, 0x8c2b200c, 0x82122013, 0x00212463, 0x860700be, 0x820f2027, 0x04252239, 0x858b82f9, 0x000f214f, 0x200d8743, 0x838b84b4, + 0x82102051, 0x001924cd, 0x8cec0719, 0x001f2411, 0x88490411, 0x82102061, 0x840e2089, 0x00bf2261, 0x8a61860a, 0xc00021f3, 0x6785df82, 0x815b158b, + 0x6b01210e, 0x1020dd88, 0x210b0757, 0x79888108, 0x2007b345, 0x85e98282, 0x8211864f, 0x8224200f, 0x001f2433, 0x884a0418, 0x00162245, 0x86178210, + 0xf00021bf, 0x19284588, 0x1b001600, 0x89021800, 0x3f79fd88, 0xfa04210e, 0x5f853982, 0x6141198e, 0x04212206, 0x1881884b, 0x2211979b, 0x4113004e, + 0xa1410603, 0x05414309, 0x2305f747, 0x000e001b, 0x06210982, 0x227f881d, 0x8212001f, 0x08b56013, 0x88fb0421, 0x069946ab, 0x842a0321, 0x82112051, + 0xaf9b1875, 0xfa052118, 0x21203588, 0x20244d82, 0xfc041800, 0x21226188, 0xb1841c00, 0xfb821f20, 0x12002324, 0x91412601, 0x41198508, 0x20200947, + 0x09654518, 0x88b20121, 0x892585e5, 0x002022cf, 0x225b8e67, 0x8222001e, 0x21038253, 0x8786fd04, 0x23081542, 0x0b009a07, 0x1320bf82, 0x230f4368, + 0x0600b301, 0x17201782, 0x20263982, 0xfe042100, 0x0d821400, 0x16001a24, 0x29821b00, 0xc3821d20, 0x51821b20, 0x35841920, 0x18001221, 0x2508d18f, + 0x5f072000, 0x29820500, 0x0f001c28, 0x33071200, 0x0b820900, 0x25822020, 0x19001022, 0x10203b82, 0xff20f782, 0x14226f82, 0x0d841f00, 0x15822220, + 0x61822120, 0x12001f26, 0x03001e06, 0x1f221382, 0x3182df02, 0x1f821620, 0x20050942, 0x20618612, 0x2263820e, 0x8213000d, 0x2309822f, 0x1800e002, + 0x53842b83, 0x0d228783, 0x8d822000, 0x9318238c, 0x00250b01, 0x00e10211, 0x8331981d, 0x821120d3, 0x8223201d, 0x82112003, 0x820e208d, 0x20518357, + 0x260f8222, 0x02120021, 0x981a00e2, 0x8219203b, 0x4e142077, 0x12220add, 0xa9822500, 0x0e001f26, 0x1b00e302, 0x1b2235a8, 0x43821c00, 0x0e001a26, + 0xe4021900, 0xff970b82, 0x1f206d8f, 0xb1837d82, 0x07831020, 0x9ae50221, 0x412983a7, 0x2f410583, 0x20a78905, 0x8fa79ae6, 0x23a78a35, 0x0d004907, + 0x2120df90, 0x1d26bb82, 0x4a072000, 0x1b8c0800, 0x1f062024, 0x11840f00, 0x52001d21, 0x1220054b, 0x21203d82, 0x10221182, 0xbb821800, 0xf7002124, + 0x1f8e1300, 0x4b821a20, 0x1b821120, 0x20093364, 0x220d8223, 0x981500f6, 0x82162027, 0x000e23c9, 0x57830010, 0x10202b85, 0x1c222b98, 0x01821300, + 0x9590f720, 0x1c207589, 0x60224d82, 0x418a0700, 0xe3042622, 0x1c222f88, 0x80181f00, 0x22200833, 0x21200982, 0x1222d782, 0x48182b03, 0x1a24089f, + 0x09002c03, 0x83089747, 0x001124c3, 0x8c2d0311, 0x23838413, 0x08002e03, 0x7583278a, 0x45842d20, 0x22000f28, 0x09061a00, 0x1d821700, 0x14001622, + 0x1808174b, 0x49116f56, 0x06230a95, 0xa015000a, 0x0019222f, 0x22fb8212, 0x820b0621, 0x821920db, 0x4d5b9b03, 0x06210887, 0x4d598c0c, 0x00220e55, + 0x714e000d, 0x0d06210a, 0xb18b2b9e, 0x8d820e20, 0x57918589, 0x1c002128, 0x4c041d00, 0xd7820900, 0x67821920, 0x1b001622, 0x25226b84, 0x0d82e404, + 0x8305996b, 0x82102013, 0x0527471f, 0x03234382, 0x860700dc, 0x001c262f, 0x05210022, 0x203f8400, 0x20318221, 0x824f821f, 0x20758211, 0x214782b2, + 0xf7450019, 0x2c1f820c, 0x001a0012, 0x0016000e, 0x00990419, 0x200b820b, 0x2013821d, 0x22258220, 0x821f001c, 0x00122415, 0x82010520, 0x821b204b, + 0x00192223, 0x22178226, 0x82100016, 0x00022213, 0x20978206, 0x82f78210, 0x2f032127, 0x1b227d82, 0x31821100, 0x33821c20, 0x03051122, 0x16203184, + 0x21205984, 0x1c261182, 0x30031b00, 0x31820c00, 0x8d841b20, 0x43821b20, 0x1d821220, 0x11821220, 0x20062124, 0x15820300, 0xbf041122, 0x6c183582, + 0x05210e3d, 0x241b8204, 0x0516001d, 0x223d8205, 0x821d001d, 0x820f209b, 0x821c20e7, 0x0018223f, 0x223d8216, 0x82060514, 0x2019850b, 0x20e3821f, + 0x83158214, 0x875418bd, 0x1b002308, 0x21880705, 0x180e4370, 0x20089b40, 0x205d889f, 0x21d18520, 0x33822100, 0x21002226, 0x05006007, 0x1d207582, + 0x12247382, 0x08004d04, 0x1f2c0b84, 0x23001c00, 0x19000e00, 0x0400a002, 0x20241184, 0x0b004b07, 0x53820985, 0x22001c22, 0x0e263f82, 0x12001400, + 0x59820805, 0x4b821f20, 0x5b451520, 0x20098205, 0x05ff4521, 0x00c10024, 0x19870007, 0x12002326, 0x0a003b07, 0x12200f82, 0x1f4d5782, 0xa102210a, + 0x71831584, 0xfb842420, 0x41820e20, 0xbd021822, 0x1f202582, 0x08ff6618, 0x3b570f20, 0x82162008, 0x06202199, 0x8e05e141, 0x843d8233, 0x2807821d, + 0x0012001b, 0x00090524, 0x87418211, 0x0d0b4925, 0x47821120, 0x1b002423, 0x05b34e07, 0x55432395, 0x79072106, 0x8b894d82, 0x4d43478d, 0x0a052308, + 0x6d980f00, 0x1d002224, 0xd18cb802, 0x00217f86, 0x22158424, 0x8ca20211, 0x0567423d, 0xc9821d20, 0x02232786, 0x8a1600a3, 0x621f905d, 0x02210d7f, + 0x890f82a4, 0x832d89b1, 0x8ca52087, 0x0013211b, 0x210a1172, 0x3141be02, 0x411b8c0c, 0x0221075d, 0x0caf41bb, 0x21062341, 0x558c8b08, 0x22001c24, + 0xdb882100, 0x0b00bc22, 0x3141bb8a, 0x11042108, 0x1788f38c, 0x2307b342, 0x0c00b502, 0xbb82378a, 0x00235187, 0x4509006b, 0x761806ad, 0x05230883, + 0x8407000b, 0x00162313, 0x95820010, 0x82310321, 0x0020213d, 0x124f6518, 0x82320321, 0x002023c1, 0x6d4d0020, 0x821a2005, 0x001b2407, 0x86330321, + 0x00162515, 0x001b0014, 0x08241586, 0x000e00b1, 0x158c2b83, 0x1124a184, 0x34031100, 0x16201d96, 0x11224182, 0xdf823503, 0x19203b93, 0x21263582, + 0x36031200, 0x5b941100, 0x0a8f6718, 0x00370323, 0x82239f13, 0x031122bf, 0x93b58238, 0x0021216b, 0x0ed5cd18, 0x828c0821, 0x222985bd, 0x82210020, + 0x8224200b, 0x0019228d, 0x24458218, 0x00b4011f, 0x836d8609, 0x820e201b, 0x042122c5, 0x8881884e, 0x20358213, 0x0f1f7611, 0x884f0421, 0x20278b81, + 0x205d821b, 0x202b8223, 0x09fd6a14, 0x41b50121, 0x298b0817, 0x2308ed4a, 0x1000d507, 0xb9838584, 0x11001222, 0x23096d4c, 0x1c001900, 0x11244782, + 0x03009502, 0x1a24bb82, 0x0c000c05, 0x21200782, 0x10221382, 0xe9451500, 0x2b01230b, 0x198c0b00, 0x83821320, 0x12001924, 0x318e2c01, 0x7b181a20, + 0x722208c3, 0x318a0a00, 0x2106ff41, 0x4786cb04, 0x314c1f20, 0x2000230b, 0x17882206, 0xcd821620, 0x69182220, 0xed200887, 0x22204582, 0x1620b382, + 0x0d215782, 0x20758700, 0x42158ab6, 0x0d2009b1, 0x39838b82, 0xb9821c20, 0x24000e24, 0xf5821200, 0x82001c21, 0x0e052179, 0x19943982, 0xb1832982, + 0x8d822020, 0x10001624, 0x279e0f05, 0x21069946, 0xad821005, 0x11204f87, 0x19206782, 0x21240382, 0x11051200, 0x17874f82, 0x16001324, 0x0f822500, + 0x07821520, 0x15001424, 0xd7861205, 0x1b879d83, 0x210a2d4a, 0xbd8a1305, 0x1c201f87, 0x13228f82, 0xed84e606, 0x83002121, 0x00142239, 0x27ab821f, + 0x0815001d, 0x0009005f, 0xc3836b87, 0x7f821120, 0x438a1420, 0x210c9147, 0x35822306, 0x13242d85, 0x20001d00, 0x0d596318, 0x88390321, 0x821f204b, + 0x821b20c9, 0x00242603, 0x0008002e, 0x83278223, 0x821a20f3, 0x001f2211, 0x2ac98203, 0x0408000e, 0x00020045, 0x82470418, 0x001a280f, 0x0046041d, + 0x82180007, 0x481d2027, 0x2587065d, 0x25844220, 0x25864420, 0x25964320, 0x25843f20, 0x25864120, 0x258e4020, 0x60000630, 0x4a005000, 0x1a003400, + 0x1a060e00, 0x27820500, 0x0621bf84, 0x21e9821b, 0xcb920003, 0x00ed0523, 0x228d820a, 0x82210013, 0x820e2005, 0x000e26eb, 0x0421001f, 0x2067843c, + 0x215f8d3d, 0x77853e04, 0x00040023, 0x24db8226, 0x040a0010, 0x222782f7, 0x84390414, 0x8e3a202d, 0x863b202d, 0x00052b2d, 0x00540064, 0x0028004e, + 0xf983060c, 0x67181420, 0x00230d95, 0x820e0011, 0x060e257d, 0x00120019, 0x65181b83, 0x00211ccf, 0x206b847d, 0x206b8e37, 0x346b8638, 0x00940009, + 0x007c008c, 0x005a0076, 0x003a0042, 0x06140020, 0x0a074114, 0x07411520, 0x99022117, 0x09264182, 0x24030300, 0x91820b00, 0x61000d21, 0x162609d3, + 0x1b001c00, 0xb5821606, 0x0421b996, 0x20938434, 0x20938e35, 0x21938536, 0x1d821706, 0x08001d2c, 0x48005200, 0x34003e00, 0x95822a00, 0x12001824, + 0x35843104, 0x25853320, 0x002c0423, 0x20098604, 0x2609822d, 0x001a0004, 0x822e041d, 0x84052009, 0x822f2009, 0x84062009, 0x82302009, 0x84072009, + 0x8d322009, 0x1000396f, 0xb600c600, 0xa600b000, 0x82009c00, 0x6e007800, 0x5a006400, 0x46005000, 0x22227586, 0x61821f04, 0x18000324, 0x6b882004, + 0x6b872120, 0x82ea0721, 0x0005241b, 0x88220406, 0x88232073, 0x88242073, 0x82252073, 0x84082009, 0x8226207d, 0x84092009, 0x82272009, 0x830a2009, + 0x77082509, 0x0b000c00, 0x2e063175, 0x001f000d, 0x0021000e, 0x001b0016, 0x82280414, 0x840b2023, 0x8229202d, 0x840c2009, 0x842a2009, 0x8d2b20ff, + 0x130625c5, 0x25000d00, 0x82152142, 0x8403202f, 0x8200203d, 0x00242859, 0x00260009, 0x82200027, 0x00112615, 0x01990000, 0x35c18255, 0xb12e0007, + 0x3c2f0001, 0x000407b2, 0x06b132ed, 0xb23cdc05, 0x0a820203, 0x03b10022, 0x05201683, 0xb2271683, 0xfc010607, 0x8301b23c, 0x11333517, 0x33271133, + 0x88112311, 0x01666677, 0x11abfe55, 0x01003301, 0x02884f82, 0x00103120, 0x351c020e, 0x002b0003, 0x01d5012b, 0x000300d5, 0x000f0007, 0x23352500, + 0x03821715, 0x1632023a, 0x26220614, 0x2a150134, 0xb0432a2a, 0x7db07d7d, 0x568080eb, 0x40012b2b, 0x7d230a82, 0x880400b0, 0x2d378339, 0x00170013, + 0x36323600, 0x06222634, 0x3b861214, 0x15333724, 0x03821523, 0x658cba26, 0x53658c65, 0xc0204484, 0x2a214e82, 0x230e8255, 0x1b018c65, 0x13234984, + 0x822b2b80, 0x0015247d, 0x86eb0140, 0x890a2087, 0x13072287, 0x2d828413, 0xd5ebebd6, 0x2b555656, 0x9501402b, 0x2f826bfe, 0x15004024, 0x2f82c001, + 0x1f000b24, 0x2f842500, 0x6e83b582, 0x1735332a, 0x35211517, 0x36343537, 0x32280383, 0x16151516, 0x33071516, 0x013bce83, 0x402a4055, 0x2d7e2a40, + 0x422d80fe, 0x141c142f, 0x54bd4031, 0xea192219, 0x8240402b, 0x2d513502, 0x7c2d1717, 0x0f0b5430, 0x0e14140e, 0x33510b0f, 0x1a1a11d5, 0x5534ea82, + 0xab012b00, 0x0600cb01, 0x0e000a00, 0x00002200, 0x35262225, 0x37205182, 0x20062d41, 0x26719233, 0x19120001, 0x82041a56, 0x952708ef, 0x2baafe2b, + 0x1c122d33, 0x2b332d12, 0x19111218, 0x555555d5, 0x152b2a2a, 0x326a2b15, 0x0d0f0b4a, 0x0f0d1313, 0x82324a0b, 0x078d41d5, 0x0f000726, 0x00001700, + 0x20074941, 0x06594106, 0x59413620, 0x12f73306, 0x0c120c0c, 0x38385013, 0xb0083850, 0x7db07d7d, 0x10821501, 0x69120c22, 0x38221082, 0x1082fd50, + 0x82b07d21, 0x004027b7, 0x01c00140, 0x4e8300c0, 0x32002a26, 0x34360000, 0x36244285, 0x26220614, 0x27210b82, 0x33518533, 0x35373435, 0x06270717, + 0x32161415, 0x26343536, 0x14231527, 0x80262a86, 0x0d0d120c, 0x0584f412, 0x50158931, 0x70a07070, 0x741e914d, 0x577c5721, 0x842a364a, 0x208e8575, + 0x2094841e, 0x321f82ab, 0x39605070, 0x731e9101, 0x573e3529, 0x54383e57, 0x83df2908, 0x820c2043, 0x004022e0, 0x20918255, 0x25dc82ab, 0x003f002f, + 0x6b820100, 0x22232324, 0x78821506, 0x82333321, 0x2335257a, 0x33352315, 0x34210382, 0x37179326, 0x15163237, 0x23061411, 0x35262221, 0x33363411, + 0x090c8001, 0x0d0d0940, 0x0c240482, 0x752b2b20, 0x12840884, 0xca320d82, 0x111a1a11, 0x1912d6fe, 0x15011219, 0x0c0c0916, 0x04835609, 0x400b1623, + 0x260d8d0b, 0xff111a96, 0x821a1100, 0x12002226, 0x20a48219, 0x22a48255, 0x82ab01ab, 0x00072209, 0x82a4820b, 0x8221208f, 0x11333894, 0x55011133, + 0x00ff5656, 0x01562a56, 0xababeb40, 0xaafe5601, 0x41000200, 0x0b220766, 0x2d821b00, 0x3323c282, 0x83352335, 0x26ae9003, 0x55808040, 0x85aa5555, + 0x28058398, 0xd62b4001, 0x2b2a2b2b, 0x84a98380, 0x112a2210, 0x2652821a, 0x01800055, 0x828001cb, 0x82052009, 0x07173052, 0x01171123, 0xc0b6b615, + 0x808001b6, 0x83000180, 0x00352418, 0x87ab0180, 0x37132622, 0x37272311, 0x202082f5, 0x231d82b6, 0x808000ff, 0x260aa143, 0x00090004, 0x8213000e, + 0x26c98248, 0x17370727, 0x82032315, 0x25353452, 0x33352707, 0x75756001, 0x40406040, 0x40402080, 0x82150175, 0x40012208, 0x85108380, 0x2115830c, + 0xe2820300, 0xc0012b2d, 0x0700e601, 0x35000f00, 0x42120000, 0x2732061c, 0x07171406, 0x13373426, 0x33353632, 0x22230614, 0x01852627, 0x20833520, + 0x34231529, 0x15062226, 0x85161714, 0xf52b0801, 0x1f1f2c20, 0x3838722c, 0xe645451e, 0x322b1911, 0x29101323, 0x291d0712, 0x7e571714, 0x5a3d2b56, + 0x240e113e, 0x170d0b28, 0x832a0108, 0xbd1f2329, 0x2b82a038, 0x45c22108, 0x111a6ffe, 0x15073223, 0x1e161637, 0x3f2a2925, 0x2d3f5656, 0x202d3e3e, + 0x1e1b1b1f, 0x040c2622, 0x5842eb82, 0x00032d07, 0x00230017, 0x25000033, 0x17153335, 0x2a0c5e42, 0x33353315, 0x35073632, 0x82231523, 0x200c8203, + 0x109f4115, 0x202b3523, 0x0550420c, 0x1020102a, 0x20950c09, 0x2b20202b, 0x240a4742, 0x0b4040e0, 0x06494256, 0x0c20202a, 0x3535800c, 0xeb2b2b80, + 0x2c0c3f42, 0x00550002, 0x01ab0115, 0x000e00eb, 0x3487831d, 0x22350717, 0x37343526, 0x14150617, 0x16321316, 0x27071415, 0x2d998336, 0x01372715, + 0x46555500, 0x0f1f1b65, 0x0686354b, 0x80555531, 0x40565540, 0x29324665, 0x35211b1f, 0x882b014b, 0x3417820a, 0x6b000200, 0x95014000, 0x0f00d501, + 0x00001b00, 0x06143301, 0x28cf8207, 0x33352626, 0x36321614, 0x41698206, 0x2608057b, 0x71011415, 0x2a354b24, 0x43244b35, 0x3457435c, 0x26342626, + 0x51361501, 0x08464608, 0x3d2f3651, 0x1a26113d, 0x83261a80, 0x03002104, 0x1c22548a, 0x56912800, 0xb9822720, 0x36323329, 0x26343735, 0x96160622, + 0x0f8b2963, 0x010f0a0b, 0x34101410, 0xb12a6c91, 0x0e0f0a84, 0x0f0b840b, 0x768bcd0f, 0x2c053943, 0x001900d5, 0x00270021, 0x07011300, 0x25ce8a27, + 0x27373233, 0x6d832306, 0x27052722, 0x172cd585, 0x36270714, 0x65015b35, 0x2116591b, 0x2e2bdb84, 0x08231819, 0x80261a06, 0x82800001, 0x13552be2, + 0xc001091a, 0x591b9bfe, 0xe986050e, 0x02230b29, 0x80101a26, 0x84047f93, 0x212530ee, 0x0017141b, 0x002b0001, 0x01d50155, 0x831800ab, 0x0b5444ee, + 0x33173323, 0x08038627, 0x55800122, 0xaafe1119, 0x11191911, 0x2a402a16, 0x2b402b2a, 0x01402b2b, 0x11d5feab, 0x01111a1a, 0x561a1100, 0xb9450083, + 0x000b240a, 0x8224001b, 0x23352151, 0x42088f46, 0x07240f65, 0x21152111, 0x1128d582, 0x2b559501, 0x6b2b5555, 0xff205e83, 0x1a2a4b82, 0x2b015611, + 0x1911d5fe, 0x17831501, 0xc0555524, 0x17851119, 0x192a6982, 0x2ad5fe55, 0x2b011119, 0xb4470500, 0x2170890c, 0x72821715, 0x03833720, 0x8a0e2545, + 0x80d52570, 0xebd5d580, 0x6b287091, 0x2bab2a2a, 0x2b2b552b, 0x27487295, 0x00082709, 0x00260016, 0xc3871300, 0x6f820520, 0x22232629, 0x32161406, + 0x8f353536, 0x865520ea, 0x555528cf, 0x2016120e, 0x8a1f2c20, 0x800121eb, 0x1523d086, 0x820b752a, 0x161f231a, 0xef8b6a76, 0x00030029, 0x01210015, + 0x82df01eb, 0x00072209, 0x0914481b, 0x17072529, 0x07270707, 0x83372727, 0x17373601, 0x07171737, 0x2a2a1501, 0x3400012a, 0x49284d07, 0x074d2849, + 0x48098834, 0x6b2c05b7, 0x44114f3b, 0x12431f1f, 0x4e3c3b4f, 0x44220983, 0xb6414f11, 0x0008240a, 0x82190011, 0x35362261, 0x29cd8334, 0x36321307, + 0x15062737, 0x08491614, 0x24872708, 0x3e184665, 0x03826913, 0x6524f034, 0x7d7db012, 0x2d977db0, 0x1565463c, 0x15cefe0f, 0x0a83f00f, 0x82800121, + 0xb07d2b14, 0x80000200, 0x80016b00, 0xb9849501, 0x33010036, 0x11232311, 0x2b011133, 0x55ab5555, 0xd6fe9501, 0xd6fe2a01, 0x7c497d8a, 0x4923200a, + 0x40240b7c, 0x182b2a2b, 0xab216984, 0x210082aa, 0x7b492a01, 0x0003260f, 0x0013000b, 0x22b88217, 0x48153335, 0x35480725, 0x82172007, 0x15012313, + 0x7e49862b, 0x2b95210a, 0x56204882, 0x260b7e49, 0x00aaaaad, 0x82ab0001, 0x829520ae, 0x00022cae, 0x07171300, 0x01eaeaab, 0x82959595, 0x078f48c6, + 0x0a000228, 0x37370000, 0x2e482627, 0xd5342405, 0x842d8080, 0x60a02397, 0x94857560, 0x24092242, 0x000f0007, 0x110e4a12, 0x17351722, 0x210b094a, + 0x064a80aa, 0xc0b8240c, 0x43040060, 0x80220693, 0x42820300, 0x3720d784, 0x3730c382, 0x15231533, 0x35233523, 0x27333533, 0x05352115, 0x2b250382, + 0x5555abaa, 0x2002832b, 0x23be82ff, 0x2aab00ff, 0x56260082, 0x55562a56, 0x02822b2b, 0x336d9043, 0x00400004, 0x01d50155, 0x000d0080, 0x00150011, + 0x01000019, 0x6449b383, 0x32332705, 0x33350517, 0xb5823715, 0x03822520, 0x6a6b012e, 0x26342640, 0x0e081a26, 0x55abd5fe, 0x0125be85, 0x1ac02b80, + 0x24168226, 0x2a2a2604, 0x26c28d80, 0x000700eb, 0x8221000f, 0x21352153, 0x33223f82, 0x0d4a0415, 0x25032406, 0x43330717, 0x01280cea, 0x01aafeab, + 0xfbfe2b00, 0x34365f82, 0x0e011026, 0x12fab00e, 0xfe121818, 0x011812aa, 0x2b555500, 0x6382ab2b, 0x0134262a, 0x47246e02, 0x00ff1219, 0x012c1c83, + 0x05001e00, 0x6b001500, 0x9501eb01, 0x1f2f6b84, 0x27002300, 0x35250000, 0x06222634, 0x43361515, 0x342005dd, 0x080fdc43, 0x3311012b, 0x11331311, + 0x420b0123, 0x2673423c, 0x1d261d1d, 0x0c0c0950, 0x0900ff09, 0x01090d0d, 0x2b2b2a40, 0x1610952b, 0x10161a1a, 0x221b82c6, 0x8457261d, 0x2321821b, + 0x0c090001, 0x25050443, 0xd6fe2a01, 0x5e480200, 0x00d52406, 0x42110008, 0x213105cb, 0x15372715, 0x35231535, 0x07173521, 0x2a6b0135, 0x20be82ff, + 0x27c3832a, 0x40805695, 0xd6405555, 0x9a480685, 0x00d52608, 0x000f0006, 0x293d8218, 0x35233523, 0x35173337, 0x448e1533, 0x20201525, 0x8956152b, + 0x55c02449, 0x8dab1516, 0x0001334d, 0x01400055, 0x00eb01ab, 0x01000013, 0x14151632, 0x59472206, 0x26342206, 0x38938223, 0x64470001, 0x2b658c65, + 0x4b4b6a4b, 0x016b6b35, 0x47466495, 0x35476464, 0x2210824b, 0x4a6b6b56, 0x06220a3c, 0xcc840d00, 0x37172408, 0x27372315, 0x27153337, 0x07012701, + 0x01372707, 0x762c433c, 0x7617432c, 0x1ef4fe2c, 0x1e7f0c01, 0x84e21e6f, 0x86e72011, 0x82432011, 0x02002611, 0x80008000, 0x82018201, 0x00062152, + 0x2a064244, 0x2b550117, 0x01b5d52b, 0x4a00ff80, 0x23870503, 0xfd820220, 0x3713002d, 0x11330111, 0xffb5cb23, 0x822b2b00, 0x055a421f, 0x22082e46, + 0x820900d8, 0x00193090, 0x0021001d, 0x33351300, 0x15330715, 0x4c373523, 0x25200f5b, 0xa683a282, 0x80c02408, 0x4d804d4d, 0x57577c4b, 0xa045577c, + 0x70a07070, 0x621b9501, 0x1b62cb1b, 0x2b150162, 0x272b5a26, 0x8358c059, 0x71fe2d1d, 0x9e71719e, 0x2053214c, 0x52205220, 0xb8879884, 0x21130027, + 0x01802111, 0x82898200, 0x228984b2, 0x4bd50155, 0x0f220859, 0xd4451f00, 0x35232809, 0x15351523, 0x42253533, 0x362d0cd1, 0xd6ab0133, 0xd62a56d6, + 0x11000156, 0x078b4719, 0x2b2bd524, 0x00822b55, 0x2b2b8023, 0x057b49ab, 0x8a058c47, 0x00072861, 0x001b0013, 0x4d370027, 0x172c0945, 0x34353536, + 0x16072726, 0x26071415, 0x2c064343, 0x34352607, 0x15062737, 0x17161415, 0x36798e01, 0x1a1a22ef, 0x32a41a22, 0x261f151d, 0x32467e25, 0x05324632, + 0x821e2526, 0x2401210f, 0x01218b89, 0x2e24822b, 0x328a221a, 0x471d0147, 0x34261f14, 0x82062536, 0x46322229, 0x200a8337, 0x2116851e, 0xa68c2401, + 0x22092b45, 0x82120002, 0x250023a6, 0x5d432737, 0x09b4470f, 0x80800023, 0x10b147ab, 0x6060cb23, 0x141d484a, 0x40000131, 0xc0018000, 0x13008001, + 0x37010000, 0x4d152715, 0x3524062f, 0x21333634, 0x0128e282, 0x0d55556b, 0x0900ff09, 0x26058843, 0x5520010d, 0x834b55ea, 0x83d6200d, 0x02002e04, + 0x40002b00, 0xd501c001, 0x17000f00, 0x05934900, 0x22212324, 0x40833526, 0x05273325, 0x82332715, 0x46152745, 0x441b7a01, 0x47850606, 0x013a103a, + 0x0984ef95, 0xfed5010d, 0x04441b86, 0x09d6090c, 0xe4453a0c, 0x4b090cef, 0x6b2a4f82, 0x8b015500, 0x0500ab01, 0x4f820b00, 0x37332408, 0x25232711, + 0x16350714, 0x6b556b16, 0x2001556b, 0x01201636, 0xaafe6b40, 0x1b3b406b, 0x00330bac, 0x82950001, 0x84552031, 0x13002131, 0x95242f84, 0x566a6a56, + 0xd74e2485, 0x0002260a, 0x001e0012, 0x2fe78225, 0x01272715, 0x07062707, 0x27373635, 0x35232715, 0x3422a782, 0x62822726, 0x07141525, 0x82273627, + 0x080b8204, 0x2d00014e, 0x1b650178, 0x192d212c, 0x556b5b17, 0x55016565, 0x54412f3b, 0x350b2016, 0x1f163401, 0x2d5aab01, 0x1b9bfe42, 0x2c0b1c2c, + 0x905b1207, 0xa565806b, 0x2c0e4e33, 0x2f44690e, 0x1d1b212a, 0x2f340409, 0x0300320b, 0x45004000, 0xbb01c001, 0x1122cd82, 0x7c821700, 0x14161622, + 0x36207983, 0x17207182, 0x2520d784, 0x012fb384, 0x5454412b, 0x3b3b2f41, 0x1635352f, 0x84e0fe1f, 0x0ebb24ec, 0x82698869, 0x664e2a53, 0x3c8f0e4e, + 0x320bac1a, 0x46f98327, 0x754e08fb, 0x06ee4807, 0x51352721, 0x9b42058f, 0xab01280f, 0xebeb1556, 0x425601eb, 0x80250988, 0x556bc0c0, 0x21028255, + 0x6c422b01, 0x8204200c, 0x050650af, 0x0d000326, 0x29001900, 0x29056145, 0x32331527, 0x34353536, 0x114d2326, 0x4313200b, 0x01290e03, 0x564b2b35, + 0x090c0c09, 0x120a4d80, 0x0c806023, 0x201c8209, 0x05054d80, 0x4e000121, 0x193905c3, 0x122a0112, 0x00050019, 0x01310022, 0x00cf01d2, 0x000c0009, + 0x00170014, 0x0878821a, 0x2315334d, 0x35233735, 0x33051533, 0x17332727, 0x07232723, 0x07331723, 0x01372313, 0x7eb68250, 0x9cfeb17d, 0x23112a53, + 0x6d142760, 0x63b92714, 0x32653332, 0xb71b22a8, 0x6f821b22, 0x3434f42e, 0x6c013223, 0x00020032, 0x012b0015, 0x85c001eb, 0x071b4154, 0x11225682, + 0x61821121, 0x2e061c50, 0x01173713, 0x1a1a11c0, 0xfe555511, 0x83555580, 0x80403c09, 0x1ac00180, 0x1100ff11, 0x00012a19, 0x192a00ff, 0x11000111, + 0x806bfe1a, 0x45040080, 0x34240afb, 0x4f003b00, 0x1434ae82, 0x37373233, 0x26353536, 0x22232634, 0x15060707, 0x14371615, 0x232c0782, 0x22230622, + 0x27262627, 0x34353526, 0x33392182, 0x32333632, 0x17021e17, 0x23071516, 0x37350735, 0x36340733, 0x07173533, 0x053b4735, 0x14333539, 0x01262206, + 0x02050a1a, 0x09020204, 0x04030302, 0x02280303, 0x82040706, 0x0409230c, 0x06820602, 0x86060721, 0x0721080c, 0x59020404, 0x03261514, 0x6b476494, + 0x4c4c346b, 0x652b4c68, 0x07bc658c, 0x02040502, 0x0504042b, 0x2e208203, 0x0d13042b, 0x02060d04, 0x01040102, 0x870f1905, 0x0c02370b, 0x46350b06, + 0x1b0c0f06, 0x6b566446, 0x6a4b566b, 0x47354b4b, 0xdd8c6464, 0x47002727, 0x00008900, 0x20a29237, 0x92f19e37, 0x32232cf0, 0x34263535, 0x22062323, + 0x82231515, 0x36322e52, 0x16173233, 0x15061515, 0x07222314, 0x250a8216, 0x06060714, 0x33410607, 0x1533260a, 0x33331416, 0x21388636, 0xe78c5535, + 0x2441c720, 0x0202220a, 0x0624412a, 0x10072708, 0x03030402, 0x02040706, 0x04090208, 0x04040702, 0x020f7102, 0x04020b04, 0x01070b16, 0x0c0c0108, + 0x02040208, 0x04820905, 0x01040126, 0x09020704, 0x01202882, 0x12202b82, 0x02232484, 0x41eb0d04, 0x18200d11, 0x82144e41, 0x08092448, 0x41060b0f, + 0x02250559, 0x0d0b060c, 0x27528204, 0x0f080404, 0x0f040602, 0x04247e82, 0x08030505, 0x012a6782, 0x02040106, 0x01020102, 0x21841005, 0x04020b25, + 0x4202000f, 0x32380843, 0x00004600, 0x07150637, 0x15333723, 0x35320723, 0x33353634, 0x16173233, 0x420b1041, 0x33200541, 0x24077341, 0x23262727, + 0x12944127, 0x0207fa2d, 0x2533050d, 0x04030202, 0x82030804, 0x02092178, 0x08217b82, 0x2406820f, 0x11090207, 0x25f7820d, 0x04050202, 0x4741a902, + 0x03de300c, 0x0f2f0301, 0x01010213, 0x04010301, 0x820e0901, 0x0208222e, 0x2ab28408, 0x04020a0e, 0x040d0204, 0x410d0205, 0x27420d15, 0x4105430c, + 0x42493720, 0x0d054313, 0x4307e041, 0x5b251305, 0x03261514, 0x05714917, 0x4c684c26, 0x6b6b344c, 0x202d0543, 0x0e9e498f, 0x2609e343, 0x00350015, + 0x438b0077, 0x34220ae3, 0xe5433526, 0x54f34215, 0x2a141941, 0x02040b1e, 0x08020204, 0x82030402, 0x071f4406, 0x2041fa42, 0x13424133, 0x01040123, + 0x0c4a4402, 0x203dfb42, 0x0e6a41b5, 0x22090a43, 0x43480034, 0x0e221b0a, 0x4c450703, 0x0c0a4308, 0x3c423520, 0x07fc2312, 0x0a430f02, 0x05042410, + 0x430b0201, 0xf28c0f0c, 0x22140b43, 0x43010304, 0x0d4305c0, 0x8eb72009, 0x000331c4, 0x01400015, 0x00c001eb, 0x000f000b, 0x01000023, 0x25098a4e, + 0x21111715, 0xa3820111, 0x06140328, 0x23152323, 0x77462335, 0x06655806, 0x80feab35, 0x19128001, 0x6b111901, 0x19126baa, 0x2b011219, 0x8240402b, + 0x01963602, 0x0100ff00, 0xff12192b, 0x2b191100, 0x0112182b, 0x00191200, 0x2a6a8806, 0x0014000d, 0x002e001e, 0x82360032, 0x34352270, 0x2e5d8226, + 0x17333533, 0x07362733, 0x27072337, 0x86271723, 0x36322114, 0x240f2d4b, 0x23153317, 0x3a038225, 0x0e12c001, 0x1219204b, 0xb3131320, 0x15162026, + 0x13422520, 0x0d4b4b0d, 0x83150113, 0x82fe208a, 0x231c8298, 0x15012b2b, 0x0b2f0382, 0x80120e15, 0x092d2b2b, 0x49498036, 0x82402080, 0xee12240d, + 0x57fe1219, 0x2a26053a, 0x40a01912, 0xa1481540, 0x0011220a, 0x05594b1d, 0x84352521, 0x57fb83f7, 0x272006c0, 0xfd561182, 0x82072007, 0x2327250b, + 0x17353315, 0x0139a58f, 0x1b181ab5, 0x090d1b18, 0x950c0955, 0x35355555, 0x361a3635, 0x01371a1a, 0x07ad4e0f, 0xd5121836, 0x4b4b606b, 0x0c096b60, + 0x801b590c, 0x181b171b, 0x4b4b8065, 0xeb240282, 0x00ff1219, 0x0120c383, 0x94820582, 0x55005529, 0x80019501, 0x59000200, 0x0025059d, 0x27071725, + 0x21928233, 0x01841521, 0x6a2b0128, 0xababd66a, 0x0e4d0001, 0x40d53205, 0xd52a8040, 0x002b2a2b, 0x002b0005, 0x01d50195, 0x3344826b, 0x00180014, + 0x0020001c, 0x07273700, 0x15370727, 0x23230614, 0x2607f14a, 0x35171632, 0x82351533, 0x23172f51, 0x30e03335, 0xb5251b25, 0x1180111a, 0x04821919, + 0xaa2b1a22, 0xc0280083, 0x30203040, 0x1a118080, 0x1a2c1883, 0x2b2bbc1a, 0x802b2bd6, 0x0001002a, 0xab249e83, 0x0700ab01, 0x50097c59, 0x0b5105f7, + 0x24b68205, 0x01550015, 0x222182eb, 0x4a13000b, 0x04200d4b, 0x2b066457, 0x48386b01, 0x32233848, 0xaafe2332, 0x2e05ba51, 0x765c0ea5, 0x0d2c0e5c, + 0x0d474a47, 0x82658cbf, 0x08415b14, 0x0d00c026, 0x21001100, 0x33216d84, 0x20b98332, 0x20cd8223, 0x07ab4222, 0x2c0be754, 0x071a26ab, 0x26406b0e, + 0x80feef34, 0x20bb8401, 0x2f0584fe, 0x042634a6, 0x1a962b84, 0x2a011525, 0x5501d6fe, 0x5b0c9a58, 0x022c09f7, 0x16001200, 0x00001a00, 0x25152725, + 0x2c0e644c, 0x35211527, 0x21352105, 0x01805501, 0x07b54d00, 0x1156013e, 0x00ff5519, 0xaafe2b01, 0x45ab5601, 0x11ab9b8b, 0xab111919, 0xc41a1a11, + 0x2b802a2a, 0x26066042, 0x008001eb, 0x84090005, 0x010027c6, 0x37270717, 0x3e512517, 0x82052006, 0xcb012a55, 0x20619520, 0xaad5fe41, 0x05d04156, + 0x200b0129, 0x40206096, 0x4e2a2a16, 0x00290515, 0x00150003, 0x01000220, 0x254682c0, 0x00280011, 0x43822500, 0x27372722, 0x290a4552, 0x15163237, + 0x21352315, 0xce432111, 0x06b84305, 0x82000221, 0x20402548, 0x2a40408b, 0xab280282, 0xfe2b1912, 0x2b400180, 0x2005bd43, 0x2d1b8480, 0x40402b4b, + 0x1955402b, 0xffaaaa12, 0xbc432a00, 0x09274408, 0x07000327, 0x00001b00, 0x205e8201, 0x181f4405, 0x1501aa22, 0x20121c44, 0x1718442b, 0x2c002c35, + 0xd401d501, 0x12000b00, 0x1f001800, 0x29002500, 0x4c000000, 0x35350873, 0x16370316, 0x26261517, 0x07171627, 0x06372726, 0x36362307, 0x08068237, + 0x37362736, 0x07061717, 0x516ed501, 0x3f56563f, 0x241eee51, 0x36431b30, 0x291e1d05, 0x061c4d06, 0x101c032b, 0x1e243090, 0x3f2b3f33, 0x5201413f, + 0x2b087aa4, 0x61806108, 0xfe220582, 0x1f841e8f, 0x242fa02e, 0x7e3f331f, 0x431b2f25, 0x1c062214, 0xa5263782, 0x00312f2f, 0x6e590002, 0x00132609, + 0x21352500, 0x10a04c15, 0xd6fe9526, 0x19122a01, 0x2207815b, 0x44d5d580, 0x675b06f2, 0x53052007, 0xab2206ed, 0x974c0900, 0x832d2006, 0x1523214a, + 0x21053344, 0x09823523, 0x2108fc44, 0x1f4f3632, 0x3317350f, 0xab012315, 0x1b1b351b, 0x2b208636, 0x204b0e12, 0xeb120e2b, 0x23093f44, 0xc02b2b20, + 0x29053144, 0x154b8080, 0x2b80120e, 0x3a44ad13, 0x158b210b, 0xdd45c682, 0x00032107, 0x2321c684, 0x10ff4c15, 0xc0c0c024, 0xc4821a11, 0x05838020, + 0x80806b22, 0x200e0e43, 0x08b54502, 0x09414286, 0x43c02012, 0x6b220d5e, 0x448e4040, 0x230d3d42, 0x01000017, 0x4506f54d, 0x00201037, 0xaa438e82, + 0x6b01270b, 0x2b562a2a, 0xa243ab2b, 0x83938e0c, 0x8c48924c, 0x95002346, 0x438ec095, 0x22071e59, 0x82100002, 0x33152790, 0x06141537, 0x29430523, + 0x01212406, 0x43207540, 0x002808d7, 0x16768b01, 0x011911ab, 0x20068551, 0x08825002, 0x51000b21, 0x0b5905e1, 0x13905009, 0x2b402b26, 0x802b4040, + 0x230d9650, 0x40402aeb, 0x35200282, 0x410f9c50, 0x6f410eb2, 0xeaab2421, 0x8c1501ea, 0x4f0320dc, 0x0a2b0811, 0x28001800, 0x27250000, 0x82072337, + 0x353323a3, 0xb8592717, 0x210c8305, 0xcf583315, 0x80012f10, 0x26253030, 0x5b262020, 0x20202015, 0xc95d2040, 0x40c0240a, 0x82303040, 0x2516821e, + 0x20604040, 0x728ce020, 0x2a091241, 0x001e000a, 0x27373700, 0x84332707, 0x41372071, 0xd5281211, 0x425a116b, 0xe9175e36, 0x280d1241, 0x5b116bc0, + 0x365e1743, 0x0d13410d, 0x28090f5a, 0x000d0007, 0x00190013, 0x096c461f, 0x07172727, 0x17270717, 0x22018237, 0x82273707, 0x82172001, 0x27072a79, + 0x3426c037, 0x70342626, 0x21008226, 0x0482894b, 0x8a4c2622, 0xe6200b8a, 0x26211c83, 0x8517908c, 0x0c002d23, 0x40002b00, 0xc001d501, 0x07000300, + 0x17227182, 0x73821b00, 0x27002322, 0x2f2b1782, 0x39003300, 0x15250000, 0x82373523, 0x83172003, 0x050762e4, 0x42031521, 0x138306d6, 0x0f8f0383, + 0x1133132c, 0x01331121, 0x2b2b2b80, 0x0482ab56, 0x2a2b2b22, 0x0b840085, 0xab2e0482, 0xd556fed5, 0x552b2bc0, 0xd5aa2a2a, 0x1f822a2b, 0x2a000127, + 0x2b2b562a, 0x8e138455, 0xd5fe250c, 0x01008001, 0x2008eb41, 0x2b94821c, 0x15151632, 0x26222314, 0x33333435, 0x38080b82, 0x07161714, 0x37171607, + 0x17323336, 0x09ab0116, 0xd695150c, 0x0c094a19, 0x2909040c, 0x0621652e, 0x24020509, 0x4a090cb8, 0x1595d619, 0x2427090c, 0x6024090d, 0x01062a31, + 0x3f56820c, 0x02ae0000, 0x006b0100, 0x0100001e, 0x14150722, 0x06070607, 0x26272722, 0x20363734, 0x07141617, 0x26370d83, 0x35352627, 0x34000126, + 0x19200c2e, 0x35061206, 0x01690606, 0x82066922, 0x06122d08, 0x320c2316, 0x420f4001, 0x180f050f, 0x64211185, 0x25238564, 0x0e051215, 0x3c481042, + 0x01953a06, 0x00080095, 0x15331300, 0x27073523, 0xd5c02337, 0xf81ef82a, 0xd595018d, 0x2907828d, 0x77000200, 0x89014d00, 0x2482b501, 0x26820c20, + 0x23173723, 0x3d268215, 0x37271335, 0x6060a017, 0x741e804b, 0x491e4980, 0x60605501, 0x731e8088, 0x48f8fe77, 0x5a82481e, 0x8d004024, 0xbe82c001, + 0xbe820a20, 0x27071722, 0x60825c82, 0xa201172b, 0x2b95c01e, 0x017762ab, 0x2308826b, 0x772bab62, 0x6b262a82, 0xab016b00, 0x6082ab01, 0x07010022, + 0x35272582, 0x01371533, 0x828df8ab, 0x8d012388, 0x87822af8, 0xe7488582, 0x00082707, 0x1300000f, 0x50821707, 0x35072726, 0x27153333, 0xd5348d82, + 0x652a7131, 0x3180d631, 0x013e1e3e, 0xb47131ab, 0x803165a2, 0x00200d84, 0x26094f48, 0x00070003, 0x8219000b, 0x2135298f, 0x23351715, 0x21153515, + 0x08098043, 0x34110721, 0x80013336, 0xabab00ff, 0x112b0001, 0xfe111919, 0x111955d5, 0x2b2b5501, 0x6b2b2b80, 0x55952b2b, 0x552a050d, 0x19118001, + 0x40000300, 0xdf849500, 0x00255585, 0x21152113, 0x20578207, 0x22038225, 0x822b0195, 0x2b012e3b, 0x2a0100ff, 0xab2b6b01, 0x2a562b2b, 0x2088972a, + 0x83308205, 0x11252303, 0xfc442127, 0x16322107, 0x514a8883, 0x55012407, 0x83d5fe55, 0x56012390, 0x8f831911, 0x2b2b4022, 0xd6270282, 0x1a5580fe, + 0x82000111, 0x05002319, 0xd6822b00, 0x0002d522, 0x202b5e59, 0x2f798211, 0x35211511, 0x44496b01, 0x1c287f49, 0x7b1c281c, 0xaa20f784, 0xfe296c85, + 0x182095aa, 0x20181e1e, 0x221982db, 0x5357281c, 0xfe270bf4, 0x022b2b55, 0x822b2b00, 0x00402179, 0x2805fc53, 0x00240020, 0x0036002a, 0x0706433a, + 0x82230621, 0x363427cf, 0x16323333, 0x09431515, 0x070a4305, 0x23353723, 0x052f4915, 0x62152721, 0x332405c9, 0x37152315, 0x012a0b82, 0x0c0c09ab, + 0x0cd59609, 0x08824b09, 0x2f090432, 0x2f265314, 0x04030807, 0x15162824, 0x40152b40, 0x5622fc84, 0x2084b516, 0x8296d521, 0x01093524, 0x090d2229, + 0x1453262f, 0x0c02072f, 0x2b1616e0, 0x40402b40, 0x15292d82, 0x6b6b2b16, 0x55000a00, 0x052e6100, 0x0f000732, 0x1f001700, 0x2f002700, 0x3f003700, + 0x4f004700, 0x2009bc57, 0x06795c16, 0x2105bf64, 0x0f873426, 0x2307915c, 0x34262236, 0x04201b83, 0x2f87278e, 0x5707145d, 0x1a2205d4, 0x02821a22, + 0x05849a20, 0x66200b85, 0xbc200b84, 0xfe210584, 0x8b188ac4, 0xeb01212a, 0x66200d84, 0x41830584, 0x8b221a21, 0x84c4200b, 0x20058517, 0x850b849a, + 0x85fe2005, 0x02002106, 0x2a08f148, 0x00150005, 0x07350100, 0x48171527, 0x01210fd7, 0x410083ab, 0x55260ae8, 0x2b6b6b2b, 0xd355c06a, 0x6749830c, + 0x0d2205b7, 0x49821a00, 0x23061425, 0x57110723, 0x310806e0, 0x15163217, 0x22232711, 0x21353526, 0x0d6b0135, 0x0c55d509, 0x09150109, 0x0c09550d, + 0x0c09eb55, 0x00011501, 0x01560c09, 0x0c0c092b, 0x090c4009, 0x1f82c0fe, 0x62c02b21, 0xc03c085a, 0x0d000600, 0x33250000, 0x35332707, 0x23172733, + 0x23352315, 0x55405501, 0x952a4055, 0x40380382, 0x96555595, 0x96965595, 0x40000300, 0xc0012000, 0x0800d001, 0x22001100, 0x07258882, 0x16173727, + 0x08d78216, 0x06273539, 0x17161415, 0x07171716, 0x22230627, 0x3435022e, 0x37273736, 0x31000100, 0x26794f1e, 0x669b1612, 0x2610161a, 0x3a1b07ed, + 0x471d3c2f, 0x10161d2a, 0x2b011b3b, 0x83309301, 0x2f6b3b1e, 0x6667d39a, 0x34162b22, 0x081b2610, 0x1d263a1b, 0x191d462a, 0x1b3b1340, 0xfc67d5fe, + 0x0015240a, 0x822c0019, 0x5c362075, 0x332f05a9, 0x16323634, 0x06070714, 0x34331515, 0x49350737, 0x232209ce, 0x9d4f2707, 0x41240808, 0x32463214, + 0x1a221a2a, 0x2a191a0d, 0xaa2a1919, 0x111a1a11, 0x55404055, 0x12191912, 0x1c142501, 0x23333323, 0x22341382, 0x211b1b0d, 0x921b220b, 0x55012b2b, + 0xd5fe1119, 0x40401a11, 0x2b232182, 0x41001812, 0xab2a057f, 0x1300d501, 0x00002400, 0xe5831613, 0x07070626, 0x3435042e, 0x1727e582, 0x27072237, + 0x63333636, 0x300809eb, 0x1b446dfa, 0x0a241048, 0x3414060a, 0x44042027, 0x1708b21b, 0x40124510, 0x24573e1a, 0x011f114d, 0x1b446c0b, 0x0b2e1847, + 0x4517070b, 0x0b1f5241, 0x2d218216, 0x13441267, 0x303e571b, 0x180f4e45, 0x73821f16, 0x2b006b24, 0x73829501, 0x18000726, 0x32120000, 0x20056d69, + 0x21648326, 0x7b85020e, 0x1f2cea2d, 0x091f2c1f, 0x2c1f577c, 0x84100f2b, 0x0b01216b, 0x1f2a1182, 0x3e57ab2c, 0x3d46501f, 0x60851112, 0xef443e20, + 0x08cf4b1f, 0x44087845, 0x7d4508ef, 0x2b40220d, 0x2102822b, 0x7e450001, 0x6201200b, 0x0d2208a1, 0x498e0000, 0xbb45ab20, 0x8bd52009, 0x09d24233, + 0x12000429, 0x11250000, 0x8f371121, 0xaafe233a, 0x7d89012b, 0x0001ab27, 0x012bd5fe, 0x28458d2a, 0x011d0033, 0x00c001c3, 0x2345830b, 0x27070113, + 0x0806ca4f, 0x15252729, 0x32333727, 0x75014e16, 0x080c281c, 0x381911d6, 0x32f26201, 0x01191196, 0x1c8cfead, 0x111a0629, 0xf90338ef, 0x481a32f2, + 0x13260d33, 0x36371716, 0x39821617, 0x14151522, 0x2b0b3345, 0x07161714, 0x2f5d308d, 0x28240c0a, 0x270d1445, 0x305d1a01, 0x0c050a2f, 0x370a0345, + 0x090d2428, 0x2b000300, 0xd5013500, 0x2200d501, 0x42003200, 0x17130000, 0x232c9f82, 0x35262207, 0x15062737, 0x26071714, 0x21068e5c, 0x0b871614, + 0x07221723, 0x0b484227, 0x3a661720, 0x08158805, 0x01154678, 0x01a01b65, 0x011a1104, 0x152a0922, 0x1e14231d, 0x15272e21, 0x2c2c3931, 0x1f252bd5, + 0x7d583d32, 0x6515201f, 0x32012331, 0x23040923, 0x4b351a16, 0xfe16cb01, 0x01a11b9b, 0x2204111a, 0x19311412, 0x233b1125, 0x2e1f1f26, 0x174f2e36, + 0x3a631c25, 0x052d394a, 0x7d1f1f14, 0x1f333c58, 0x65462927, 0x090423db, 0x23013223, 0x1a354b09, 0x00000400, 0x00024000, 0xac45c001, 0x002f3206, + 0x34262500, 0x27373337, 0x1614020e, 0x27371716, 0x058c4307, 0x60121521, 0x7d3e1736, 0x20230808, 0x0c23122a, 0x2a12230c, 0x50587520, 0x26349a58, + 0xea263426, 0x111a1a11, 0x058356fe, 0x2c15d537, 0x0e2b2a15, 0x2a2c2a32, 0x2a2b0e32, 0x251d1555, 0x01151d25, 0x22258200, 0x4b663426, 0x05200c59, + 0x0c639088, 0x00232905, 0x01000029, 0x15152335, 0x0528879e, 0x17352707, 0xaad50137, 0x01228093, 0x00824095, 0x80000124, 0x7b998080, 0x2a2a6b27, + 0x002b2b16, 0x24818204, 0x01000243, 0x310982d5, 0x000c0008, 0x1300002c, 0x17372726, 0x35231537, 0x08820717, 0x4a0c0d4a, 0x332e0e2b, 0x4a891632, + 0x6e4c1e02, 0x1e4cd82a, 0x084a554c, 0x1d1c2405, 0x4a682e0c, 0x91300a33, 0x2f01923c, 0x4c1f014a, 0x5b6a6a88, 0xfd4c1e4b, 0x2505274a, 0x0e050e1a, + 0x414a0f42, 0x823b200c, 0x005b2c83, 0x01a5012b, 0x000300eb, 0x6d1d0013, 0x1524061c, 0x15163237, 0x820bd652, 0x0717290f, 0x27072226, 0x32360736, + 0x01280984, 0x0a7d8040, 0x7a0a0e0e, 0x3d380483, 0x1e1d6028, 0x1e389e38, 0x7e2c0b45, 0x5a1f1f2c, 0xabab551f, 0xcf0a0ed5, 0xcf241c83, 0x28c00f0a, + 0x1d821e82, 0x2c2c8227, 0x001f1f1e, 0x083f6202, 0x00257483, 0x21152101, 0x068d4625, 0x29071952, 0xd6fe9501, 0x81fe2a01, 0x794e1119, 0x6b012709, + 0x1911d6d6, 0x04841119, 0x6b244482, 0x95011500, 0x0024b986, 0x11231125, 0x45078e4f, 0x308b08bc, 0x4e826b20, 0x7f01d624, 0xb6521119, 0x40568305, + 0x012f8988, 0x6b002b00, 0xab01d501, 0x00002100, 0x62231701, 0x92420549, 0x07332906, 0x34353327, 0x15163236, 0x2d05706d, 0x80012335, 0x46324055, + 0x1a221a32, 0x09885540, 0x56ab0133, 0x32322395, 0x1a119523, 0x5595111a, 0x33239555, 0x450c8633, 0x8d5515be, 0x08f04f09, 0x2705be45, 0x2a2b2b6b, + 0x16012b2b, 0x21097b45, 0x00842b15, 0x4b06ee67, 0x002f0735, 0x00029500, 0x07008001, 0x23000f00, 0x46240000, 0x23620663, 0x32242207, 0x054c6016, + 0x2308bb84, 0x26330714, 0x6c013435, 0x3e2b2b3e, 0x2c3eea2c, 0x012b3e2c, 0x4444622f, 0x31eafe31, 0x45624444, 0xc01b601b, 0x1c821382, 0x94200584, + 0x45201282, 0x2b2c1e83, 0x312b2020, 0x15000200, 0xeb018000, 0x19206c84, 0x20092d66, 0x06a65337, 0x2306063f, 0x36342622, 0x84163233, 0x221a1a22, + 0x2bdda319, 0x470d5d55, 0x4b4b3525, 0xd5472535, 0x2914831a, 0x5555563c, 0x6a4b3223, 0x4d82324b, 0x22051070, 0x831700eb, 0x08125eb8, 0x3526222b, + 0x33153335, 0x23152311, 0x084d8235, 0x17071721, 0x27072707, 0x17372737, 0x11950137, 0xd5111a1a, 0xd52b1a11, 0x111a2bd5, 0x15555555, 0x82155655, + 0x55562405, 0x421aeb01, 0x40280654, 0x2b56012b, 0x9a1a1140, 0x20821a87, 0x00030032, 0x01150055, 0x00eb01c0, 0x001d0007, 0x13000035, 0x4307d741, + 0xe3410e64, 0x07e14905, 0x8c8cd082, 0x1a13cb31, 0x100a5b13, 0x0a750b11, 0x250a1010, 0x8caf242e, 0x15012b90, 0x10100c20, 0x0b10200c, 0x24820a4b, + 0x0f0a4b28, 0x20201620, 0x9a8fb616, 0x00040023, 0x208e822b, 0x063743d5, 0x22001a23, 0x143b4300, 0x14160527, 0x27362707, 0x23068437, 0x2b012734, + 0x330a7b43, 0x14142b01, 0x42121215, 0x1d162828, 0x5601551d, 0x9601aafe, 0x01366787, 0xbc1a1180, 0x16133415, 0x26421819, 0x1f16256b, 0x03001c4f, + 0xb44b2a00, 0x00172406, 0x475d001f, 0xe38f09e4, 0x41420220, 0x17373206, 0x06070716, 0x07062727, 0x23231407, 0x26273522, 0x270e8327, 0x37373626, + 0x36342634, 0x37240f82, 0x17173637, 0x33260e83, 0x17153233, 0x0e831716, 0x2e831620, 0x06141622, 0x41053144, 0x263e08aa, 0x20171720, 0x04177816, + 0x05021602, 0x040b081b, 0x04062c05, 0x051b080b, 0x01011502, 0x02821701, 0x88010321, 0x05052419, 0x821c0e04, 0x21198529, 0x2e44ea01, 0x15403907, + 0x40152a01, 0xf0fe1a11, 0x15152015, 0x04120620, 0x02042503, 0x1c05050a, 0x0a2f0284, 0x01250402, 0x01120105, 0x02060407, 0x89040312, 0x0902221b, + 0x201b890b, 0x0a785707, 0x0a00062d, 0x00001a00, 0x17372313, 0x57231523, 0xd52a1371, 0x2a55552a, 0x80feeb56, 0x85598001, 0x00012b09, 0x41555555, + 0xd4fe2c01, 0x74595601, 0x0022080b, 0x00150002, 0x01eb0135, 0x000900a0, 0x25000026, 0x22232635, 0x33361507, 0x17320332, 0x23061411, 0x10832722, + 0x22200383, 0x26220c82, 0x1a821135, 0x36173d08, 0x2a21c001, 0x41343441, 0x2a4c2727, 0x02030407, 0x34413d29, 0x30364a2b, 0x04010301, 0x4a4b2b07, + 0xf6752b2b, 0x20f5200a, 0xfe202001, 0x010704c9, 0x17202016, 0x01040601, 0x20202039, 0xf653cc82, 0x00072b09, 0x01000017, 0x35012137, 0xde552707, + 0xab002711, 0x5601aafe, 0x8162abab, 0x1501280b, 0xd500ff6b, 0x62d56a6a, 0x02280e81, 0x55000000, 0xab010002, 0x2e051b57, 0x15273725, 0x33360706, + 0x21153317, 0x64223335, 0x21200558, 0x08053a43, 0x56150124, 0x2b176956, 0xfe559655, 0x18125500, 0x56011218, 0xcb191812, 0x0f2e5050, 0x2b7a3a6e, + 0xd512192b, 0x04821912, 0x001a1123, 0x24558204, 0x0100021b, 0x2f0982db, 0x00210012, 0x37000025, 0x06273736, 0x27070127, 0x37265787, 0x07140127, + 0x6f823727, 0x27072222, 0x032f6283, 0x95231533, 0x2022311d, 0x1ba5016e, 0x827dfe3a, 0x0e330863, 0x16bd0121, 0x02562276, 0x01700207, 0x10181211, + 0x28c0113b, 0xe41f220c, 0x3a1b5bfe, 0xd612182b, 0xfe210c13, 0x760c19ea, 0x012d4f20, 0x12186f01, 0x512b00ff, 0x13250d40, 0x23371737, 0x2b598235, + 0x1e400735, 0xab6277a2, 0x4d01952b, 0x2b2d0882, 0x009562ab, 0x00550003, 0x01a10155, 0x25fc82a1, 0x0019000f, 0xe9821300, 0x26342324, 0x07863523, + 0x34152d08, 0x14163236, 0x26222306, 0x3d7c5855, 0xc3893e59, 0x1b719f3c, 0x131b1a28, 0x29011b14, 0x593e587c, 0x7189c3b5, 0x1b13e19f, 0x1b1b281a, + 0x22067a4c, 0x82d501d5, 0x452d204f, 0x26200937, 0x25053f41, 0x06272223, 0x5a462622, 0x2634260b, 0x16140622, 0x829d8233, 0x05d75317, 0x7db01838, + 0x18271f2b, 0x3f3f5820, 0x1a133f58, 0x658c6513, 0x6b6b4665, 0x14547d58, 0x7def2705, 0x2c201f58, 0x1c822020, 0x1f2c3f29, 0x0d14140d, 0x8265461f, + 0x7d2a2223, 0x47cd82b0, 0x072f07a3, 0x1b000b00, 0x22250000, 0x35373607, 0x47170717, 0x112713ad, 0x52142343, 0x445a4444, 0xe6270a69, 0x240b5a2f, + 0x47563f40, 0xab5014bb, 0x000b2207, 0x0e6a5d28, 0x2622dd87, 0xb1503435, 0x08ba5305, 0x01161729, 0x402b40c0, 0x4b2b2b40, 0x2f280d84, 0x092f5e2f, + 0x8001240d, 0x40221b83, 0x8c4bcb40, 0x5c2f260e, 0x04092f31, 0x0abe430c, 0x1f20ce83, 0x23467682, 0x0f0d650b, 0x11211126, 0x371e3701, 0x1b580288, + 0x8001250a, 0x550180fe, 0xa2201b8a, 0x270ba64a, 0x2c01a9fe, 0x0400d4fe, 0x240a2e58, 0x00170007, 0x236f821b, 0x27231533, 0xeb4c0382, 0x26222308, + 0xe4821135, 0x6b830120, 0x2b2b1527, 0x012b2b55, 0x09825800, 0xaa226685, 0xd356aaaa, 0x2e5f880d, 0x01550040, 0x00c001d5, 0x001a0005, 0x8226001e, + 0x3537265f, 0x17152707, 0x0b674323, 0x2223262b, 0x16141506, 0x15233517, 0x062f5136, 0x95000126, 0xb6b69595, 0x013b6883, 0x1b1a112a, 0x013f2c1a, + 0x3e0c5594, 0x2c3e2b2b, 0x2a4b2001, 0xd62a4a4a, 0x83d5111a, 0x0f992e1f, 0x07022c3f, 0x56161602, 0x2c2c3e2c, 0x22d4823e, 0x822b0054, 0x00bf2474, + 0x650f0009, 0x13210592, 0x2b578236, 0x22260717, 0x33361707, 0x27071732, 0x0807634a, 0x8b012124, 0x392e3910, 0x501d1c10, 0x19111b1c, 0x97291118, + 0x1c3eb23e, 0x01339133, 0x01abfe66, 0x104b0155, 0x1d821717, 0x111b1d2e, 0x3e962911, 0x33331b3e, 0x5501c5fe, 0x8a6ece82, 0x05c46a07, 0x2900212e, + 0x22240000, 0x16332726, 0x06333732, 0x200ffa6e, 0x05034316, 0x07871420, 0x4a25012c, 0x19230d3b, 0x0d231962, 0x8d788ca6, 0x1a972609, 0x131a1313, + 0x27058483, 0x2a21298b, 0x655f212a, 0x01271e83, 0x7db07d1b, 0x8243b07d, 0x2202871c, 0x42000800, 0x0324079d, 0x0b000700, 0x1320e982, 0x2627eb82, + 0x00002a00, 0x43153337, 0x078205fe, 0x0b8a1720, 0x260dda51, 0x11210533, 0x842b9521, 0x80562100, 0xc2350084, 0x070c0c07, 0x0b08a6fe, 0xfe420113, + 0xc02a01d6, 0x802a802b, 0x8301822b, 0x080b2305, 0x1f83a6fe, 0x135a0130, 0x00d6fe2b, 0x00020009, 0x01dc0100, 0x7f8b00da, 0x22001e2f, 0x00003000, + 0x23273325, 0x15233527, 0x87038217, 0x270b8307, 0x27070103, 0x05271121, 0x27269482, 0x15332715, 0x1d831133, 0x3533272a, 0x2a550001, 0x2a2a2b2b, + 0x90830482, 0xc0013934, 0xabfe401c, 0x2b530129, 0x933eaa2b, 0x3eab2ad5, 0x1b836b13, 0x2a2a5523, 0x085e57aa, 0x42fe6f34, 0x5501401c, 0xaa2aa929, + 0xfe553e13, 0x13be2bec, 0x96822a3e, 0x50006b21, 0x112a0597, 0x00001b00, 0x15163212, 0x6a4c0714, 0x35262508, 0x33351334, 0xc22a0e86, 0x0c40577c, + 0x0c098009, 0x3a685540, 0xd5013205, 0x2f4b3e57, 0x0c0c0931, 0x4e2c3109, 0x15c2fe3e, 0x560b8215, 0x95240673, 0x0b009501, 0x2326db82, 0x23352315, + 0x45823335, 0x95013325, 0x82802a80, 0x83eb2002, 0x77802004, 0x25200f7a, 0x2005bb59, 0x59e78215, 0x6b2611b9, 0x56562a56, 0x1378802a, 0x83eb2009, + 0x5656220f, 0x0cb568d5, 0x21098550, 0x125c000b, 0x08ba5a05, 0x20076954, 0x25498501, 0x7d7db06d, 0x44867db0, 0x0371ea20, 0x451b2013, 0x127b099d, + 0x879b8208, 0x050060ce, 0x2005167b, 0x219a82ea, 0x18605656, 0x067c4205, 0xaf841320, 0x5a005621, 0x032d09ac, 0x1e000a00, 0x21130000, 0x37132127, + 0x20978323, 0x0b0d7925, 0x36373734, 0x17322133, 0x1426016d, 0x758100ff, 0x014a564a, 0xdc850a2b, 0x1d0a2108, 0x00010f0a, 0x95010a0f, 0x75e0fe16, + 0x0c902b2b, 0x11f6fe0f, 0x01111a1a, 0x240c0f0a, 0x02000c0c, 0x2008444f, 0x05d15f0b, 0x07273729, 0x07170727, 0x4d173717, 0x21230782, 0x82272722, + 0x95012861, 0x4c1e4c4c, 0x824d1e4d, 0x5e4c2102, 0xfe284383, 0x730e14c0, 0xb3140e73, 0x18851283, 0x2b014d22, 0x13237885, 0x8213adad, 0x07bb43c1, + 0x11000829, 0x00001900, 0x6d363225, 0x27280588, 0x37171614, 0x06222326, 0x26098544, 0x0f156546, 0x736f2df0, 0x1d410650, 0x65552805, 0x133e1846, + 0x84ab24f0, 0x8f652105, 0x25056c41, 0x006b0001, 0x2442016b, 0x4b012006, 0x77220cd8, 0x02871e77, 0x8a770121, 0x4b8a840c, 0x032405b9, 0x1c001300, + 0x2c15284b, 0x11211537, 0x36341123, 0xea950133, 0x84e183ea, 0xffaa2b04, 0x11192a00, 0xfe2b0140, 0x0e5401d5, 0x111a2606, 0x19112b01, 0x22118356, + 0x441a112b, 0x04330aa3, 0x10000800, 0x35001800, 0x33010000, 0x06270715, 0x6f223432, 0xb7530967, 0x01172705, 0x07272315, 0x24721516, 0x27372408, + 0x47222306, 0x142a05ba, 0x95409501, 0x1616202b, 0x65562286, 0x33058305, 0x40070179, 0x32073295, 0x23323246, 0x32320f14, 0x3223140f, 0x012d0c82, + 0x2b9615c0, 0x19b6164b, 0x24191924, 0x240584e7, 0x15f8fe11, 0x211f8795, 0x33873207, 0x0003002f, 0x012b0040, 0x000002c0, 0x000f0007, 0x24fd8425, + 0x23352315, 0x17aa5111, 0x36363330, 0x01171632, 0x2ad62a95, 0x0c0c129e, 0x3e430c12, 0x1a113206, 0x0759111a, 0x07202a20, 0x40560155, 0x01aafe40, + 0x821c8280, 0x08125e02, 0x19115626, 0x13181813, 0x080aa143, 0x0e000925, 0x07010000, 0x32363727, 0x14161717, 0x07173705, 0x27ba0123, 0x12062750, + 0xfe063206, 0xec50ec80, 0x836a0150, 0x210e820f, 0x0e82e012, 0x20082f57, 0x20b982eb, 0x23ad8212, 0x05072737, 0x2a096862, 0x16173737, 0xb0b00001, + 0x858501b0, 0xc1142976, 0x6eeb14c1, 0xd5046767, 0xd5259f83, 0x71710c19, 0x24f3840c, 0x01c00180, 0x06364580, 0x35370030, 0x21251521, 0x35172115, + 0x01801533, 0x1a82fe00, 0x9580fe37, 0x2a2aeb56, 0x2bd52b95, 0x0001002b, 0x0140006b, 0x00ab01ab, 0x2faf8209, 0x27231533, 0x11231523, 0x78330133, + 0x2a780896, 0xd5242d82, 0x6b01952a, 0xf15a2682, 0x00063507, 0x17350100, 0x35233507, 0xabab0001, 0x565501ab, 0xaa56abab, 0x3d20bc82, 0xc0264782, + 0x0800c001, 0xbc824500, 0x3736322b, 0x14150606, 0x36272716, 0x06d05337, 0x06070626, 0x37323316, 0x17200f85, 0x06216a82, 0x05935906, 0x2e378908, + 0x07222304, 0x0607020e, 0x3e343526, 0x27363703, 0x0e280126, 0x201e041c, 0x0a25c00a, 0x131f1b08, 0x0b1c1c23, 0x09080506, 0x301b160f, 0x03292a39, + 0x3e063435, 0x3c281c21, 0x05010137, 0x1c0a0e07, 0x180d113b, 0x0b32230b, 0x010f1012, 0x74070b11, 0x26082625, 0xf909070d, 0x1b080c24, 0x281e1f1e, + 0x18112427, 0x3c241612, 0x45352237, 0x211b273e, 0x06080a48, 0x4905060d, 0x03140f15, 0x0f24300b, 0x161b2224, 0x03041c01, 0x200cc041, 0x28c68219, + 0x33152135, 0x36321614, 0x10296135, 0xfe952008, 0x342656d5, 0x19125526, 0xd5fe111a, 0x12181812, 0x1ad5d5c0, 0x011a2626, 0xfe121900, 0x6e1a11d6, + 0x03210618, 0x07776500, 0x13000f22, 0x2906ac4f, 0x23230614, 0x36323335, 0x07822634, 0x33350724, 0xb24a2415, 0x33363608, 0x22231533, 0x3e2c6b01, + 0x56562c3e, 0x1b27271b, 0xfeaa6a56, 0x200682fe, 0x2d128656, 0x583f6b01, 0x3627293f, 0x2a802927, 0x0682302a, 0x3c420e83, 0x00ab2108, 0x23436c59, + 0x01d50155, 0x012449c1, 0xab002100, 0x3f084982, 0x000e006b, 0x15370100, 0x23263723, 0x27070622, 0x32333636, 0xc04c8901, 0x333e304e, 0x1632105f, + 0x01554975, 0x4dc04d1e, 0x10314428, 0x01005644, 0xeb006b00, 0x15019501, 0x00000300, 0x21352125, 0x21054b53, 0x0c4c2aeb, 0x0003220a, 0x491b820b, + 0x6b220bd0, 0xa24613d6, 0x462a2006, 0x1320149e, 0x20119e46, 0xad411817, 0xd66a220e, 0x0c9346d6, 0x822a4321, 0x05fa638b, 0x0800953e, 0x16130000, + 0x23261716, 0xd5372715, 0x4d127168, 0x0195959e, 0x5b810f40, 0x9595576d, 0xf34d9982, 0x83278305, 0x222987ec, 0x82170707, 0x1501212f, 0x80223086, + 0x358a5555, 0x55554025, 0x46959540, 0x86470cf2, 0x16152107, 0x08064950, 0x15171321, 0x35272307, 0x2a150137, 0x1111160a, 0x706c1116, 0x7070a070, + 0x5c8080eb, 0x10101611, 0x83200116, 0x70a0210e, 0x1925458e, 0x35010000, 0x18458a23, 0x290c4640, 0x347bd540, 0x26342626, 0xaf6455ab, 0x82012007, + 0x82d5208b, 0x34262611, 0xff552f01, 0x08bd4200, 0x064a1220, 0x1c210814, 0x24002000, 0x2c002800, 0x36003100, 0x3e003a00, 0x46004200, 0x00004b00, + 0x35331513, 0x15333507, 0x20038603, 0x20078237, 0x210b8527, 0x08830614, 0x15221c84, 0x20833523, 0x2622152a, 0x32013335, 0x27231516, 0x19831182, + 0x2e861320, 0x36342729, 0x80c01533, 0x822bd6ab, 0x05b34900, 0x2b111a2d, 0x2b552ad5, 0x1a112b55, 0x822a012b, 0x2a802d04, 0x2b2a2bab, 0x1a2b2b80, + 0x80400111, 0xd6272b82, 0x2b2b0001, 0x822babfe, 0x822b2023, 0x00ff2105, 0xab212a82, 0x2125822a, 0x2582012b, 0x82d5fe21, 0x822a8218, 0x2b2b21f1, + 0x1f823683, 0x1e822b20, 0x4a82aa20, 0x39820020, 0xf76a0020, 0x00053505, 0x25353700, 0x2b053525, 0xc0fe4001, 0x9540c001, 0xc0952b2b, 0x20195645, + 0x29b18215, 0xff000140, 0xfe800100, 0x55458080, 0x47032008, 0x320806ac, 0x000200ab, 0x000e000a, 0x33070100, 0x37230707, 0x27231733, 0x21152107, + 0x50280001, 0x652c145d, 0x142c6520, 0xfe2a01ca, 0x6b8001d6, 0xebeb2f26, 0x842a5a2f, 0x01ab238c, 0x354301df, 0x32280805, 0x26071716, 0x07222326, + 0x17352317, 0x490b0136, 0x11321774, 0x303e3859, 0x3f4cc04e, 0x44565501, 0x28413410, 0x374dc04d, 0x200a7748, 0x05954c07, 0x03332527, 0x37330323, + 0x0fba4433, 0x1737172d, 0x6d2d5401, 0x182d6d28, 0x76116f78, 0x7f290865, 0x01752c2c, 0x40eafe16, 0x09ea6401, 0x19115625, 0x427676f5, 0x06240a5b, + 0x20001000, 0x2721ce83, 0x20f98233, 0x191e4517, 0x55555525, 0x456a562a, 0x11210623, 0x0723451a, 0x562b0126, 0x6b404056, 0x4a072945, 0xfa490c8c, + 0x07172314, 0x6a821533, 0xfa493720, 0x0a41211d, 0x4905c842, 0x76330af9, 0xd12b2b75, 0xf6fe100c, 0x12191a11, 0x0c100a01, 0x410c0c23, 0xc02f0823, + 0x09000500, 0x00002300, 0x07273737, 0x82110717, 0x32352562, 0x33151516, 0x7506784f, 0x352c08ff, 0xeb333634, 0x40165555, 0x19115640, 0x360a7d74, + 0x75111956, 0x40155556, 0x2a0a0140, 0x12192b2a, 0xeb111a2a, 0x82191911, 0x2a1a2304, 0x97571a11, 0x0011250a, 0x01000027, 0x06285683, 0x21151506, + 0x27263435, 0x04205383, 0x0d83688d, 0x012f1b82, 0x131a1180, 0x1800ff18, 0x01111a13, 0x541a222f, 0x22370693, 0x012a011a, 0x2e111995, 0x2c152007, + 0x0720152c, 0x6a19112e, 0x836b111a, 0x116b2170, 0x40222582, 0x0b781140, 0x0011260c, 0x00190015, 0x8278821d, 0x37332471, 0x4c031733, 0x25200893, + 0x2006b04d, 0x2b078215, 0x00ff2b01, 0x16551540, 0x1119d5ab, 0x01317982, 0x95808000, 0x01555595, 0x162a2a95, 0xd5ebfe16, 0x255b82d5, 0x2a802b91, + 0x0d6d2b80, 0x6b952008, 0x1e240605, 0x34360000, 0x2a05ab46, 0x33161406, 0x07173533, 0x4e222335, 0x2b2f0b19, 0x4b4b3951, 0x28383828, 0x0b40400b, + 0x84aaaf39, 0x72d22f00, 0x50382a51, 0x40402a38, 0xa02b2b2b, 0x4e4da02b, 0x057f4805, 0x1100072d, 0x35250000, 0x15232723, 0x48351733, 0x80310989, + 0x806b156b, 0x15968016, 0xd5aa2a6b, 0x2b802b80, 0x059248ab, 0x95650320, 0x001a2d08, 0x002d001e, 0x01371300, 0x35232707, 0x33240282, 0x15060627, + 0x08075247, 0x36343523, 0x23151737, 0x16323727, 0x27071415, 0x34353636, 0x35232326, 0x65011b2b, 0x3025561b, 0x192c0f3a, 0x055e4722, 0xe81c262b, + 0x2c442a04, 0x151f3a3e, 0x0811821c, 0x1ba50121, 0x551b9bfe, 0x2c2a3125, 0x1b192503, 0x2c3f2927, 0x4e0b3a1e, 0x3f562a2a, 0x1f1e412c, 0x82172405, + 0x03002b13, 0x15001500, 0xdb01db01, 0xc0820700, 0x280a044d, 0x07270717, 0x37352723, 0x087d8227, 0x33372736, 0x27071517, 0x1116f535, 0xf7111611, + 0xa0234d1b, 0x1b4e2370, 0xa01752bb, 0x8f941770, 0x10101611, 0x4e1b7016, 0x23a07023, 0x14701b4d, 0xa0701752, 0x003f9317, 0x096b4518, 0x1600082f, + 0x37250000, 0x37270717, 0x17333517, 0x08174a33, 0x2115332c, 0x1e381501, 0x381e6b6b, 0x864c802a, 0x012b2406, 0x8337f22a, 0xce372912, 0x1a1195c0, + 0x9595111a, 0x40219c82, 0x05196300, 0xcf4f0320, 0x7c1f2006, 0x372705f6, 0x07231533, 0x87233533, 0x21012107, 0x2409f763, 0x06141115, 0x201b8227, + 0x26038235, 0x15404095, 0x84156b6b, 0x15012305, 0x5783d6fe, 0x822a0121, 0x6b912105, 0xd5200082, 0x80271c82, 0xfe6b1640, 0x84111ac0, 0x83112015, + 0x2b602321, 0x844c2b6a, 0x0002280a, 0x00190010, 0x82330100, 0x20c083c4, 0x4c698623, 0x2b2b0981, 0x80157575, 0x11eb111a, 0x4c111a19, 0x01250581, + 0x80207500, 0x4c6c84d5, 0x03240b7c, 0x4b004000, 0x2506a448, 0x0016000d, 0x53822500, 0x26173722, 0x3e05514c, 0x23170714, 0x33363435, 0x4a011732, + 0x6d2c1e4a, 0x3346c71e, 0x80324633, 0x3675c040, 0x824b060f, 0x1e6e2312, 0x13833229, 0x2b409d25, 0x82012f26, 0x004026a3, 0x01c0012b, 0x22a182d5, + 0x82280014, 0x203c83a3, 0x06c95c17, 0x34262728, 0x07273737, 0x7541021f, 0x33373508, 0x21072317, 0x01372327, 0x0b090610, 0x06066a04, 0x06120688, + 0xe3380682, 0x7f4b694c, 0xfe121940, 0x401911d5, 0x262b2a12, 0x29252a01, 0x06cf012a, 0x12251c82, 0x06068706, 0x2d278269, 0x4b6a4c0f, 0x12564002, + 0x56111918, 0x00822b40, 0x00040025, 0x824e002b, 0x00b230ce, 0x003b001d, 0x00770059, 0x17320000, 0x56153316, 0x062005f4, 0x23240686, 0x36373235, + 0x32221782, 0x1b9a3737, 0x06323622, 0x16203b9c, 0x01361d9c, 0x18223a4e, 0x1a221d13, 0x221a1211, 0x121a223a, 0x1d221a11, 0x0a821813, 0x18281825, + 0x8e111a7e, 0x821d8219, 0x1a242424, 0x9a3a3a22, 0x36242237, 0x83539224, 0x18282a15, 0x0c115301, 0x0d0d112a, 0x28038311, 0x11110c2a, 0x0d5f0c0c, + 0x20108729, 0x20178529, 0x212390be, 0x358b124d, 0x0c121226, 0x0002000c, 0x2b079a51, 0x00160005, 0x27373700, 0x36072707, 0x260b3062, 0x6e1e8cdf, + 0x622d1e2c, 0xd5260b30, 0x2d6f1e8d, 0x2f62b51e, 0x01552f13, 0x006b01d5, 0x001b000b, 0x00290025, 0xcd500100, 0x0fb04b0a, 0x26340526, 0x33352323, + 0x252c6b82, 0x01231533, 0x2a404095, 0xe8fe4040, 0x200bb64b, 0x280c8533, 0xaaaad6fe, 0x2b400001, 0x20028240, 0x06bd4b1b, 0x271b4227, 0x152c3f29, + 0x2343182a, 0x681d200e, 0x1320091c, 0x15205982, 0x24056752, 0x35262221, 0x08028235, 0x3336342e, 0xaafeab01, 0x10eb80eb, 0x0f1c151a, 0x1c0fd6fe, + 0x01101a15, 0x9640406b, 0x00012b2b, 0x18411119, 0x1911f10c, 0x0cf11119, 0x19114118, 0x2408af4f, 0x000700d8, 0x0720460f, 0x4b183620, 0x372a0e6a, + 0x27071715, 0x27072735, 0x03820537, 0x0e7fc220, 0x55cb2e0a, 0x62436510, 0x4801621b, 0x551b621b, 0x090a7f58, 0x32701b2d, 0x63803c1a, 0x52522052, + 0x88205321, 0xb7da2066, 0x64112366, 0x66846342, 0x861c6321, 0xa0703266, 0x1aa07070, 0x3e1a3371, 0x20516280, 0x54205151, 0x0a294120, 0x0d000522, + 0x0021cd82, 0x5bb98401, 0x81520780, 0x0b012507, 0x31701060, 0x280a0355, 0x39706b01, 0xfe80441b, 0x0bf954ea, 0xd82ab488, 0x13000b00, 0x1f001b00, + 0xef412300, 0x3640180d, 0x15012717, 0x402a4040, 0x28412940, 0x3740180a, 0x41402009, 0xeb2005e5, 0x180a2c41, 0x53083740, 0xc0260579, 0x0f00d501, + 0xbb461a00, 0x17152706, 0x35072715, 0x03823537, 0x0a823720, 0x35273908, 0x16323634, 0x011b4015, 0x2b7b1b50, 0xaa2a4a4b, 0x44ab6b7f, 0x131a13a7, + 0xfe1b9001, 0x4f7a1bb0, 0x15152020, 0x35752020, 0x6b1b502a, 0x4ea7152a, 0x0d13130d, 0x2b000100, 0x2406cb44, 0x25000014, 0x85548a27, 0x1715244f, + 0x84abc001, 0x82aa204e, 0xabab234a, 0x46887535, 0x83756b21, 0x6b752541, 0x95000300, 0x6b204382, 0xe0719d82, 0x35252106, 0x60056d55, 0x332e0fa1, + 0x01153335, 0x2a2a2a15, 0x11110c63, 0x04839c0c, 0xd5562339, 0x2b556b6b, 0x112b012b, 0x0cb9fe0c, 0x010c1010, 0x2a110c47, 0x8802002a, 0x00052a54, + 0x37000019, 0x07352337, 0x0b2d5e33, 0x36341123, 0x24508333, 0x552b55eb, 0x24508b2b, 0xa076a055, 0x204d8ee0, 0x234d8801, 0x01000013, 0x4606b958, + 0x96840751, 0x928a4e20, 0xcdab0121, 0x0920413e, 0x18001427, 0x00002c00, 0x10946725, 0x460f9367, 0x9a8406ec, 0x260f3130, 0x12202634, 0x1409121c, + 0x0f122214, 0xaa8a6228, 0x150ff12a, 0x1a26261a, 0x1a13130d, 0x17271d82, 0x29611210, 0x8e2a0129, 0x00032ebe, 0x012b006b, 0x00d5017a, 0x00050002, + 0x087f8213, 0x1115272d, 0x07333715, 0x35230717, 0x27372707, 0x33351737, 0x28283d01, 0x7a5c5c3d, 0x771e6215, 0x15621e77, 0x015129a4, 0x5c295108, + 0x85a2795c, 0x82a22011, 0x07f8463b, 0x0600032f, 0x17000900, 0x00001b00, 0x27071701, 0x204f9207, 0x25588207, 0x2b2b9501, 0x578d2e2a, 0x2b2a6b25, + 0x822b012b, 0x905c2000, 0x82d52060, 0x03002315, 0xac825500, 0xac84ab20, 0x16000d22, 0x3723ac82, 0x82012727, 0x24aa8563, 0x35271517, 0x2a728233, + 0x28150137, 0x3801a228, 0x835c311e, 0xc08d30b1, 0x417a152a, 0x287c221e, 0xc8fede29, 0x835b311e, 0x098d28b4, 0x796b2b45, 0x8a231e41, 0x050141b9, + 0x22001c22, 0x20150541, 0x05f64917, 0x07273423, 0x24098337, 0x28281301, 0x0a14413c, 0x211fcc29, 0x56151519, 0x410a0a31, 0x642e111e, 0x353c3d32, + 0x2a582a19, 0x18193156, 0xc8821919, 0x0f000f27, 0xf101f101, 0x08624d00, 0x07232731, 0x37333733, 0x23150717, 0x35232707, 0x82353727, 0x0733330c, + 0x31011737, 0x452a4529, 0x89440f29, 0x47644646, 0x05856447, 0x1919c427, 0x2ac0c0ab, 0x24108872, 0x4eb94646, 0x22588c4e, 0x6c1f000f, 0x3e550b07, + 0x8e252005, 0x46dd2d60, 0x32463232, 0x4b4b6a20, 0x2b014b6a, 0x0121618b, 0x22188255, 0x82a34632, 0x6a4b2218, 0x22678a7c, 0x8b000200, 0xbf5218bd, + 0x8c052008, 0x171522b9, 0x895486cb, 0x804621b4, 0x12204c84, 0x6d83c386, 0x05264c8a, 0x00001500, 0xa7823225, 0x8e172321, 0x0001264a, 0x354b4b35, + 0x20498eab, 0x2a478dc7, 0x012b002b, 0x00d401d5, 0x841e0012, 0x17372147, 0x27071654, 0x15060615, 0x16131614, 0x0805c041, 0x2634353c, 0x1d000127, + 0x40381344, 0x6f7d586c, 0x574a3651, 0x126f5153, 0x364a0a38, 0x2117216b, 0x53587d57, 0x08400879, 0x573e3854, 0x79086901, 0x21273053, 0x54381a1c, + 0x00040008, 0x726d0055, 0x000d2605, 0x00190013, 0x4d668227, 0x3520080f, 0x37280982, 0x17372707, 0x37271707, 0x25200682, 0x77063963, 0x01360532, + 0x11192a6b, 0x2a1911d6, 0x62621e40, 0x1eb7431e, 0x621e4343, 0x1486eafe, 0x552a6b29, 0x111a1a11, 0x83512a55, 0x6244271d, 0x1e44441e, 0x14839562, + 0x82190121, 0x03002215, 0x05145200, 0x0982ab20, 0x20001322, 0x23207683, 0x08109966, 0x3315252a, 0x33352115, 0x33363435, 0xd5011521, 0x0c096b55, + 0x0980090c, 0xfe090d0d, 0xd5fed6ea, 0x0111192b, 0x96969580, 0xd5090cc0, 0xd52c1483, 0xeb2b0c09, 0x11eb4040, 0x06002b1a, 0x5b0c5e5d, 0xdc8205a3, + 0xc2821320, 0x03823720, 0x07870520, 0x28169877, 0x2a2a2a95, 0xeaea2a01, 0x059e77ea, 0x821a1121, 0xaa6b22b5, 0x27d2836b, 0x2b2b0001, 0x552a2a55, + 0xc02d0584, 0x00ff0001, 0x111a2b01, 0x191100ff, 0x2290832b, 0x821a1100, 0x00152bd2, 0x01eb0115, 0x000700eb, 0x7682001f, 0x26074a48, 0x23153325, + 0x82070606, 0x26262d7c, 0x33352327, 0x35373636, 0x16161533, 0x4807505a, 0x012a0554, 0x072c2c54, 0x3f2a3f64, 0x08870764, 0x3246db2c, 0x6b324632, + 0x57577c57, 0x188b537c, 0x01202184, 0x32231b82, 0x82020046, 0x427689f3, 0x749708c4, 0x66976c98, 0x0927d78a, 0x32001c00, 0x4e250000, 0x3225064c, + 0x01370136, 0xb04f1807, 0x20d98607, 0x20ec8305, 0x09a46a07, 0x0131ea85, 0x120dd15b, 0x35153e57, 0x011bf6fe, 0x2d2c1b65, 0x31ce8537, 0x010f1a02, + 0x052c2c53, 0x570b2010, 0x201b1e3e, 0x1782251f, 0x11d18a30, 0x573e1535, 0x1b280112, 0x2c1b9bfe, 0x0f410625, 0x3b172f05, 0x272a6412, 0x1e1b201d, + 0x200b573e, 0x15830510, 0x419d9c40, 0x0521609a, 0x09ac4600, 0x2d07935e, 0x15330100, 0x33110723, 0x33352511, 0x07821715, 0x03822720, 0x2b95013b, + 0xfe2b552b, 0x2a802bd5, 0x2b012b80, 0x00015556, 0x565500ff, 0xaa01aa56, 0x490c85fe, 0xd5320625, 0x0200d501, 0x21250000, 0xfed50101, 0x2baa0156, + 0x1982aa01, 0x36000828, 0xc001f801, 0x0a470900, 0x37303805, 0x17323627, 0xb501b401, 0x794401b5, 0x170179fe, 0x01e0e001, 0x4a555554, 0x18240a84, + 0x2c001c00, 0x11222e82, 0x8f821121, 0x35331532, 0x15161523, 0x26220614, 0x35373435, 0x13333634, 0x55068343, 0x80200c86, 0x2a2c9482, 0x1a1640aa, + 0x19161a22, 0xaafe9611, 0x820c5d64, 0x0001341d, 0x30aaaa2b, 0x1a11190c, 0x0c19111a, 0xfe1a1130, 0x825601d5, 0x19802826, 0x11aafe11, 0x83111919, + 0x06002130, 0x2e087e6e, 0x00110008, 0x0022001a, 0x00300027, 0x82153700, 0x23808289, 0x33350535, 0x23238a82, 0x44133523, 0x232205d4, 0x855b1635, + 0x07322605, 0x21173717, 0x05f14403, 0x55153329, 0x19119696, 0x822a8001, 0x2e08828a, 0x1356962a, 0x1a13131a, 0x402b4083, 0x832b00ff, 0x96eb2115, + 0x26831b84, 0x82012a21, 0x96962383, 0x22837d2a, 0x4f801326, 0x2b015539, 0x00201784, 0x2405b350, 0x00dc01dc, 0x238d820d, 0x07170100, 0x35228682, + 0x65822733, 0x28051756, 0x79796301, 0x784eab5d, 0x220082ab, 0x8279dc01, 0x4e782a07, 0xddfe5dab, 0x0400abab, 0x974d1800, 0x001d2f09, 0x00310021, + 0x33151300, 0x22263435, 0xd0610706, 0x06c34a06, 0x1423c983, 0x7b172306, 0x984f068a, 0x36342f08, 0x0f34e633, 0x09110f16, 0x19090c0c, 0x06831924, + 0xd6fe6a25, 0x53115501, 0x1133074c, 0x16162b01, 0x8a0f0f0a, 0x0940090c, 0x1812160c, 0x85161218, 0xd6d6240a, 0x6b190001, 0xd622059c, 0x8c821911, + 0x200b9f6b, 0x6b8c831b, 0x172013a3, 0xf26ba09c, 0x8f51200c, 0x556b2099, 0xe65305fa, 0x01112506, 0xc01a1180, 0x8d829c95, 0x15001531, 0x0002fa01, + 0x1d000700, 0x40002700, 0x9c010000, 0x37052a79, 0x26220717, 0x16163327, 0x06c65025, 0x3526013e, 0x36373734, 0x07171732, 0x37170727, 0x66013727, + 0x161e1549, 0x0c0c0911, 0x1f2c2009, 0x35080683, 0x511cf5fe, 0x0893640e, 0x014b0520, 0x880a0a6b, 0xff0a1a09, 0x870a0a00, 0x34091c09, 0xf2792d1e, + 0x011e2f78, 0x0f0b0bcb, 0x0c9a1515, 0x0c095609, 0x1f1f160b, 0x0a840b16, 0x01303982, 0x6a356388, 0x0a1b098f, 0x010a0a87, 0x0c0d0a00, 0x37824082, + 0xf2782c25, 0x821e2f79, 0x820120c1, 0x82ff20b3, 0x000929c1, 0x001f000d, 0x37000029, 0x1725a388, 0x37070137, 0x21a88d01, 0xa8823233, 0x16323728, + 0x26262317, 0x97861da0, 0x88cc4a28, 0x9e8800ff, 0x9d850101, 0x09fffe28, 0x0e098809, 0x1f868f0d, 0x36440624, 0x8784511c, 0x01881025, 0x829f8800, + 0x0a1a221f, 0x238e8288, 0x0e0d0901, 0x1a202982, 0x3c211d84, 0xe55a1860, 0x00d52108, 0x6c0a8877, 0xcb620950, 0x3713250b, 0x152b8001, 0xab2d0182, + 0x111a1a11, 0x1a1100ff, 0x55017f01, 0x43008456, 0x00210989, 0x7b498280, 0x26230bad, 0x43250000, 0x132912f5, 0x34352622, 0x36333736, 0x82d98233, + 0x06142303, 0x327d0123, 0x1a80360e, 0x04182126, 0x2a1c2e15, 0x1f160104, 0x016a161f, 0x01d4fe2c, 0x0c606556, 0x1a26eb2b, 0x2b022518, 0x2c1f1b25, + 0x0dcc441f, 0x11013725, 0x82aa012b, 0x56fe2102, 0x300aa044, 0x00080004, 0x3700000c, 0x11231501, 0x15333533, 0x82038227, 0x2b552423, 0x822a2a2a, + 0xfe802a07, 0x552a2ad6, 0x0200abab, 0x42517200, 0x91440220, 0x00023408, 0x01000005, 0x01012111, 0xfed50121, 0xfe800156, 0x841901e7, 0xfe432209, + 0x06cc47e7, 0x01d52a08, 0x000600eb, 0x13000009, 0x21270701, 0x11252737, 0x6f016627, 0x85fe2a1b, 0x750187bd, 0xfea001b7, 0xbd2b1b90, 0x91fe6688, + 0x0a9c45b7, 0x00000432, 0x32360325, 0xf8000117, 0x3679fe79, 0x55553501, 0x092aee82, 0x00022b00, 0x1b00c001, 0x967b2300, 0x03072f05, 0x32073e37, + 0x1717061e, 0x22232607, 0xba6c1706, 0x0125081c, 0x06f74b4b, 0x19160d06, 0x2d272420, 0x24272d2e, 0x0d161920, 0x062c0606, 0x8a3d2d10, 0x56131a13, + 0x080d0d08, 0x0804836b, 0x1f2e1e26, 0x015e38cb, 0x09040536, 0x0b0f0c0e, 0x0a05050a, 0x0e0c0f0b, 0x38050409, 0x204d3d02, 0x0d13130d, 0x55080e20, + 0x55272a83, 0x17200e08, 0x82161f1e, 0x055846ed, 0x0a00e124, 0xed821000, 0x00163708, 0x07270717, 0x27373603, 0x36270705, 0x0c463233, 0x1b481b01, + 0x21f85347, 0xcd012b2d, 0x2c2ddd74, 0x0ce1017f, 0x1b4ae6fe, 0x35016747, 0x5b2c141b, 0x000adc91, 0xb36a0006, 0x05b84207, 0x13000f24, 0x4d821700, + 0x3533152f, 0x15213507, 0x15233525, 0x21152127, 0x280f8617, 0x01552b55, 0x2babfeaa, 0x2105822a, 0x0c832a56, 0x2a150127, 0x5656402a, 0x20058396, + 0x350a84c0, 0x66000100, 0x95012600, 0x2c00eb01, 0x33010000, 0x14152315, 0xc1462306, 0x2223250b, 0x26353526, 0x21057b45, 0x5a820714, 0x17372323, + 0x33068323, 0x15554001, 0x1a401219, 0x1a1b281b, 0x1a191240, 0x191c261c, 0x2b05f550, 0x566b0115, 0x4119122a, 0x1c131c0e, 0x23080282, 0x1219410e, + 0x141b0e2c, 0x1c141b1b, 0x56aa2c0d, 0x002aaa56, 0x00000003, 0x0100022b, 0x000700d5, 0x0029001d, 0x08825318, 0x586e3320, 0x22273614, 0x07151506, + 0x17203601, 0xd5012607, 0x56131a13, 0x090c0c09, 0x2f04836b, 0x36202c1f, 0xff4b3e2c, 0x20017000, 0xab063970, 0x22058041, 0x8355090d, 0x0955321c, + 0x1f16200d, 0x3e6a161f, 0x01633d2c, 0x4c555555, 0x2d7a8201, 0x0132002b, 0x00c001d5, 0x002d0017, 0xc7650035, 0x07062305, 0xc74f3627, 0x07927406, + 0x83140521, 0x05354214, 0xa5741420, 0x32362305, 0x46680616, 0xa8520806, 0x31397db0, 0x642f2716, 0x272e648e, 0x01393115, 0x151d2355, 0x3246322a, + 0x231d152a, 0x914b6a4b, 0x221a1a22, 0x7cc0011a, 0x1c633a59, 0x2e4f1725, 0x46646446, 0x25174e2f, 0x593a631c, 0x113b2359, 0x23311925, 0x31233232, + 0x3b112519, 0x4b4b3523, 0x3183190b, 0x00020023, 0x06b24c40, 0x2000082c, 0x35370000, 0x23372707, 0x41183335, 0x776e08af, 0x77d5260f, 0x954c771e, + 0x0c506f80, 0x784dc028, 0x952a781e, 0x026e2a01, 0x0a88510f, 0x1e000e22, 0x82053a42, 0x8235205c, 0x26342403, 0x48170622, 0x32250bb8, 0x2aeb1516, + 0x08008215, 0x0c120c23, 0x583f2b55, 0x34262b3f, 0x80950126, 0x152b152b, 0xb30d0d09, 0x3e2c371f, 0x1f372c3e, 0x26261aaa, 0x2058821a, 0x26b68244, + 0x00eb01c0, 0x821d0005, 0x173721b6, 0x9b71b782, 0x27b38f07, 0x9a1b7e96, 0x36011b51, 0xe127b48c, 0x51991b7e, 0x701ad41b, 0x00230e8f, 0x82200003, + 0x82d52059, 0x000a2959, 0x001a000d, 0x27230100, 0x2b05196b, 0x33072711, 0x07012727, 0x23060627, 0x11366283, 0xc46b0127, 0xd61e0a3a, 0xd62a1911, + 0x015ad0d0, 0x02251b9a, 0x0e821018, 0x95014b24, 0x59821c3a, 0x672be72f, 0x66fe91cf, 0x1610251b, 0x2501111a, 0x205c824b, 0x025f186b, 0x6a13200d, + 0x332a07a4, 0x40eb2311, 0x40408040, 0x03820001, 0x80eb402b, 0xfe560180, 0x000100aa, 0x208d8295, 0x208d8280, 0x20898227, 0x05e84933, 0x36341122, + 0x2305b642, 0x35352622, 0x16231382, 0x42353632, 0x11210537, 0x2f0b8314, 0x44206001, 0x46334562, 0x202c1f32, 0x0c120d20, 0x0c820682, 0xf580013e, + 0x31454531, 0x33230a01, 0x16e02333, 0xcb161f1f, 0x0c0c09cb, 0x2016e009, 0xf6fe1620, 0x6e821583, 0x4000872d, 0xc0016001, 0x00002800, 0x82031e13, + 0x065e4d6f, 0x33163322, 0x34256582, 0x34352627, 0x057a4c36, 0x23174908, 0x06222326, 0x16fc1415, 0x2911201d, 0x2b214022, 0x3b042f02, 0x64401b1f, + 0x2140202a, 0x022f0123, 0x011f1a34, 0x150c0617, 0x271f1620, 0x072e2e06, 0x172d212a, 0x1710240f, 0x07291d41, 0x2c082f2e, 0x12162d1d, 0x0005001d, + 0x200f2f5a, 0xa8431813, 0x54272009, 0x0329060d, 0x01211121, 0x80808095, 0x2903822a, 0xfe80012b, 0x80150180, 0x0287aa80, 0xfe550125, 0x92110080, + 0x18172048, 0x310e4041, 0x003b0037, 0x0043003f, 0x23153700, 0x21351535, 0x07822515, 0x33352528, 0x15332715, 0x0b820523, 0xb1460520, 0x82272006, + 0x8223200b, 0x82172003, 0x830b8303, 0x200b8703, 0x20138613, 0x2488836b, 0x55012bab, 0x2100822b, 0x0885d6fe, 0x2a230c82, 0x822b2b80, 0x2ad52403, + 0x82802b2b, 0x82c02003, 0x2b2b2306, 0x0a822ad5, 0x2b802b22, 0xd6260582, 0x2a562b2b, 0x3482d52a, 0x18ab2b21, 0x60076541, 0xff20053f, 0x21050d4f, + 0xcaaa1500, 0x4b004729, 0x53004f00, 0x82010000, 0x860720ba, 0x82032003, 0x82372007, 0x200f83d2, 0x05166133, 0x86271521, 0x8707831b, 0x872f870b, + 0x21238f27, 0xa5834001, 0xd282c682, 0xd382aa20, 0xcb820d84, 0x0c84bc84, 0x2a2a8022, 0x01241786, 0xaa2b2b95, 0x20050661, 0x841a8355, 0x85d18304, + 0x22f282e4, 0x822b2baa, 0x87552014, 0x210d85f3, 0x1f822b2b, 0x00221982, 0x00820003, 0x02000223, 0x28098200, 0x0012000d, 0x15213500, 0x09d86621, + 0x2307073a, 0x00023735, 0xba0100fe, 0x062a502a, 0x06320612, 0xd650d645, 0xaa015555, 0x0e820f83, 0x0f831220, 0x242d0642, 0x15333525, 0x06f24123, + 0x06423720, 0x20778207, 0x830b8207, 0x4203200f, 0x37200602, 0x20060e42, 0x20078223, 0x202f8613, 0x200b8235, 0x820b8211, 0x05596cf7, 0xfe26f482, + 0xd58001ab, 0xd283802a, 0x80220582, 0xf0822a2b, 0x2b2b8024, 0x1041402b, 0x2bab2306, 0x2441802b, 0x54552006, 0x068205ca, 0x1e830282, 0x2882fe20, + 0xd6280a82, 0xd5fe2b2b, 0x0d002b2b, 0x210c0342, 0xca420013, 0x25002113, 0x2106d341, 0xc7821503, 0x2006ce6b, 0x20138213, 0x820e8313, 0x07c64207, + 0x35210e82, 0x830f8203, 0x831f83b3, 0x28b782f3, 0xabab2b2b, 0xabab2aab, 0x20a88255, 0x20aa822b, 0x849d82d5, 0x2b802290, 0x220f8395, 0x8380012b, + 0xab2a211e, 0x01219b83, 0x82218280, 0x84ab8320, 0x82a986a2, 0x2c7a43ab, 0x2007a742, 0x06474117, 0x9c822720, 0xc7861120, 0x07821320, 0x33110123, + 0x0ace6311, 0x0b871520, 0x2106de63, 0x23830715, 0xaf634020, 0x822b2008, 0x2b2a2192, 0x2a20a082, 0x44189884, 0x2a2107da, 0x098f422a, 0x2a2aab26, + 0x00ff2bd5, 0x0682d185, 0x42054463, 0xfe230576, 0x822b2bab, 0x87f58409, 0x07002123, 0x520c7b41, 0x172505ef, 0x00001b00, 0x060f4213, 0x21111728, + 0x11210311, 0x17422521, 0x82372006, 0x2bc02607, 0xfeaa2a80, 0x059d44d6, 0x2a208b82, 0x15228282, 0x59832a2a, 0xfe2a0128, 0xfe5501d6, 0x1382d580, + 0x41562a21, 0x70422f30, 0x08944207, 0x15333526, 0x23113313, 0x830bac43, 0x200f831b, 0x06d04217, 0x20073441, 0x830f8223, 0x83eb203f, 0x822a2079, + 0x822b2095, 0x82552004, 0x05c143a9, 0xd52a8022, 0x2b211083, 0x23058280, 0x2b2b4001, 0xaa28ac82, 0x2baa2a2a, 0x2babfe2b, 0xbb43c884, 0x820c8205, + 0x2a562202, 0x2005822a, 0x06af432b, 0xbe6f2385, 0x0009230c, 0x1162000d, 0x44212007, 0x25250590, 0x11211521, 0x07a64223, 0x9183a583, 0xa5863320, + 0x2b950126, 0x800180fe, 0x01206c82, 0x2b257982, 0x2b802ad5, 0x838b82d5, 0x82802089, 0x081d4582, 0x00842b20, 0x2031da43, 0x06fa4417, 0xce431320, + 0x82012006, 0x07e1458d, 0x45073141, 0x3d410702, 0x83078307, 0x066642a3, 0x95822a20, 0x2a2b2b22, 0x8020a785, 0x3c41a686, 0x2b2b2105, 0x2807fc44, + 0xab2a2aeb, 0x00012b2b, 0x0865422b, 0xaa2b2b24, 0xd3822a2a, 0x20053941, 0x421f8455, 0xd4820563, 0xcdb10d84, 0x03209183, 0xd583c982, 0xe0432720, + 0x20138306, 0x06304323, 0xed860120, 0x3320d987, 0x430a0c46, 0xcb830834, 0x00842b20, 0x802ad525, 0x43d5fe2b, 0x9c4606d0, 0x2b2b2105, 0xaa85c986, + 0x2307aa44, 0x80fe8001, 0xdf8a1182, 0x0120c487, 0xc4472885, 0x21132415, 0x82172115, 0x180720a7, 0x8207ea45, 0x8440200b, 0xd6d6224b, 0x82078355, + 0xd6d52703, 0x2bc001d6, 0x21412b2a, 0x18802005, 0x4c0b5845, 0x00200975, 0x15204983, 0x05204586, 0x49840786, 0x80204586, 0x49820785, 0x990b5f46, + 0x82112095, 0x82252043, 0x15272403, 0x82053521, 0x244b8a03, 0x0100ff80, 0x21038200, 0x19442bc0, 0x2b802306, 0x4518ab2b, 0x978e0cf0, 0x97931720, + 0x00018023, 0x209482fe, 0x204b82ff, 0x8f0782fe, 0x00032f98, 0x01800095, 0x00ab017b, 0x000f0007, 0xd558001b, 0x23300806, 0x33153515, 0x26343632, + 0x15161723, 0x23230614, 0x16323311, 0x0e200114, 0x4b0e1212, 0x13130d40, 0x2d2e380d, 0x24869722, 0x1a13b531, 0x40c04013, 0x50080582, 0x2234155b, + 0x322b012f, 0x00020048, 0x0140002b, 0x009501ab, 0x00110008, 0x15211300, 0x37270723, 0x17272723, 0x07270701, 0x80273723, 0x227c2b01, 0x3c330f2d, + 0x3401063a, 0x4021791b, 0x95019434, 0x242c5040, 0xfe05043c, 0x4e791bcb, 0x0400947b, 0x09844700, 0x46820e20, 0x47002221, 0xaa4b0586, 0x37362407, + 0x62273325, 0x232905ae, 0x26272722, 0x37373435, 0x05964727, 0x2b952c08, 0x1519221a, 0xcde5fe0a, 0x0a0a8c67, 0x0c0d0a75, 0x0909760a, 0x551f336e, + 0x2f0b0155, 0x1a1a111c, 0x0c260c11, 0x0a50662d, 0x8275091a, 0x0e092220, 0x2e1d820d, 0x0002001e, 0x013d0055, 0x00bc01a8, 0x8213000b, 0x59ad82b7, + 0x37230597, 0x82140527, 0x1e2808c1, 0x38017002, 0x2f25391b, 0x471c4b35, 0xb7032b01, 0x472b0e3a, 0xc8fe9001, 0x4b20381b, 0x47362235, 0xb80d0f9f, + 0x7b36104b, 0x21074148, 0x5382c001, 0x0e000a22, 0x29084b82, 0x33272733, 0x23272313, 0x21072307, 0x66cd2115, 0x752a1533, 0x18861730, 0x00027530, + 0x000100fe, 0xd5fe3987, 0x55404040, 0xf1450600, 0x00122410, 0x45000016, 0x25200746, 0x11303d82, 0x25152135, 0x35171537, 0xd5eb1533, 0x80fed5d5, + 0x36057442, 0x565580fe, 0x2a2aebd5, 0x802b2b55, 0x2babfe2b, 0xaa55c02b, 0xa32b2b16, 0x82132051, 0x1725234a, 0x58821507, 0xab205189, 0x55235982, + 0x87800155, 0x00ff2152, 0x55215283, 0x2352826b, 0x00800001, 0x01237582, 0x830b00ab, 0x231521db, 0x2605f154, 0xabd52337, 0x832f483c, 0xab013003, + 0x4040ab40, 0x000400ab, 0x014b0020, 0x52b501d5, 0x15200674, 0x2122ca83, 0x69820515, 0xca820120, 0x3315232a, 0x35332707, 0xd5173723, 0x087d4418, + 0x00ff002a, 0x4b4a3555, 0x4a4b3535, 0x80287a82, 0x2a012a2a, 0x4a4ad62a, 0xca820282, 0x60003526, 0xa001c001, 0x13244d86, 0x23001b00, 0x49828182, + 0x20079543, 0x06a74e24, 0x20070e61, 0x240f8616, 0xfe2b0195, 0x230386d5, 0x13131a88, 0x0122028d, 0x68822a95, 0x35200282, 0x01271884, 0x121c1213, + 0x846e1c12, 0x067f5005, 0xed82c020, 0x20057143, 0x20758215, 0x2bc78d27, 0x15333507, 0x23153307, 0x35273735, 0x4e07b345, 0x35200660, 0xd52f798b, + 0x2727406a, 0x15112640, 0x40402a2a, 0x8815152a, 0x165623e0, 0x02822c14, 0x1640402f, 0x5616c056, 0x0a160a16, 0x55000100, 0x05a16500, 0xa2501f20, + 0x2622260a, 0x35333535, 0x0bfe5523, 0x32212508, 0x80011516, 0x090cab40, 0xd50c092b, 0xff090c15, 0x0d0d0900, 0x09000109, 0xabab010c, 0x0c0c09c0, + 0x1555eb09, 0x55201283, 0x00290b83, 0x006b0002, 0x01950195, 0x24d9826b, 0x2500000d, 0x20b18437, 0x2f068523, 0x402a2b01, 0x2beb2a80, 0x952b8040, + 0x56808056, 0x31820383, 0x6b004024, 0x2644d501, 0x13002106, 0x2320ed82, 0x2123ec83, 0x82112315, 0xc0403201, 0x01404040, 0x6b406a15, 0x40400001, + 0x40ab9595, 0x22bd82ff, 0x83000300, 0x05374135, 0x0f000b22, 0x20053141, 0x82338225, 0x8323203a, 0x01402f43, 0x01abfe80, 0x6a566a2a, 0x2bd5566a, + 0x4582d62b, 0x4082ff20, 0xf985a084, 0x15000622, 0x0722a082, 0x01822135, 0x26222725, 0x4a333634, 0x1525065e, 0x55c00123, 0x366582ff, 0x323223ab, + 0x2b2bab23, 0x55802b2a, 0x56402a40, 0x2a324632, 0x82ebebeb, 0x00552643, 0x01ab012b, 0x82e482d5, 0x21372743, 0x27152115, 0x438d3737, 0x0001ab27, + 0x565600ff, 0x2743852a, 0x952b2b2a, 0x5555402a, 0x6b26438a, 0x95014000, 0xca82c001, 0xbe821320, 0x36204382, 0x3d0bea4e, 0x6b141533, 0xd6fe2a01, + 0x354b6aca, 0x352c3e2c, 0x4b552b6b, 0x1fabab35, 0xab1f2b2b, 0x9c8235ab, 0x00802c08, 0x01800155, 0x000b00ab, 0x23150100, 0x15330717, 0x27373521, + 0x95800135, 0xff956a6a, 0x018b8b00, 0x6b6b40ab, 0x80802b40, 0x4304002b, 0x1b200ef8, 0x5718f882, 0x3d7a0a7d, 0x836b2010, 0x7a2b20f3, 0xd62b0639, + 0x111a1a11, 0xd6565695, 0x759696d6, 0x9668079a, 0x18578205, 0x220b0172, 0x8219000b, 0x0a29468b, 0x4c185784, 0x4c1808f9, 0x2b220cf6, 0x4c181911, + 0x552307f8, 0x84402b2b, 0x00012302, 0x4c181119, 0x644108f7, 0x0002220a, 0x24578210, 0x33272733, 0x07f05917, 0x36341329, 0x76761501, 0x5680ab95, + 0x19270642, 0x20754001, 0x5900ff80, 0x501808c6, 0xd16409d7, 0x001d2a05, 0x24000025, 0x33272622, 0x07d66806, 0x6407df79, 0xd643078d, 0x25012707, + 0xda0d3b4a, 0xdf799e0d, 0x8cb1210a, 0x2409f779, 0x2121298b, 0x0ae34361, 0xfb64d320, 0x4103200c, 0xeb31066a, 0x1b000300, 0x00001f00, 0x15213525, + 0x33153313, 0x7c701832, 0x3533210d, 0x172b1382, 0x01352315, 0xead6fe95, 0x1811152b, 0x28086e70, 0x16aa2b15, 0xeaea6b6b, 0x07806a01, 0x0112192a, + 0x2b1a112a, 0x6b6bc02b, 0xff725482, 0x07af5066, 0x1400042a, 0x07370000, 0x17072721, 0x0a3a7118, 0xcd822120, 0x014ab528, 0xd54a602a, 0xbd6a111a, + 0x60e02409, 0x83356080, 0x05b46ac9, 0x385f5018, 0x23075542, 0x0100000d, 0x0d3a4f18, 0x3542d520, 0x11562407, 0x42ab0119, 0x1920082d, 0x760c6a74, + 0x6b2a322b, 0x95015500, 0x0600ab01, 0xee820a00, 0x17372608, 0x35231523, 0x21152127, 0x5595956b, 0x2a015580, 0x96d5d6fe, 0xd6808096, 0x0001002b, + 0x01c00055, 0x004001ab, 0x239d8207, 0x35211533, 0x012c0382, 0xaafe2b80, 0x0100012b, 0x55808040, 0x80288b84, 0xc001c001, 0x38001f00, 0x34084e82, + 0x35323314, 0x22272634, 0x23232626, 0x23152135, 0x16171614, 0x06071415, 0x26272223, 0x37352627, 0x07222334, 0x17141506, 0x34231716, 0x35263526, + 0x33363734, 0x08228232, 0x313ec853, 0x0501110d, 0x01cd0204, 0x01035380, 0x19154307, 0x14240f10, 0x2433ae27, 0x1010030b, 0x0804620e, 0x35341f20, + 0x36e81f1e, 0x080e1024, 0x2b2b0202, 0x11010501, 0x06133d12, 0x1d0f0703, 0x162d7832, 0x0b0f0806, 0x0301050a, 0x25170d01, 0x1c1b181a, 0x229c8229, + 0x82400055, 0x00c022bf, 0x26eb8403, 0x25211521, 0x82332707, 0x015531c5, 0x01aafe56, 0x40555500, 0xab2b6b2a, 0xd5d55656, 0xec612282, 0x492c8307, + 0x2e870570, 0x25410320, 0x20358a05, 0x293a836a, 0xaa2a1501, 0x56565555, 0x0583d6fe, 0x13206e8f, 0x17206e82, 0x5620388a, 0xc0223284, 0x6e88802b, + 0xc0014037, 0x12009501, 0x1a001600, 0x32010000, 0x23061416, 0x37271523, 0x05334a15, 0x25352126, 0x11352115, 0x012fad82, 0x3232236b, 0x40402b23, + 0x1a1a1130, 0x83e5fe11, 0x018025bc, 0x32463215, 0x2b2b1382, 0x2a1a221a, 0xfe2a2a80, 0x822a2ad6, 0x00572a82, 0x01a90140, 0x001400c0, 0x27701822, + 0x33272d0c, 0x37323316, 0x27352627, 0x27072217, 0x0809f353, 0x37017226, 0x21132f1b, 0x022c2140, 0x253c042f, 0x49534b0e, 0x1f0e13b4, 0x2040120e, + 0x022f0123, 0xc8fea901, 0x0711301b, 0x2905ee53, 0x3b194a14, 0x1f062149, 0xef530507, 0x42f28405, 0x03220521, 0x99460700, 0x82352005, 0x835520b4, + 0x052753a1, 0x61080021, 0xd1720877, 0x00122205, 0x229a821e, 0x823a0026, 0x2733232e, 0xdc722317, 0x33372505, 0x35132335, 0x3520fd82, 0x07820882, + 0x33152324, 0x07820715, 0x33151124, 0x0c830535, 0x0c822320, 0x1c842320, 0x12823320, 0x38e4332d, 0x0f4b251c, 0x481e4923, 0x822b6022, 0x2a2a2200, + 0x28ff822a, 0x012b2b2a, 0x802b2b80, 0x280485d6, 0x2a6d52f0, 0x2beac0c0, 0x200e82fe, 0x201f832b, 0x842082d6, 0x86552021, 0x2b2b2a21, 0x4b000400, + 0xb5012b00, 0x07cf5b01, 0x00001327, 0x07173701, 0x53038225, 0x34080571, 0x15071521, 0x6a013523, 0xfe2d1e2d, 0x1e2d1ec3, 0x6b2a2a73, 0x80400001, + 0x1e2d7401, 0x2d1e2e2e, 0xc040801f, 0x6a406b6b, 0x0001006a, 0x01cb002b, 0x003501d5, 0x2844821b, 0x06141632, 0x23272223, 0x29038306, 0x34262223, + 0x17323336, 0x03833633, 0x16a0012a, 0x24161f1f, 0x480d3e0d, 0x24200382, 0x01250c8b, 0x1f2c1f35, 0x86008220, 0x10624106, 0x8c823320, 0x2115212d, + 0x01d6d655, 0xebaafe56, 0x822b802b, 0x00352422, 0x48cb016b, 0x01220757, 0x23822315, 0x27352323, 0x05574821, 0x40cb0133, 0x01d64040, 0x6b406b16, + 0x95404001, 0x406b4095, 0x82ab82ff, 0x077c4436, 0x2a002227, 0x36250000, 0x050f5635, 0x2628a683, 0x15233527, 0x14150606, 0x8205b94c, 0x171624c2, + 0x4a023315, 0x35080605, 0x5a431e01, 0x2d181b38, 0x3b022a02, 0x59251d39, 0x351c1739, 0x43032a04, 0x7db07639, 0x7e7db07d, 0x173d360d, 0x140f1b0e, + 0x2a0f3928, 0x1b23062a, 0x210d1638, 0x0d83150d, 0x07f96f18, 0xe7740120, 0x00072308, 0xa8861300, 0x2a016b26, 0x01754075, 0x3406f748, 0x00400004, + 0x01d50140, 0x000600c0, 0x00170010, 0x3700001b, 0x2cfd8235, 0x32012622, 0x21151516, 0x33363435, 0x05a16001, 0x16822720, 0x2508d582, 0x6b011a11, + 0x6bfe1911, 0x0001111a, 0xd611196a, 0xc06b6b6b, 0x66011aeb, 0x4040111a, 0x80fe1a11, 0x1a11c0eb, 0xf78aeaea, 0x2006c647, 0x08bb7e23, 0x82453720, + 0x05c17e0d, 0x8845c020, 0x2b15230b, 0x02825555, 0x8f459620, 0x05585b0a, 0x8210d84a, 0x152121d5, 0x11200182, 0x05200382, 0x241ad84a, 0xfe2a012b, + 0x360388d6, 0x26264055, 0x15112640, 0x40402b2b, 0x0116162b, 0x2a562a15, 0x4a2a2a01, 0x033212d8, 0x49005500, 0xc001a201, 0x0f000700, 0x00001700, + 0x1e7e3424, 0x86022005, 0x86062007, 0x22012707, 0x26263426, 0x05849d34, 0x05847c20, 0x10836f20, 0x1d012622, 0x85200684, 0x00200584, 0x36093949, + 0x00130007, 0x002e001e, 0x07352500, 0x37150727, 0x33152717, 0x82352335, 0x33152303, 0x0b823715, 0x27331725, 0x18072337, 0x22113b40, 0x82558095, + 0x56802a00, 0x36563636, 0x242b2035, 0x2202822b, 0x471a1175, 0xeb210737, 0x261f8235, 0xfa555535, 0x82102050, 0x80302202, 0x72008440, 0x6849067c, + 0x00052606, 0x01400035, 0x20d682cb, 0x5586820f, 0xa66b0525, 0x07627208, 0x21110124, 0x91822511, 0x03860720, 0x84a00121, 0x83c02065, 0x40012f05, + 0x0b01c0fe, 0x2a562b2b, 0x2b2b552a, 0xb547c001, 0xa9fe2c0b, 0xd4fe2c01, 0xd656562c, 0x770096d6, 0x9520076b, 0x2906064d, 0x15332500, 0x11330323, + 0x07822723, 0x3b5a0131, 0x3c3c783b, 0xeb404077, 0xfe2a0180, 0x77d1d1d6, 0x21211bcb, 0x09725015, 0xcc770020, 0x00013008, 0x0180002b, 0x006b01d5, + 0x36000025, 0x5f333634, 0x0b4405b5, 0x21638205, 0x11821422, 0x26343624, 0x46182323, 0x2b31087a, 0x23e03144, 0xb5233232, 0x16202016, 0x0909a2a0, + 0x28d283b7, 0x2c2c1fe0, 0x31cbcb1f, 0x07065ac4, 0x19152b2a, 0x3e2c1a22, 0x01002b2b, 0x26082a68, 0x01000012, 0x48151616, 0x342406ba, 0x36363736, + 0x013f6f82, 0x3f3a299d, 0x35ebfe2c, 0x152f434b, 0x5d362d4c, 0x3d032a01, 0x4b3f2c2a, 0x054b2f35, 0x434c3027, 0x12220a0d, 0xb9501a00, 0x23948208, + 0x27070622, 0xf5439784, 0x60210808, 0x161f1f16, 0x1b23320b, 0x1a030730, 0x031a2626, 0xb07d7db0, 0x2c1fab7d, 0x2633231f, 0x3426011b, 0x79731826, + 0x88022007, 0x00052495, 0x71000018, 0x25200550, 0xd5279d91, 0x2c6f1e8d, 0x8e12011e, 0x8d9526a3, 0x1e2c6e1e, 0x2aa88f4a, 0x02550000, 0x00ab0100, + 0x82190006, 0x352326a8, 0x17231523, 0x25549137, 0x56406b01, 0xf78f6b40, 0x5555eb24, 0x518daa6b, 0xa5820320, 0x51842b20, 0x13000727, 0x00002b00, + 0x06884113, 0x01370124, 0x627e2707, 0x6a052006, 0x44080945, 0x34352323, 0x07222326, 0x32333627, 0x2325a516, 0xd0233232, 0x011bf0fe, 0xfa2b1b65, + 0x33484b35, 0x3a292201, 0x26211f2d, 0x3144201a, 0x27201a1c, 0x015d362f, 0x3246332b, 0xfe1b1001, 0x4b2a1b9b, 0x024a3435, 0x2e82822b, 0x121f2037, + 0x0b261a26, 0x1f0d4431, 0x41004c19, 0x1322092c, 0x81412600, 0x216a8408, 0x91850706, 0x23123a41, 0x261a9501, 0x28236984, 0x830f0b3e, 0x1d01218a, + 0x220e4541, 0x83342680, 0x25302163, 0xf98e8282, 0x4b417289, 0x27332505, 0x33153307, 0x26134b41, 0x6b6b402b, 0x8e725640, 0x6aeb245a, 0x4195566a, + 0x02210d4c, 0x05584a00, 0x31116c49, 0xfe2a016b, 0x952a01d6, 0x80805595, 0x9595eb2b, 0xf2828080, 0x37262c90, 0x17372335, 0x2c841523, 0x83555521, + 0x562b222c, 0x182c8280, 0x240a8178, 0x13000011, 0x0b697917, 0x36341126, 0xab2bd533, 0x24098a7a, 0x1a2bab01, 0x05f47511, 0x1a110022, 0xf2606682, + 0x00152209, 0x7f611800, 0x07234307, 0x33233e83, 0x67ab0117, 0x80260d3f, 0xd5d5802b, 0x478a0001, 0x21058a76, 0xb94f0155, 0x60212007, 0x36200970, + 0x0abc5318, 0x952a568e, 0x663b343b, 0x221a1a22, 0xa089401a, 0x952b802f, 0x17171316, 0x1aab1613, 0x22191922, 0x20658c5a, 0x08a16102, 0x1d000b22, + 0x0dab7f18, 0x07965218, 0x82070045, 0x40952cb6, 0x2a40402a, 0x18181256, 0x83aafe12, 0x2b802505, 0x40402bd5, 0xab2d0282, 0x12d51219, 0x01121919, + 0x2b191200, 0x4b491800, 0x00072609, 0x0014000f, 0x5a4b1827, 0x18152009, 0x83075a4b, 0x1e6e1807, 0x1530080c, 0x36343523, 0x8a611533, 0x3e4f712b, + 0x2c3f2b58, 0x0140261a, 0x1a1a11ab, 0xfe959511, 0x111a2b80, 0x618a2b01, 0x572b7050, 0x2b3f2c3e, 0x80011a26, 0x21056545, 0x9382012b, 0x001a1123, + 0x08606c05, 0x1a001228, 0x29002100, 0x6b712e00, 0x3335230a, 0x60852111, 0x80860720, 0x23152526, 0x35272626, 0x97840e87, 0x8ac00121, 0x842b206e, + 0x80012689, 0x3f5f1478, 0x45908856, 0x758606db, 0x91839520, 0x3fd66b26, 0x96231460, 0x5b439786, 0x0003220a, 0x23f88217, 0x11352115, 0x124e4d18, + 0x56015526, 0x5500fe55, 0x2707524f, 0xd5800119, 0x2b00ffd5, 0x20074c42, 0x20d282d5, 0x28d28202, 0x01eb012b, 0x000300d5, 0x094b4219, 0x06141125, + 0x82172323, 0x233721cd, 0x6506a771, 0x95240994, 0x952aaa2a, 0xd520c483, 0x2d052168, 0x1a1100ff, 0x40151540, 0x0001111a, 0x9b821911, 0x87001521, + 0x651b2051, 0xf14a0df3, 0x18332005, 0x65092a69, 0x538808e8, 0x0001ab28, 0x2a0100ff, 0x55831119, 0x2a2a2b22, 0x5584ab82, 0x2b000622, 0x56063649, + 0x2f2009d8, 0x093e4b18, 0x54333721, 0x05240566, 0x25112111, 0x15206684, 0xba421182, 0x32212d0b, 0x33151516, 0x55550001, 0x806b6b80, 0x01260584, + 0x01d5fe00, 0x00832a80, 0x111a2008, 0x1911d5fe, 0x2b011119, 0x012a1a11, 0x6bd68015, 0x5640406b, 0xfe2a012a, 0x2a2bd5d6, 0x4f2a2b2b, 0x2a240913, + 0x80000300, 0x2406ee60, 0x00130003, 0x20e38217, 0x6b5a1835, 0x062f410a, 0x33351127, 0xaa550115, 0x853883aa, 0xd5c02204, 0x89d883d5, 0x82fe2068, + 0x0a815158, 0x40a77f18, 0x4000012a, 0xc0015500, 0x1900eb01, 0x8305c063, 0x352322ff, 0x05756133, 0x15331523, 0x089b8223, 0xb0343523, 0x1a2670a0, + 0x7c575540, 0x1a405557, 0x71eb0126, 0x261a964f, 0x573e2bab, 0xab2b3e57, 0x4f961a26, 0x20488300, 0x20488415, 0x96488d1d, 0x9580224c, 0x244e8b55, + 0x2b261ad6, 0x27508c15, 0x002b000c, 0x01d5016b, 0x49079348, 0x23220903, 0x1b822700, 0x4b613b20, 0xcb4a1811, 0x1537240b, 0x82273533, 0x86172003, + 0x0b364407, 0x36343529, 0x2a950133, 0x82162a2a, 0xaa2a2103, 0x40200583, 0x96200d86, 0x2309a044, 0x2a2a2b01, 0x02851682, 0x2b2b5623, 0x820e8496, + 0x20148827, 0x0aea6a40, 0x80000137, 0x8001ab00, 0x05004901, 0x17130000, 0x27071737, 0x1e62629e, 0x84118280, 0x01002406, 0x8200ab00, 0x8001210c, + 0x25222083, 0x21822707, 0x82490121, 0x621e221f, 0x8205849e, 0x82b72020, 0x85552020, 0x37372220, 0x20208227, 0x853a84b7, 0x221f8247, 0x82b70080, + 0x83552061, 0x201e8440, 0x20398527, 0x203f87b7, 0x203f8240, 0x253f82c0, 0x01000008, 0x81822115, 0x01244282, 0x4cd2fec0, 0x4c242083, 0x4d2a1501, + 0x4d220883, 0x6d570200, 0x00892406, 0x4e090003, 0x272005ab, 0x80209084, 0xb383c582, 0x2b801e24, 0x0884cd2b, 0x000d0029, 0x0115002b, 0x82c001d5, + 0x00062435, 0x7e0e000a, 0x222f08bd, 0x2a002600, 0x3e002e00, 0x27250000, 0x76353733, 0x4c1805dd, 0x0b870b4b, 0x22208b41, 0x41aa5500, 0x8e410780, + 0x56152318, 0x33542bea, 0x2b402606, 0x2b2b552b, 0x200e8495, 0x20148a2b, 0x06434640, 0x1a11d523, 0x05714a00, 0x8001c022, 0x0022b382, 0x0e413301, + 0x01212507, 0xbcfe2b95, 0x24050741, 0x6b011901, 0x08124180, 0x80001522, 0x8025e682, 0x0c000300, 0x3d308200, 0x37272311, 0x37270717, 0x01213521, + 0xb42a2aab, 0x1e80801e, 0x01d1fe4d, 0xff80012f, 0x0d84e200, 0x2805797f, 0x0195012b, 0x000f00c0, 0x1835831b, 0x2b2c5a81, 0x08513600, 0x51084646, + 0x3e3e2f36, 0x0a5a8118, 0x45099148, 0x03213fa8, 0x05274a00, 0xd482c020, 0xa2820720, 0x3525002f, 0x35171521, 0x33211523, 0x33352115, 0x35d98211, + 0x56d6aafe, 0xfe2b0001, 0xaa012b00, 0x40d5d5c0, 0x2b2b1515, 0x2f824001, 0x07253987, 0x23000b00, 0x08247200, 0x38820320, 0x4b331121, 0x53180659, + 0xf72f0e89, 0x120c0c12, 0x5601960c, 0xfe111a55, 0x461a1156, 0x6b200944, 0x0c2e1782, 0xea1e0112, 0x11ebfeea, 0x1a111a1a, 0x0683ea11, 0x96460482, + 0x20a38308, 0x0b964619, 0x50183520, 0x70820b7e, 0x290f9846, 0xd5950111, 0x2bebfed5, 0xf541152b, 0x09b94d0a, 0x33000327, 0x3b003700, 0x21f38200, + 0xde451523, 0x6c458206, 0x5d83089e, 0x45512320, 0x79352005, 0x33210633, 0x05b15535, 0x0733152e, 0x37152335, 0x01352315, 0x2b01d66b, 0x19280082, + 0x2a2b2b11, 0x19112b2b, 0xab270c8d, 0x9580552a, 0x9280d6d6, 0x2134851a, 0x21822a55, 0x50538020, 0x00e92608, 0x000c0004, 0x08e58311, 0x3634232d, + 0x15213503, 0x26220614, 0x15161613, 0x5796eb23, 0x65560157, 0x3fc0658c, 0xe9019657, 0xfe6041a9, 0x465555df, 0x6f016565, 0x82416008, 0x006b2641, + 0x01950115, 0x220982eb, 0x82170007, 0x231123d5, 0x42461711, 0x70012a12, 0x80569be0, 0x1a26261a, 0x2c0483aa, 0xfe2b0180, 0x151540d5, 0x1a26ab01, + 0x231184fe, 0x261a5601, 0x80204e86, 0x0b224e84, 0x4e851b00, 0x082e4718, 0x2e0e087a, 0x53c05501, 0x1a13131a, 0x1f167613, 0x83ab161f, 0x20568404, + 0x2f128255, 0xad011a13, 0x96fe1620, 0x16202016, 0x20166a01, 0x3060af75, 0x00000004, 0x01000223, 0x001200dd, 0x00220015, 0x054c4926, 0x14155b08, + 0x27232306, 0x15233533, 0x36343527, 0x33152533, 0x17001601, 0x35212707, 0x37343533, 0x27210527, 0x09eb0121, 0x04090c0c, 0x2b552e40, 0xeafe090d, + 0x51effee5, 0x1b222b01, 0x2b86fe32, 0xc701270a, 0x012be7fe, 0x0c550144, 0x0d09d509, 0x2b6f9640, 0x250c0959, 0x514801e5, 0x2382d4fe, 0x0feb4025, + 0x5c42270c, 0x1f2411f9, 0x33002900, 0x200d5659, 0x95441825, 0x3333260d, 0x37153335, 0x072b4d07, 0x08881720, 0x2b400127, 0x2b202a20, 0x06035801, + 0x1a1a113b, 0x312bd511, 0x20211511, 0x281e1115, 0x31293129, 0x2d112930, 0x802d3e3d, 0x2300842b, 0x55111a6b, 0x04822483, 0x86555524, 0x25821511, + 0x24240d27, 0x002d2d11, 0x06c24703, 0x20052847, 0x238e891a, 0x15161625, 0x2a0cd65b, 0x95013725, 0x012a2bd5, 0x500f0b3b, 0x0c24080a, 0x950fd4fe, + 0x87246183, 0x750d1703, 0x6d216186, 0x32631828, 0x00eb2a08, 0x000e0009, 0x01000012, 0x084b8217, 0x26260730, 0x15173535, 0x23373636, 0x01150735, + 0x526ec000, 0x3bc06e52, 0x95950852, 0x8056eb01, 0x14149359, 0x95805993, 0x436913bf, 0x007a42bc, 0x335b0007, 0x09814907, 0x25001722, 0x1d46a285, + 0x25078707, 0x15233523, 0x5a441301, 0x11210806, 0x16323337, 0x2b2b6b01, 0x2b2a2a2a, 0x802bd62b, 0x0115012b, 0x00ff111a, 0xab801a11, 0x55c01911, + 0x21198255, 0x00845580, 0x2a222282, 0xcd734001, 0x80002206, 0x165e1819, 0x18042044, 0x26080841, 0x000f0007, 0x7a290019, 0x13291150, 0x16140622, + 0x34363233, 0x0f817d26, 0x2634e635, 0x14263426, 0x583f3f58, 0x19126b3f, 0x1a111219, 0x18115a1a, 0x2107b65e, 0x1c820001, 0x85342622, 0x3f2a1c82, + 0x19170158, 0x221a1924, 0x8f742a1a, 0x0005210c, 0x25078257, 0x00100008, 0xc7730018, 0xa97a1805, 0x52162007, 0x517f06ce, 0x8f888708, 0xd5803387, + 0xa01912d5, 0x1f1f2c20, 0x32460d2c, 0x67334632, 0x8c821a22, 0x102f1936, 0xb3101717, 0x10161610, 0xabfe9501, 0x0112192b, 0x202cb655, 0x20202782, + 0x332c2382, 0x2419ee46, 0x44241818, 0xcdfe1017, 0x332c2384, 0x02001710, 0x55001500, 0xab01eb01, 0x2805ba5c, 0x11211125, 0x15163201, 0x0a1f5a03, + 0xd6254b82, 0x1a115501, 0x20ca8201, 0x21f18280, 0xf5788011, 0x1a1a260a, 0x11000111, 0x263d821a, 0x01000040, 0x440002c0, 0x212009c9, 0x520cc944, + 0x9b2b08d8, 0x56c6cafe, 0x26261aab, 0x8300ff1a, 0x016b2d05, 0x40abfe55, 0xd5011515, 0x80fe1a26, 0x01201183, 0x46820582, 0x50882b20, 0x2106cb44, + 0xcb441121, 0x2f54880f, 0x93c0fe95, 0x1a13131a, 0x1f16b613, 0xd5fe161f, 0x58840583, 0x2105a975, 0x1482d801, 0x14836a20, 0x16960125, 0x8405001f, + 0x82d520f4, 0x333608f4, 0x46003f00, 0x58004c00, 0x34250000, 0x27272626, 0x23232626, 0x07070622, 0x34363727, 0x07222627, 0x17140607, 0x37373216, + 0x15060617, 0x16171614, 0x36323316, 0x06853337, 0x05363639, 0x34352622, 0x16323336, 0x37061415, 0x36373123, 0x1732033b, 0x8a172317, 0xd5012e16, + 0x1d141f12, 0x6e142206, 0x11062214, 0x235a821e, 0x2a061206, 0x2c085782, 0x26060711, 0x1318211a, 0x15182304, 0x065e0621, 0x23181521, 0xfe181304, + 0x0d0d08c0, 0x0d0d0908, 0x05174d4d, 0x222a220f, 0x4d17050f, 0x200f8256, 0x2c178209, 0x182315d5, 0x18145604, 0x1e321418, 0x22478206, 0x842b0606, + 0x27073205, 0x181d2c08, 0x1f170b27, 0x18131318, 0x270b171f, 0x8243843d, 0x46ab2533, 0xab460f0f, 0x00200d87, 0x0b127018, 0x924d1720, 0xb9761809, + 0x068e4d10, 0x2009f77a, 0x0af44195, 0x3009ea7a, 0x00550002, 0x02ab0100, 0x00070000, 0x12000015, 0x05a14114, 0x82141721, 0x272328e7, 0x37373426, + 0x7d161733, 0xe0270523, 0xaa151b26, 0x83414115, 0x35013404, 0x6a4b4b6a, 0x4e23804b, 0x327a7a15, 0x7a7a32a8, 0x5e010034, 0x182008d7, 0x33259782, + 0x27352315, 0x23048207, 0x26353733, 0x27075e71, 0x01150706, 0x556b556b, 0x25080282, 0x26181356, 0x13182634, 0x5a416bab, 0x556b415a, 0x15200744, + 0x1a26261a, 0x44072015, 0x2b000400, 0xc001c000, 0x57184001, 0x00230821, 0x5b333525, 0x078205dd, 0x15212728, 0x6b550121, 0x028200ff, 0x016a6a27, + 0xc06bfe95, 0x2100842b, 0x1a422b80, 0x070f4306, 0x29001b24, 0x9c7c3700, 0x07a44315, 0x16153724, 0xa8831415, 0x3722a482, 0xcb432735, 0x342d0807, + 0x15213336, 0x6a55c001, 0x080e0e08, 0x0d0d0880, 0x131a7708, 0x4a131a13, 0x15551616, 0x55558015, 0x111a1a11, 0xab808001, 0x080dd5ab, 0x232483d5, + 0xca0d08d5, 0x13312082, 0x1426621a, 0x26141c1b, 0x1c1d1326, 0xff802613, 0x05f74e00, 0xe7501a20, 0x01802505, 0x008001eb, 0x24058465, 0x0000002b, + 0x05047f32, 0x27208d87, 0x0af85618, 0x270fb246, 0x121c9201, 0x42121c12, 0x40228784, 0x02822b40, 0x2006a646, 0x208c8480, 0x221c8200, 0x84521c12, + 0x2a192305, 0x02824040, 0x111a9522, 0x2105b04e, 0xf4771a11, 0x0017230c, 0x7d82001b, 0x15333725, 0x82322623, 0x150625ff, 0x023e3423, 0x21055c4e, + 0x5c183423, 0xed311301, 0x400d2626, 0x1126382b, 0x1e161116, 0xd6b62616, 0x083745d6, 0xe226b53a, 0x32191f2b, 0x0d1d1514, 0x160f0c14, 0xdb1f0f16, + 0xd6fe2a01, 0x111a8001, 0x0ecf6318, 0xdb011528, 0x1500db01, 0xf85b2400, 0x23232506, 0x15062735, 0x2008cd4e, 0x05f95b37, 0x91823320, 0x33271522, + 0x3a088d82, 0x1bab0130, 0x4009092e, 0x405511c4, 0x471c261a, 0x1f252ceb, 0x70503f31, 0x01573e69, 0x1b55fedb, 0xc555032e, 0xab2a261f, 0x38951a26, + 0x1815472c, 0x4f71241e, 0x3e2a6993, 0x75030058, 0x0b2008a6, 0x61c68b18, 0x07276c89, 0x17000f00, 0x7a000000, 0xcc600684, 0x26402610, 0x34262634, + 0x0ac06060, 0x831a0121, 0xeb262111, 0x730cb760, 0xc02f0523, 0x0700d501, 0x00001a00, 0x27273725, 0x18170707, 0x1808c057, 0x230b036b, 0x28585828, + 0x95280383, 0x111a1a11, 0x55404055, 0xed200783, 0x28231284, 0x18400158, 0x2507ed6a, 0x2b01111a, 0x55181911, 0x80202912, 0x2a060f63, 0x0100000f, + 0x15231533, 0x58060623, 0x323b0514, 0x95000117, 0x36040155, 0x38382825, 0x01120e28, 0x24eb40c0, 0x38503831, 0x410e0006, 0x06410873, 0xff6d1805, + 0x00572a0d, 0x0067005f, 0x2400006f, 0x05a37b32, 0x15321727, 0x35222314, 0x0f244134, 0x17860520, 0x27201f87, 0x33202382, 0x06201382, 0x0f873786, + 0x278f0720, 0x08660f86, 0x89581807, 0x12222a08, 0x0d120c0c, 0x0b0a0a16, 0x0b784166, 0x10824020, 0x03820b20, 0x0b0b3524, 0x2284130a, 0x4b201183, + 0x4a200d82, 0x36200382, 0x41230382, 0x840d0d12, 0x20058218, 0x200984eb, 0x2030833e, 0x0bab414b, 0x820a2321, 0x83552028, 0x83802016, 0x82202004, + 0x120d2269, 0x200f882c, 0x20098340, 0x20238395, 0x2040844a, 0x211f8462, 0x2b450e00, 0x052a4108, 0x25001d3a, 0x31002900, 0x41003900, 0x4d004900, + 0x5d005500, 0x00006500, 0x34262224, 0x2620c683, 0x1725078e, 0x32333422, 0x07084114, 0x15212524, 0x24410521, 0x87298e07, 0x35032439, 0x86021521, + 0x8e06201b, 0x1e012107, 0x9c84e487, 0x05820c20, 0xd4824020, 0xfe27b483, 0xfe8001cb, 0x822b0180, 0x83ac200e, 0x5d0c2224, 0x0951671a, 0x80014b22, + 0x20055a4e, 0x201a8a0c, 0x20e68495, 0x82128449, 0x0d0d2605, 0x16165712, 0x244b8356, 0x0bf52b75, 0x8408820a, 0x123e2720, 0x1c12121c, 0x4e831343, + 0x2bf8fe25, 0x8400012b, 0x8461207b, 0x846c2037, 0x00350816, 0x00350012, 0x01cb0135, 0x000500cb, 0x0013000d, 0x00210019, 0x002f0027, 0x005a0054, + 0x006a0062, 0x007a0072, 0x00860080, 0x0098008c, 0x360000a0, 0x22141532, 0x07fd4135, 0x14321726, 0x26342223, 0x2420138c, 0x47420d84, 0x37032407, + 0x6a270701, 0x34260565, 0x17323336, 0x046a0627, 0x37362105, 0x17201589, 0x12204685, 0x410e3141, 0x5d410741, 0x22162c07, 0x15323435, 0x33342227, + 0x84331432, 0x26072c05, 0x34352726, 0x14163236, 0x86362306, 0x1635253d, 0x0c124216, 0x6a24e182, 0x960a0b0b, 0x01310c87, 0xe916164a, 0x120d0d12, + 0x011b8b0c, 0x01501c5b, 0x2b0c820c, 0x3c020409, 0x0d0c1202, 0x3c0b1013, 0x0c281082, 0xa506090c, 0x690b0a0a, 0x41823e84, 0xb7200288, 0x0d241183, + 0xf61616e0, 0x4b201e82, 0x0f295782, 0x1301100a, 0x0d13131a, 0x24538409, 0x0a0a0be0, 0x282d8440, 0xea16163e, 0x400b0b0a, 0x2031830d, 0x29168802, + 0xfe1b0701, 0x02511ba5, 0x99830904, 0x0b3c0127, 0x0c0d1310, 0x217d8212, 0x93830904, 0x16f40125, 0x84200116, 0x42622040, 0x9f200ac0, 0x57201184, + 0x8a214582, 0x26008216, 0x0a1001aa, 0x82130d05, 0x84602077, 0x18002118, 0x4208ba41, 0x2b0805df, 0x0025001f, 0x0033002d, 0x0043003b, 0x0053004b, + 0x0063005b, 0x006f0069, 0x007b0075, 0x00890083, 0x00970091, 0x00a7009f, 0x000000af, 0x4106e643, 0xae4107c8, 0x44362007, 0x14220836, 0x59412223, + 0x26222105, 0x15240782, 0x26352214, 0x0244338e, 0x5a72180f, 0x05a9410f, 0x22420320, 0x2237240a, 0x45323334, 0x162106b5, 0x05cf4114, 0x2107a844, + 0x63833206, 0x5b8f7f87, 0x431e0121, 0x3f260a12, 0x120d0d12, 0x1184080c, 0x0a0a762d, 0x0c12020b, 0xa00d120c, 0x413e1616, 0x0c2010b9, 0xa3201184, + 0x29202a84, 0x2008a144, 0x051a420b, 0x0682f620, 0x4b840120, 0x16168b23, 0x057a43fe, 0x31423620, 0x08fc4107, 0x01220882, 0x4183134b, 0x20054843, + 0x2019844d, 0x231184c2, 0x4a1616ed, 0x2008a441, 0x0a8e43c0, 0x4105ba41, 0x172005cc, 0x89202a84, 0x3e201d84, 0x96276882, 0x0b951616, 0x8be00a0a, + 0x846a203b, 0x0a54241d, 0x82150b0b, 0x120d21ca, 0x9d7d3f8b, 0x0007230a, 0x95413600, 0x7d2b2606, 0xb07d7db0, 0x200483a8, 0x2c21827d, 0x012b006b, + 0x00d501ab, 0x1300000d, 0x05716232, 0x34363633, 0xd5362726, 0x597d7d59, 0x3931303a, 0x01303139, 0x263482d5, 0x74631c1c, 0x821c1c63, 0x00802433, + 0x9395012b, 0x58c02b33, 0x22587d7d, 0x5353421e, 0x33841e42, 0x71140927, 0x0914718e, 0x01481800, 0x000d2209, 0x07a25c1d, 0x16072222, 0x07217082, + 0xc3481816, 0x00012d0f, 0x354b4b35, 0x29211b1a, 0xc51b2129, 0x0b624818, 0x6a4b802b, 0x3f0f0c4b, 0x0c0f3f4c, 0x604818c7, 0x180320a0, 0x180af548, + 0x2e5a5a49, 0x01400040, 0x00c001c0, 0x001b000d, 0x50170100, 0x172608ba, 0x15371737, 0x01820727, 0x36343529, 0x16322133, 0x50408001, 0x402305bf, + 0x82955655, 0x82552003, 0x2a01300e, 0x0c011a11, 0x1a116140, 0x408c111a, 0x83de5656, 0x41562104, 0x00230f83, 0x862b0002, 0x0009225a, 0x2b5a8216, + 0x07071416, 0x32363727, 0x16320417, 0x223b6583, 0x35363227, 0x06ba0134, 0xbf3bbf06, 0xfe061206, 0x322634de, 0x0f213423, 0x829d011b, 0x2914830e, + 0x1a26e506, 0x172b3223, 0x44181a13, 0x0d3c0c2b, 0x1c001400, 0x29002100, 0x36370000, 0x06173736, 0x27222306, 0x26260733, 0x26231737, 0x0520ad82, + 0x07275f83, 0x23372727, 0x82161637, 0x36363f74, 0xd2173233, 0x4e154e04, 0x181f5018, 0x2e4fcfb4, 0xa06c2043, 0x85012104, 0x66172104, 0x10839b06, + 0x8402f421, 0x30163a1c, 0x87238807, 0x87951c14, 0xbbff4711, 0x54221318, 0x2218134b, 0x0bb01a54, 0x21118215, 0x1a82024f, 0x03000522, 0x2406275d, + 0x000700d5, 0x0ba7551b, 0x17331322, 0x20107c6a, 0x06374316, 0x3f58d429, 0x2b3f583f, 0x58442780, 0x442709ec, 0x28382823, 0x82953828, 0x583f2818, + 0x1a2a0101, 0x4b00ff11, 0x112205ec, 0x1983c71a, 0x0400282a, 0x00006b00, 0x00029501, 0x1f226b82, 0x79822700, 0x15130022, 0x15235283, 0x6a323535, + 0x232505e7, 0x23350717, 0x09ac5b35, 0x27076c6b, 0x23153311, 0x49444995, 0x96256f83, 0x6a6a4040, 0x2f098340, 0x1919227c, 0x6a6a1a22, 0x18e0d501, + 0xe0181e1e, 0x2306fd62, 0x2a2b4040, 0x012c0a82, 0xab1a112a, 0x1a1a221a, 0x2ae6fe22, 0x7c87e882, 0x20000824, 0x88822400, 0x2006d04c, 0x08f35016, + 0x13207b8e, 0x01217382, 0x23678200, 0x7d191a22, 0x9620788d, 0x80217382, 0x207d841a, 0x06484280, 0xfe227389, 0xe0822a55, 0x20050f66, 0x08174eeb, + 0x17001324, 0x715a3300, 0x35272111, 0x2405f558, 0x23113313, 0x063c7d14, 0x33363424, 0xe2623533, 0x15152705, 0x01163233, 0x00822bab, 0x2a2a2a22, + 0x2b260582, 0x1aaaaa56, 0x8e83ab11, 0x090c162d, 0x150d0955, 0x40011a11, 0x8dc02b2b, 0x15012302, 0x2383c0fe, 0x1140012a, 0x0d09151a, 0x1a15090d, + 0x280af273, 0x00110008, 0x0023001a, 0x844b182b, 0x97461809, 0x5e072009, 0x3322054e, 0xee4c0715, 0x089f4a07, 0x1a2b952a, 0x11555511, 0xd5552b1a, + 0x0b830984, 0x32469d26, 0x6b324632, 0x01211684, 0x211f8355, 0x0c842b2b, 0x8355d521, 0x82952023, 0x4632211c, 0x2a0af171, 0x000f0007, 0x00210018, + 0x5833002a, 0x32470914, 0x25471808, 0x268d9110, 0x1a1a22ef, 0x84081a22, 0x92ea2076, 0x82d52090, 0x221a221d, 0x20778466, 0x189697b8, 0x2d0c2064, + 0x001d000d, 0x11331300, 0x22211521, 0xb56c3526, 0x2a2b2e14, 0xd5fe2b01, 0x40c01911, 0x3f560001, 0x05295ebf, 0x01111a31, 0x01191100, 0x2ad5fe80, + 0x55ab1119, 0x421b4f6a, 0x192206f0, 0x6d411119, 0x0758480a, 0x4f003421, 0x26200844, 0x4c0e4c4f, 0x37200759, 0x24054e44, 0x15062223, 0x05584414, + 0x3634262a, 0x131a6801, 0x2d131a13, 0x57200584, 0x952e0b8a, 0x2c3f714f, 0x10120e25, 0x70500e12, 0x554f0170, 0x05604705, 0x53083083, 0x12681a13, + 0x1c12121c, 0x2c4764ae, 0x0b0d133e, 0x120e0c14, 0x0070a070, 0x00400002, 0x01c90140, 0x000300c0, 0x37000015, 0x25072737, 0x17070716, 0x23072707, + 0x37273735, 0x32363717, 0x29ac9417, 0x0f4f01ac, 0x1e29430f, 0xbe65bf1e, 0x43291e1e, 0x6b061206, 0xf4201582, 0xbe221485, 0x1484bf65, 0xe8550620, + 0x000d250a, 0x001e0010, 0x2b086166, 0x11173523, 0x35033523, 0x33351307, 0xd45f0882, 0x11952d08, 0x6a111a1a, 0x6a566a6a, 0x6a2b2b6a, 0x59660c83, + 0x80c02c07, 0xfe2b1501, 0x018080c0, 0x43fe2b40, 0xab4107c3, 0x5b07200a, 0x36200526, 0x18063e41, 0x203ae266, 0x7d661804, 0x23538308, 0x0028001c, + 0x08797218, 0x2d078c42, 0x17161407, 0x34262615, 0x06153736, 0x457c2506, 0x0201230a, 0x9418577c, 0x552908a1, 0x48382332, 0x2e273848, 0x05c85001, + 0x19826b20, 0xfe7c5736, 0x7070a070, 0x502750a0, 0x64142e10, 0x2e14647a, 0x40294912, 0x00202084, 0x09968118, 0x13000328, 0x35250000, 0x3f511521, + 0xfe952410, 0x672a01d6, 0xab2309ec, 0x51d5aaaa, 0x41830a1f, 0xc0015522, 0x180f4955, 0x8e0cd64a, 0x13485541, 0x092a4c18, 0x19001025, 0x73370000, + 0xd75a0606, 0x13333107, 0x33352335, 0x15151632, 0x56560195, 0x1911d62a, 0xab330583, 0x951911ab, 0x1956562a, 0x562ad611, 0x2aabd5fe, 0x84ab1119, + 0x826b20d2, 0x55952090, 0x4a1806da, 0x01201210, 0x9520908e, 0x0ee84918, 0x7f18d383, 0x1541073d, 0x80c02826, 0x111aab80, 0x841a1180, 0x47848404, + 0x574105fe, 0xf6471805, 0x21848f12, 0x8818016b, 0x4548136c, 0x45082007, 0x00210625, 0xb24b1801, 0x44132007, 0x2720079e, 0x23051a45, 0x3634023d, + 0x2b05fe73, 0x1a119501, 0x2b55552b, 0xd555111a, 0x82057153, 0xc001210c, 0x55230e82, 0x83abfe2b, 0x831d8711, 0x43304127, 0x2d073172, 0x000400c0, + 0x00180008, 0x23172500, 0x72181737, 0x01261301, 0x3aea4b2a, 0x5242a62a, 0x65fa240d, 0x9243334c, 0x000221fe, 0x210c6074, 0x77181125, 0x55202410, + 0x22080d5a, 0x821a112a, 0x005524dd, 0x42ab0155, 0x80241c9f, 0x000100ff, 0x07ca4918, 0xe8571a20, 0x002b2616, 0x01d5018b, 0x0643478b, 0x2105ea7a, + 0x01841521, 0xaa012b24, 0x038856fe, 0x402b8b25, 0x822a402b, 0x002b2127, 0x0805e66c, 0x05000222, 0x00000800, 0x03210301, 0x15272317, 0xd5000123, + 0x78c0aa01, 0x01782a78, 0x0180fec0, 0xd7d7d702, 0x180a3042, 0x5e322768, 0x0b2e0927, 0x12000e00, 0x00002200, 0x33352325, 0x27443335, 0x11172505, + 0x33151301, 0x2c11d56b, 0x202a2a35, 0x60202b2b, 0x6b15d6fe, 0x0ae043aa, 0x17832020, 0x2a011528, 0x0001d6fe, 0x4e412020, 0x01802811, 0x00950195, + 0x840a0006, 0x35072566, 0x33053337, 0x952fd582, 0x0664402a, 0xababc0fe, 0x2416e380, 0x822a8024, 0x002b22d3, 0x06894380, 0x00002323, 0x83248213, + 0x37353828, 0x35363736, 0x23262734, 0x34231522, 0x33333637, 0x15161732, 0x82060714, 0x2b360801, 0x1601aaaa, 0x1259b87f, 0x0a02070d, 0x182e2e1c, + 0x3b022b19, 0x07040514, 0x01171104, 0x24472a15, 0x16126120, 0x050d100c, 0x1824311a, 0x140b2c19, 0x06130b0e, 0x6a82171b, 0x6a825520, 0x9684ab20, + 0x96881220, 0x27450720, 0x2bab2a0b, 0xd6076440, 0x562a5656, 0x20a08456, 0x2109832a, 0xa586562a, 0x3a82d520, 0x2f000b22, 0x338aa582, 0xb1821720, + 0x0721ad8a, 0x8daf8406, 0x55ab26b1, 0x55552b55, 0x36b384d6, 0x140a0b08, 0x2e0b0e15, 0x120f0e18, 0x143b0116, 0x050c1006, 0x6e01090e, 0x5621056d, + 0x35bc84c7, 0x0f100f0d, 0x180b0e0d, 0x050e1824, 0x120d2c06, 0x05141a18, 0x85820910, 0xc082a820, 0x85825920, 0x2900152d, 0x34010000, 0x26272627, + 0x82060722, 0x14153373, 0x32331617, 0x35353637, 0x32333407, 0x15151617, 0x18831423, 0x22832220, 0x01354708, 0x0a040b2b, 0x0a071607, 0x07190b04, + 0x0c0b150b, 0x11415884, 0x0e180107, 0x1028100e, 0x01180e0e, 0x06112828, 0x06040406, 0x39281106, 0x11040f38, 0x07392812, 0x1c1a3e74, 0x101f3b2c, + 0x05060605, 0x003f1b10, 0x53180004, 0x032607ba, 0x19001300, 0x22592200, 0x0bc84509, 0x23351326, 0x25153335, 0x29069b48, 0xfec00111, 0x112b01d5, + 0x3a661a1a, 0x2b962d06, 0x01ebfe55, 0x11abfe55, 0x2b01951a, 0x56201b82, 0x2c0b5466, 0x2aabd5fe, 0xabfed5d5, 0x01111a2b, 0x26718a55, 0x00180014, + 0x82310028, 0x06eb4971, 0x2407e945, 0x23230614, 0x13434415, 0x09199a18, 0x18806b2c, 0x55552b12, 0x12191912, 0x8c8dab2b, 0x88855520, 0x822beb21, + 0x2a2b211d, 0x12232682, 0x91562a19, 0x91562095, 0x00182690, 0x00250021, 0x83908235, 0x6f352081, 0x7d460621, 0x21118205, 0x01411632, 0x13d7450a, + 0x12196b25, 0x842b5555, 0x0d132596, 0xd5fe130d, 0x01208985, 0xeb25a08e, 0x2a2b1912, 0x259a832b, 0x13130d20, 0x88868a0d, 0x9100ff21, 0x0e9f41a4, + 0xa0821c20, 0x14494e18, 0x24081841, 0x37231705, 0x0f9e4117, 0x25061141, 0xeb4c3f01, 0xa0412a3b, 0x070a4112, 0x4b647123, 0x21718e32, 0x4e18001d, + 0x352517bb, 0x15333523, 0x1b154233, 0x8255ab21, 0x070441e5, 0xfe257692, 0x558055d5, 0x13194255, 0x1a001123, 0x05ae7000, 0x23098841, 0x33152315, + 0x25258141, 0x2b568055, 0x7d411912, 0x2a80251c, 0x8012192b, 0x201b7841, 0x0a184305, 0x2305fd59, 0x01000034, 0x0720f082, 0x2006cf63, 0x20908633, + 0x42a28215, 0x15271dab, 0x18122b2b, 0x83561218, 0x43758395, 0x9b410c3a, 0x2a152307, 0x1c82552a, 0x83181221, 0x122a2399, 0x0c422b19, 0x12b14211, + 0x0a00062e, 0x23001a00, 0x23250000, 0x33352337, 0x251e3443, 0x55552a15, 0x2d435580, 0xabc02414, 0x9ad62a2a, 0x41062072, 0x07280a0e, 0x29002500, + 0x42003900, 0x20051041, 0x0a144127, 0x62071b41, 0x0686063c, 0x2c201e41, 0x18122b2b, 0x130d0d13, 0x122b1218, 0x41088319, 0x562e1b26, 0x19ab2b2b, + 0x130d2012, 0x12200d13, 0x09871818, 0x411c3141, 0x352015cd, 0x0a825918, 0x2106ed4f, 0x55183435, 0x604315a0, 0x40012108, 0x1924ac82, 0x55551219, + 0x1821b382, 0x0eda4312, 0x8207cd41, 0x18552824, 0x19128012, 0x82192a2b, 0x431820d3, 0xce4113db, 0x2f9c8908, 0x001f000f, 0x00370023, 0x01000040, + 0x21112135, 0x2321a082, 0x05cf4735, 0x60071e50, 0x17240701, 0x17233533, 0x41071d43, 0x27200a76, 0x220da345, 0x822b2a2b, 0x09a94502, 0x15155629, + 0x40121940, 0x82121540, 0x450482c3, 0x012606b5, 0xd5fe8040, 0x2c822a80, 0x45ab2b21, 0xab220bba, 0xc3825515, 0x12191522, 0x40202f84, 0x20063043, + 0x09f54900, 0x13000328, 0x00001600, 0x4a411125, 0x0b334605, 0x33071726, 0x95959501, 0x82095e48, 0x016b230c, 0x8f18802a, 0xab210cb2, 0x0ca24eaa, + 0x19001028, 0x2b002200, 0x534d0000, 0x4f172007, 0xa562228a, 0x050b5005, 0x200d1550, 0x053f5c01, 0x7f4faf20, 0x09a36818, 0x2a001722, 0x2b0da871, + 0x15161607, 0x22263423, 0x33161406, 0x291bac71, 0x3529243a, 0x3246322b, 0xae712332, 0x5313240b, 0x715d3628, 0x2f2506ae, 0x232c450b, 0x0db27133, + 0x4c332423, 0x06065d00, 0x03318382, 0x1d000a00, 0x21010000, 0x11172115, 0x23072723, 0x07ba6f11, 0x2c081d70, 0x80011737, 0x000100ff, 0x4b4a602b, + 0x1c581861, 0x55562a0b, 0xd5550155, 0x4b2b012b, 0x0f78474b, 0x82555521, 0x00153a30, 0x01eb0180, 0x00060080, 0x21130100, 0x27371737, 0xfec02b01, + 0x2260802a, 0x2351833c, 0x511980ab, 0x05488982, 0x481c200b, 0x02431503, 0x0efd4709, 0xf9477f82, 0x08e24216, 0x2c000928, 0xd4012c00, 0x8682d401, + 0x13000c3d, 0x21001b00, 0x2e002800, 0x3b003500, 0x37370000, 0x26151716, 0x37363726, 0x82070617, 0x06332405, 0x58260706, 0x072d065b, 0x26071716, + 0x07063727, 0x37363623, 0x08098205, 0x27171629, 0x35272607, 0x06071616, 0x37362707, 0x30241e79, 0x2f88431b, 0x3f331f24, 0x2b051d72, 0x65101c03, + 0x26263426, 0x1805c334, 0x2a0aeb93, 0x1c064e01, 0x4d06291e, 0x822f251e, 0x2430282c, 0x5b3f331e, 0x82061c1e, 0x840c202d, 0x246b2618, 0x14431a2f, + 0x213783a1, 0x4b845526, 0x29837e20, 0x84721421, 0x8b90202a, 0x02002d2a, 0x11003100, 0xef01cf01, 0x3e000700, 0x29093b52, 0x32333637, 0x07061417, + 0xb282020e, 0x15161627, 0x27222306, 0x06696616, 0x83373421, 0x3634260d, 0x26262737, 0x21278335, 0x0c823526, 0x143d2482, 0x323246dd, 0x23933246, + 0x261e222e, 0x0607021a, 0x1a090903, 0x2e221e26, 0x1d230223, 0x8204821d, 0x22302817, 0x20261a12, 0x84242d20, 0x82ab2012, 0x3222082e, 0x111c8f46, + 0x010f401f, 0x04010304, 0x1f400f05, 0x060e1c11, 0x11113b23, 0x0e06233b, 0x4725111c, 0x1482090b, 0x881d1221, 0x09002114, 0x200cbd45, 0xb790180b, + 0x3700290c, 0x27153335, 0x37071737, 0x26200382, 0x2c06185a, 0x23153317, 0x37270737, 0x35231527, 0x20078207, 0x33078207, 0x2e9d2aeb, 0x1ea62e1e, + 0x34841e2e, 0x26342626, 0x1d8080ab, 0x55221082, 0x1282272a, 0x15800125, 0x82818080, 0x2102820e, 0x1d82c81e, 0x05342624, 0x0c827f2a, 0x80806323, + 0x361f8291, 0x002a2a73, 0x00400003, 0x01da0115, 0x000200d5, 0x0011000a, 0x82330100, 0x232b0877, 0x23072327, 0x07332137, 0x23350333, 0x19326701, + 0x0f294515, 0x45290f44, 0x55d5d5fe, 0x01409555, 0xc02a4e5d, 0xc0c02b2b, 0x82c000ff, 0x582b2038, 0x052206e9, 0x40820e00, 0x27072c08, 0x27073335, + 0x07270701, 0x27352335, 0xb5216b01, 0x01cf56d6, 0x4d581b4f, 0x2b016a40, 0xaa2eb539, 0x1bb0fe95, 0x4fc08359, 0x1801006b, 0x23082564, 0x13000006, + 0x95286f85, 0x965656d6, 0xaad50140, 0x09205c83, 0xc03f9f84, 0x0400eb01, 0x0c000800, 0x14001000, 0x27001900, 0x2f002b00, 0x35250000, 0x27061433, + 0x83153335, 0x82132003, 0x11072907, 0x32131133, 0x21231516, 0x27057d4f, 0x23153311, 0x25352622, 0x03201a82, 0x01340382, 0x111a2b95, 0x2a2b802b, + 0x802ad52b, 0xfe2b1a11, 0x55111aab, 0x11230082, 0x8255011a, 0x2b403316, 0x2aab1a11, 0x2b2baa2a, 0x2b2b00ff, 0xfed60180, 0x2182012a, 0xd6202883, + 0xd5203882, 0x00211785, 0x5092820a, 0x0f20054d, 0x8306b441, 0x00332d8c, 0x0043003f, 0x01000047, 0x33152135, 0x8a490183, 0x15352105, 0x1a174318, + 0x9f821720, 0x03823720, 0x30832720, 0x28842320, 0x1517332f, 0x23213533, 0x95013315, 0x2b2ad6fe, 0x1802822b, 0x82103b43, 0x2bab2313, 0x1d85552b, + 0xff2a8029, 0x012a2a00, 0x85808015, 0x2b95212a, 0x01210084, 0x0b784f40, 0x2005e869, 0x8200832a, 0x0800211d, 0x0a089a18, 0x8e180f20, 0xe4450ce5, + 0x07225c08, 0x2210c25c, 0x18342622, 0x8713d98e, 0x22c42c27, 0x19221a1a, 0x1919226f, 0x836f1a22, 0x3b1a210b, 0x91200b84, 0x8e180b84, 0x1e840ccb, + 0x57011921, 0x3c200588, 0x1a222f82, 0x3b823c22, 0x3b221923, 0x202c831a, 0x8a058bc4, 0x0900221d, 0x08008200, 0x01e50120, 0x000200e5, 0x000c0007, + 0x00130010, 0x00200016, 0x003d0024, 0x27332500, 0x23273507, 0x04832715, 0x35172108, 0x15111523, 0x33151733, 0x27070103, 0x35262221, 0x15052711, + 0x23213533, 0x16322127, 0x35271115, 0x8607d86b, 0x55012607, 0x0c2a1f1f, 0x3e02824a, 0x611f5656, 0xca01d91f, 0xb6fe2b1b, 0x012b1911, 0x00ff5655, + 0x4a012b1f, 0x1f2a1911, 0x85564a2b, 0x232d8204, 0x80560c4a, 0x56230383, 0x821f0156, 0x10013631, 0x2b1b36fe, 0x4a011119, 0x56561f2b, 0xfe11192a, + 0x2a1f2bb6, 0x830d8256, 0x0a002104, 0x6a085e62, 0x1b240bb4, 0x23001f00, 0x180b0258, 0x200f8e94, 0x060a5803, 0x85461783, 0xab01220f, 0x20008356, + 0x46058a2a, 0xb8820b8a, 0x56805622, 0x01210283, 0x82068400, 0x18098a0c, 0x390daa5e, 0x001e0004, 0x01cd011e, 0x001400cb, 0x0021001d, 0x13000030, + 0x27070116, 0x51183523, 0x33330912, 0x17273335, 0x32332723, 0x27151516, 0x35331537, 0x4d272307, 0x0720068e, 0x232a1782, 0x36016235, 0x2048a218, + 0x02822b20, 0x75083c08, 0x282008f7, 0x6020130d, 0x18082b2b, 0x13130d4b, 0x18132013, 0xfe63cb01, 0x49a217cd, 0x35356920, 0x752b2b80, 0x0d132095, + 0x15092029, 0x69176015, 0x17150d13, 0x002b2d07, 0x67400005, 0x0d24083e, 0x1d001900, 0x20059258, 0xa0631823, 0x07352409, 0x43153335, 0x15260634, + 0x15233505, 0x80841433, 0x9c831382, 0x2a150123, 0x226f822a, 0x84404a0d, 0x4001238a, 0x7c844b2b, 0x85822020, 0x4040e028, 0x400d1360, 0x7d82130d, + 0x83838020, 0x15150a2d, 0x2b2d0a14, 0x0d13802b, 0x18000300, 0x22090a88, 0x5817000f, 0x535f118a, 0x225a2307, 0x6e581919, 0x01332706, 0x4b4b6a21, + 0x61584b6a, 0x825d200b, 0x6a4b210f, 0x24214e91, 0x052e6732, 0x45074c56, 0x012607df, 0x32324648, 0x48853346, 0x0b84a320, 0x20055946, 0x214884a3, + 0x12833220, 0x00070029, 0x012a002a, 0x82d501d6, 0x000b3058, 0x001b0013, 0x0027001f, 0x2500004f, 0x79072737, 0x34580727, 0x074c5807, 0x1b822720, + 0x06221624, 0x7a821614, 0x4c181720, 0x07290987, 0x27272206, 0x37373426, 0x7a5e1827, 0x36372308, 0x21823233, 0x07141534, 0x4e4e6301, 0x0d121e4d, + 0x490c120d, 0x120c0c12, 0x0b841f0c, 0x4d4d2424, 0x0f84bb4e, 0x07556533, 0x09065c07, 0x5554060a, 0x5d061206, 0x55550606, 0x2a068206, 0x54550612, + 0x06090a06, 0x8206065c, 0x7a4e2140, 0x200ab65f, 0x250b841f, 0x4e4d4e1f, 0x4c830c23, 0x07553424, 0x38930710, 0x5a844983, 0x180a8953, 0x203c3746, + 0x06cb5c06, 0x0300ab22, 0x4f0a6847, 0x172014b6, 0x83065342, 0x82372007, 0x0fb87a0b, 0x2a2bab27, 0x2a2ad52b, 0x1237572a, 0x822b8021, 0x2a562400, + 0x182b562a, 0x200d2149, 0x09055406, 0x01111723, 0x051c4637, 0x4c233521, 0x9f4b06ea, 0x6b012d0b, 0xfe2a6b6b, 0x202b0ad6, 0xf5202b2b, 0x220aa64b, + 0x82014a20, 0x83f52017, 0x2b2b2216, 0x0bda4560, 0x20264e4a, 0x08b54606, 0x0c000735, 0x1c001400, 0x29002400, 0x34250000, 0x22153336, 0x83331506, + 0x86232007, 0x1403280c, 0x32352306, 0x86333536, 0x83232007, 0x7a012007, 0xeb200785, 0x2008927a, 0x32098380, 0x401a2680, 0x3f2a573e, 0x40261a2c, + 0x702b8a61, 0x84800150, 0x820b840e, 0x0a4b4c13, 0x0b00052b, 0x30001100, 0x00003600, 0x22768301, 0x83271707, 0x14032c06, 0x35362707, 0x07013707, + 0x82150627, 0x88372083, 0x82858306, 0x2106820d, 0x24843737, 0x48015c08, 0x2a2f3f39, 0x1e1b2242, 0x1f22890c, 0x011bc016, 0x133d1b65, 0x1f0d122a, + 0x17212b2b, 0x1d564235, 0x291f1647, 0x581b2232, 0x0103220b, 0x162b2209, 0x2a0b2242, 0x393f1501, 0x1b2f2a1f, 0x1b9bfe1b, 0x15221b3d, 0x351e1135, + 0x1b592444, 0x192b3835, 0x2a1f1f12, 0x1b1e5813, 0x620c0b22, 0xed4c0d09, 0x05036207, 0x7dd50126, 0xb07d7db0, 0x220a8f42, 0x82280018, 0x343523c6, + 0xdf792326, 0x32332309, 0x11833536, 0x111f9e18, 0x40012308, 0x56561218, 0x56562b2b, 0x0e121812, 0x1156120e, 0xfe111919, 0x1a1a11d5, 0x20200111, + 0x2b2b1912, 0x8c822b2a, 0x120e2024, 0xdd41ae12, 0x00022f0c, 0x01950015, 0x008001eb, 0x0017000b, 0xca7b1200, 0x06222505, 0x36342315, 0x20080b8a, + 0x2b8ac29f, 0x2b70a070, 0x2a587aae, 0x2a3f583f, 0x618a8001, 0x4f71714f, 0x3e583561, 0x2c3f3f2c, 0x0cd3563e, 0xc8711920, 0xb45c1809, 0x08c76e09, + 0x8b824020, 0x42805521, 0xd6240a7c, 0x56805656, 0x0ea94b18, 0x09fb7418, 0x21001125, 0x18010000, 0x4107589b, 0x23200601, 0x2211e056, 0x54558040, + 0x2a20051c, 0x230ade56, 0x802b4001, 0x2b23f883, 0x182b1812, 0x4e0d75ba, 0x132409cf, 0x27002300, 0xf6826284, 0x16141523, 0x07664133, 0x132b6491, + 0x01153335, 0x19125540, 0x842a1219, 0x216a8a04, 0x6c822a80, 0x80121922, 0x6e901783, 0x2b00ff23, 0x0a22412b, 0x15000522, 0x41052241, 0x2b22121e, + 0x404f2b56, 0x2bd6220b, 0x181a41ab, 0x24001422, 0x830b2342, 0x353323be, 0xbf823523, 0x250f3a50, 0x12194001, 0xb3825555, 0x04838020, 0x7c415520, + 0x15012909, 0x2b19122b, 0x5612182b, 0xbd200482, 0x6b0c1a42, 0x13220bb2, 0xa8461f00, 0x51122009, 0x232406e3, 0x37342622, 0x200a4157, 0x073a6aba, + 0xab111925, 0x18ea7d58, 0x260de583, 0x1911ab58, 0x5713b07d, 0x2f590a87, 0x001b2e05, 0x2500002f, 0x32152311, 0x23061416, 0x26528235, 0x32153336, + 0x82263436, 0x1406220b, 0x11204116, 0x3337332e, 0xabab0117, 0x2d3e3e2d, 0x1c28281c, 0x0b830383, 0x86725e82, 0x26452f07, 0x016b2680, 0x5a3d1600, + 0x3a28263e, 0x03828927, 0x0b822620, 0x2a011522, 0x230b3d5f, 0x01002b2b, 0x2008b645, 0x16b91818, 0x00012a42, 0x01400080, 0x00c00180, 0xa350180d, + 0x21ce8408, 0x1a821732, 0x46335531, 0x15233232, 0x55c00116, 0x323223d6, 0x650c3346, 0x992d06f7, 0x1100d201, 0x15250000, 0x35211533, 0x0a087033, + 0x80150138, 0x3480d6fe, 0x577c5849, 0x2a53a84d, 0x5608542a, 0x58583e35, 0xc658373e, 0x012b2205, 0x253982d9, 0x00250007, 0x344b1200, 0x14252306, + 0x46840706, 0x61352321, 0x232107c4, 0x34528815, 0x12121c6e, 0x5901121c, 0xfe40374d, 0x090c15ab, 0x150c0940, 0x345e84ab, 0x1a131501, 0x141a1313, + 0x53075637, 0x09566a2a, 0x56090c0c, 0x7b6e8640, 0x012e0dfc, 0x27071707, 0x62490137, 0x80801e62, 0x06846201, 0xb7202182, 0x2009fd7b, 0x28208313, + 0x8080d527, 0x0162621e, 0x20068480, 0xdb4e1800, 0x001d3209, 0x00350029, 0x004d0041, 0x0e220100, 0x1e141502, 0xc25e1802, 0x82332009, 0x3536240a, + 0x72022e34, 0x27210b5b, 0x097e7222, 0x87720720, 0x22232407, 0x6a143726, 0x3336068a, 0x00011632, 0x213b4d2c, 0x2c4d3b21, 0x030d1f16, 0x24250506, + 0x0d82223a, 0x130d4928, 0x120e0d13, 0x07864e12, 0x0e12d822, 0x80200985, 0x0c821684, 0x82d50121, 0x832c2026, 0x161f2f3c, 0x04031014, 0x3a230604, + 0x34462823, 0x2a87ea1e, 0x0d135522, 0x0d223383, 0x3a853513, 0x85631221, 0x7413200e, 0x3a480a55, 0x18052009, 0x2a14724e, 0x111a0001, 0x1a1180fe, + 0x8201111a, 0x18f52005, 0x2008734e, 0x18128300, 0x220aba45, 0x430f0007, 0x14240c64, 0x34262206, 0x22085443, 0x187db07d, 0x840c9e80, 0x55220838, + 0xab01d501, 0x21001700, 0x32010000, 0x23141115, 0x22262722, 0x22230607, 0x33341135, 0x32161732, 0x0d833637, 0x36152722, 0x012a0d82, 0x020c0cc9, + 0x60c66004, 0x08870204, 0x5d4e1c35, 0x59525358, 0xab015358, 0x0ec6fe0e, 0x02232302, 0x843a010e, 0x18372507, 0x1818e818, 0x55216582, 0x059c6800, + 0x2000082e, 0x33370000, 0x23373426, 0x05141516, 0x23340382, 0x34352221, 0x27343637, 0x33343526, 0x14153221, 0x8c140607, 0xe8243482, 0x02050118, + 0x55224f8d, 0x6783b053, 0x7a896b20, 0xc68a8386, 0x1f001335, 0x32120000, 0x1416021f, 0x2206020f, 0x3426022f, 0x8216023f, 0x841420ce, 0x27342bc8, + 0x135d9ab3, 0x06121206, 0x08875d13, 0x568cf025, 0x83560f0f, 0xab012a04, 0x42130310, 0x03134286, 0x25088710, 0x703a0e1b, 0x04830e3a, 0x2147e749, + 0x0c410003, 0x000f2e07, 0x00190014, 0x22210100, 0x14111506, 0x2cfd8216, 0x34113536, 0x15330726, 0x37070727, 0x05ba5317, 0x19191225, 0x82000112, + 0x6aa72a05, 0x33563535, 0x01483823, 0x0b2b77d5, 0x20962a28, 0x2f449520, 0x0c67604b, 0x09d7456c, 0x64000821, 0x07205480, 0x300a854e, 0x0010000c, + 0x0024001a, 0x00400030, 0x33350100, 0x08ac5615, 0x0c821720, 0x2335372a, 0x33353315, 0x07352335, 0x2206e948, 0x18273632, 0x081a06a7, 0x152b0122, + 0xfe2b01eb, 0x951911d5, 0x2040e015, 0x12352020, 0x0e35350e, 0x0d136b12, 0x0d152035, 0x1911b613, 0x3b08e245, 0x7540400b, 0x192ad5fe, 0x4b2b0111, + 0x20161616, 0x16202a80, 0x130d4040, 0x16371380, 0x2a220582, 0x2a88ad13, 0x19110023, 0x09565f00, 0x13000327, 0x23001b00, 0x14be4b00, 0x23151327, + 0x32363435, 0x07d66e16, 0x2a0fd861, 0x3c42c0f5, 0x1c284c42, 0x611c281c, 0xfe3c12e3, 0x161010e5, 0x1d401a1a, 0x261d1d26, 0x15000300, 0xeb016000, + 0x0700a001, 0x19000f00, 0x76090157, 0x06210560, 0x26678214, 0x22060617, 0x79362726, 0x1c250b95, 0x1c1c809e, 0x56048380, 0x8d7906eb, 0x58cc2405, + 0x82584848, 0x26568203, 0x012b0012, 0x82f001d5, 0x831f20c5, 0x005908c7, 0x06141616, 0x22230607, 0x33163727, 0x34023e32, 0x23262726, 0x15372715, + 0x17073233, 0x17352737, 0x86012707, 0x1721212e, 0x2b315137, 0x191f1e20, 0x1a1a243e, 0x5a3e2c12, 0xe821015a, 0x8a4e4e4e, 0x89018b8a, 0x50424f2e, + 0x1f183817, 0x3f241a0d, 0x2c123e32, 0x455b5a45, 0x381c82be, 0x8a8a8a3c, 0x57000400, 0xab015700, 0x0e00eb01, 0x1a001400, 0x00002000, 0x22748401, + 0x82363635, 0x266b826d, 0x17163703, 0x55272615, 0x3f0809da, 0x3f150137, 0x2e3f5757, 0x612e3d3d, 0x171f7e61, 0x0539301e, 0x061c1e10, 0x2b041241, + 0xa9011d06, 0x60826008, 0x47082b08, 0x5308475e, 0x8efe615f, 0x2b05111f, 0x181d8e06, 0x5f2e251e, 0x262d1b1a, 0x55207382, 0xa9207382, 0xf74b7382, + 0x26738205, 0x33373625, 0x56070706, 0x23210554, 0x24ee8226, 0x06350727, 0x084d6506, 0x68013522, 0x1c2e4583, 0x1f171e72, 0x2b943024, 0x1d1f1105, + 0x82836158, 0xb6258a83, 0x252e1e17, 0x29138216, 0x1ebe061c, 0x46241e17, 0x7e84535f, 0x8a842b20, 0x01594220, 0x57212013, 0x172210b4, 0x12420717, + 0x6b6a220f, 0x120a426b, 0x55556b24, 0x0a500200, 0x00132208, 0x09334b23, 0xd2532320, 0x10a0650a, 0xde59c020, 0x23058205, 0x1a118001, 0x22075846, + 0x8655aaab, 0x0caf6500, 0x18000438, 0xd9013000, 0x0500c501, 0x25000d00, 0x00002b00, 0x23173537, 0xc7662622, 0x16052707, 0x07061415, 0x12820607, + 0x03272908, 0x36343526, 0x33363737, 0x01171632, 0x37372626, 0x1f4a7d15, 0x12221a11, 0x0c120c0c, 0x0f034301, 0x0a069d0b, 0x6a05170c, 0x9e310982, + 0x160b0809, 0x10cafe05, 0x5b34070e, 0xfb1ab287, 0x2025830d, 0x221f82a6, 0x82410418, 0x0001211f, 0x16210a82, 0x260a8305, 0x2007b2fe, 0x45c07d10, + 0xd52408e7, 0x1d000900, 0x3728ec82, 0x35231527, 0x33351707, 0x280fab4a, 0x17333733, 0x4b4b4001, 0x20028280, 0x0ae66b6b, 0x27802727, 0x364b4bb5, + 0x20038236, 0x0be36bc0, 0x842a2a21, 0x016b245b, 0x909501d5, 0x1137225b, 0x20e18227, 0x077c4c23, 0x16322125, 0x82150115, 0x4a4a3158, 0x55556b80, + 0xd5fe090c, 0x090c0c09, 0x0c092b01, 0x4a255b87, 0x56eafe56, 0x2015844b, 0x48058300, 0x57180abd, 0x05206d99, 0x2008524f, 0x37d68203, 0x0013000f, + 0x37000019, 0x37071537, 0x23230614, 0x07330137, 0x33363435, 0x34080582, 0x01171625, 0xfac62726, 0x111abdbd, 0xabfe552a, 0xa31a552a, 0x6001fa3d, + 0xa1fe0619, 0xfa400717, 0x112bbd3d, 0x2b01551a, 0x1a112a55, 0x07bb3dfa, 0x07a2fe17, 0x21db6817, 0x1616242b, 0x06070614, 0x35372722, 0x0b854832, + 0x201f012a, 0x25101516, 0x165a266a, 0x3e0c9048, 0x2c342012, 0x26261034, 0x0400805a, 0x7e000000, 0x82010002, 0x1e001200, 0x58005100, 0x64250000, + 0x072d0504, 0x14151506, 0x32161617, 0x27363637, 0x05e16234, 0x22231425, 0x18222535, 0x350939c7, 0x14151617, 0x22230607, 0x33352627, 0x32331614, + 0x032e3435, 0x0d822627, 0x36373422, 0xa2083184, 0x26273423, 0x11333725, 0x01073523, 0x17070a13, 0x0217080a, 0x082c1001, 0x537b0406, 0x52161329, + 0x1e1c0153, 0x090d0613, 0x080e0813, 0x0c2c0505, 0x05113912, 0x21101629, 0x230e0606, 0x130c0806, 0x23110c2a, 0x122a1414, 0x6549fe0c, 0xe6402b06, + 0x0f112436, 0x35340e03, 0x20050918, 0x47120c10, 0x391c186d, 0x356e6e29, 0x02060e17, 0x03060203, 0x0a0b0509, 0x040f250b, 0x0e0a0c27, 0x09061710, + 0x02090603, 0x170d0803, 0x11040e26, 0x04151a10, 0xff253a03, 0x0016cd00, 0x00590002, 0x01c2017e, 0x82330082, 0x01002209, 0x21ec8622, 0x01831617, + 0x2620d48f, 0xd690d282, 0xfb840720, 0xf9832220, 0xfa821720, 0x2323342c, 0x37323335, 0x23343536, 0x91640722, 0x32332f05, 0x76011416, 0x0714120d, + 0x0e081216, 0xdf820607, 0x11381325, 0x83172805, 0x050725df, 0x12141c10, 0x2508df86, 0x2aa10c13, 0x2f4a1718, 0x110d0b2b, 0x191a2e2a, 0x26020920, + 0x2a030a1a, 0x26101130, 0x0c21012a, 0x070c010b, 0xde8c0403, 0x83110d21, 0x020326de, 0x0c0d0604, 0x3bde8518, 0x1e030514, 0x12252c0e, 0x14222614, + 0x21520a08, 0x260b0517, 0x2d090614, 0x48240513, 0x08398318, 0x0982eb20, 0x21001d2a, 0x33130000, 0x37172315, 0x0723da82, 0x4b232626, 0x3e2508e1, + 0x26343502, 0x33ca8207, 0xd68080c0, 0x080f071e, 0x223d191e, 0x1e354528, 0x2845351e, 0x163e0783, 0x012a2a95, 0x1f5e2beb, 0x1f070f08, 0x351e1714, + 0x46282746, 0x341e1e34, 0x3d222846, 0x5d828075, 0x1e001e25, 0x8301c401, 0x00182267, 0x23678628, 0x36361715, 0x27205882, 0x06276f88, 0x07271707, + 0x4c060617, 0x37220657, 0x70823717, 0x0b955525, 0x8714160b, 0x2d182875, 0x1eab4014, 0x83141248, 0x3b20247a, 0x821e3318, 0x2e6b2877, 0x182d1495, + 0x86183d22, 0x0a0c287f, 0x491e6f40, 0x83203a18, 0x12142584, 0x08001e33, 0x2a08d348, 0x00090004, 0x0012000d, 0x711b0017, 0x2523053d, 0x82233736, + 0x20048289, 0x25098215, 0x26331535, 0x04872727, 0x06110323, 0x56c51806, 0xa53e080a, 0x70940202, 0x207f030c, 0x02943e1e, 0x037f9002, 0x1e3e700c, + 0x57573f4a, 0x7d7db004, 0x06d57db0, 0x11401610, 0x043e1605, 0x1016c010, 0x05164006, 0x10143e11, 0x5201b2fe, 0x60826008, 0x23527601, 0x002b2607, + 0x01d50115, 0x239482eb, 0x1300001f, 0x27051d57, 0x23173523, 0x27073315, 0x2205c170, 0x82352335, 0x17373308, 0xd5211123, 0x2b1a1180, 0x402b5580, + 0x11aa2a40, 0x0884551a, 0x012a0129, 0x111a2b55, 0x82d58080, 0x21088216, 0x07822baa, 0x6f00ff21, 0x0b210c2c, 0x0a811800, 0x065c6809, 0x55821720, + 0x15332523, 0x205d8323, 0x200b8217, 0x200b8215, 0x83038203, 0x40012a07, 0x5555552b, 0xd5fed5d5, 0x3208822b, 0xab2a2a80, 0xd5d5d5ab, 0x40018080, + 0x2b2a2b80, 0x822b2a55, 0x82d52006, 0x2a012803, 0x002ad62a, 0x1840000c, 0x211c214b, 0x537b002f, 0x83788205, 0x20038767, 0x200f8237, 0x83708227, + 0x8a17200f, 0x8227201b, 0x80012b0b, 0xc0555555, 0xc055c056, 0x0782eb55, 0x556a5623, 0x250c8415, 0x95015555, 0x1b82d555, 0x6a210284, 0x23148256, + 0x566b5555, 0x6b240084, 0x03005555, 0x00268a8e, 0x21152113, 0x04823517, 0x402f5482, 0x6bfe9501, 0xfe000195, 0x9501806b, 0x8295aa80, 0x3b308200, + 0x01550000, 0x00ab01fc, 0x001e0007, 0x37000021, 0x07232733, 0x25333733, 0x27230733, 0x06200282, 0x0808077c, 0x3717333f, 0x37251733, 0x4428dc17, + 0x0f29442b, 0x27080144, 0x2020252c, 0x52150226, 0x64644731, 0x10335247, 0x2022201a, 0x1819d6fe, 0x2ac0c0ab, 0x8282c096, 0x65342b09, 0x8740658c, + 0x4e0e8787, 0x1854184e, 0x583a212f, 0x0d185418, 0x0600492a, 0x21001500, 0xe001eb01, 0x0720b682, 0x19220b82, 0xb2831d00, 0x07379382, 0x23153337, + 0x15161627, 0x26220614, 0x37363435, 0x15073335, 0x5e173523, 0x3608061a, 0x261e7001, 0x4040151e, 0x4b231d6b, 0x1d234b6a, 0xd640eb80, 0x1e26c92a, + 0x261d7d26, 0x842bca1e, 0x35233a11, 0x23354b4b, 0xc067113a, 0x3fff2b2b, 0x1e27533f, 0x86090027, 0x84f4206e, 0x570f206e, 0x27260a0c, 0x37370000, + 0x5e830717, 0x078a5418, 0x80820520, 0x13820720, 0x755e1320, 0x207e8207, 0x200b8237, 0x2465824c, 0x6a4a2a81, 0x2478824b, 0x40402b01, 0x8289823b, + 0x81262502, 0x7b40962a, 0x74200882, 0x35246982, 0x6a013f3f, 0x4b241f82, 0x782b206a, 0x01219182, 0x8234824b, 0x2bd42314, 0x2282792b, 0x0cfa7418, + 0xf3821420, 0x35010025, 0x48371523, 0xdf600f6a, 0x6bab2309, 0x3c4c3635, 0x4c562009, 0x01250564, 0x20abab00, 0x78c218b5, 0x63421814, 0x05fd4f09, + 0x07272123, 0xea701827, 0x076c4807, 0x2a016b36, 0x01364a60, 0x1b1b100b, 0x1180fe10, 0x95101b1a, 0xcb406080, 0xd62a0c82, 0x111a1b10, 0x1b102a01, + 0x51180e00, 0x04320863, 0x0f000b00, 0x18001300, 0x20001c00, 0x29002400, 0x8f182d00, 0x0022085f, 0x5f823337, 0x26722720, 0x5d132005, 0x152407d5, + 0x01363423, 0x11200c82, 0x05200382, 0x7f830382, 0x5d152321, 0x232605ef, 0x23061413, 0x9c433535, 0xd5403706, 0x60273544, 0x00ff2b01, 0x2a561a11, + 0x2b2b552a, 0x011b2b80, 0x00822a3b, 0x2baafe30, 0x10ab012b, 0x2b2b2b1b, 0xd62b2bab, 0x0882101b, 0x5b6b2b26, 0xd5662e45, 0x2982a282, 0x102c0f82, + 0x2babfe1b, 0x2a2b8001, 0x101b802b, 0x2b210482, 0x24c082fe, 0x2b2aaa2b, 0x18b1822b, 0x2009f476, 0x22c18207, 0x86140010, 0x002730c1, 0x0030002c, + 0x00390034, 0x0041003d, 0x43151300, 0x072005c4, 0x37200782, 0x0882b984, 0x03201483, 0x03830782, 0x26221322, 0x1325af83, 0x23151632, 0x20138217, + 0x84038227, 0x202d82c4, 0x22108335, 0x82802a95, 0x822b20b6, 0x826520b8, 0x2b2b28b7, 0x112b2bd5, 0x84d5d61a, 0x878020ba, 0xc00121b9, 0x2b25af82, + 0xab2a2aab, 0x21b5842b, 0xc282012b, 0x2b25bd82, 0x2b2b0001, 0x22d282fe, 0x84018055, 0x842b20c4, 0x223c8217, 0x822a2aaa, 0x4100200a, 0x072009d0, + 0x410b945b, 0xb9270fd3, 0x8e64648e, 0x4b6b0164, 0x8026097a, 0x4b4b6a4b, 0x3a55f56a, 0x0007280c, 0x0121004c, 0x75f401b4, 0x23080c84, 0x3700001b, + 0x03173727, 0x01071737, 0x07372707, 0x13333523, 0x27270717, 0x07231533, 0x6a152135, 0x441e261e, 0x01210382, 0x23048242, 0x812a2a79, 0x852b0682, + 0x01802a2a, 0x261f562a, 0x8224011e, 0xf9fe280e, 0x7a1e271e, 0x825f013f, 0x3f5b230b, 0x694980ea, 0x29bb8205, 0x10000002, 0x25001900, 0x4e713100, + 0x35172112, 0x2b064e71, 0x17163203, 0x27262623, 0x36322707, 0x22318582, 0x26222306, 0x16163327, 0x2b0001ab, 0x1912aa2b, 0x3005822b, 0x19128080, + 0x0893647f, 0x35440620, 0x0803511d, 0x2004835f, 0x20108503, 0x362082ab, 0x2baa1219, 0x2b80d62b, 0x01801219, 0x3c63882b, 0x511c1960, 0x8236fe01, + 0x4b0c8304, 0x08200a2c, 0x242f9182, 0x34002c00, 0x32010000, 0x34331516, 0x18152326, 0x200820a3, 0x0b944b33, 0x33373327, 0x27163215, 0x39258235, + 0x02263423, 0x16323634, 0x01220614, 0x1c191255, 0x58811d2a, 0x3f583f3f, 0x37516ad6, 0x27442107, 0x1634a082, 0x3b1c4b35, 0x283828c2, 0x80013828, + 0x2a1d1219, 0x3eebfe1c, 0x31082883, 0x1911eb97, 0x00011119, 0x402b1a11, 0x4b1c6719, 0xfe3b2935, 0x28283aff, 0x0400273a, 0x2b000000, 0xeb01eb01, + 0x11000900, 0x30002400, 0x34360000, 0x74823336, 0xd15c6c82, 0x35272307, 0x7e783533, 0x033d220c, 0x08e15633, 0x1c28d123, 0x204a821d, 0x2b68830f, + 0x95402b3e, 0x1a114427, 0xabfe111a, 0x40236c83, 0x82b8402b, 0x1c1d2367, 0x88842628, 0x40408227, 0xff111a2b, 0x218e8300, 0x0c8280d6, 0xe5510282, + 0x00ab3108, 0x000f0007, 0x01000028, 0x07272737, 0x07171707, 0x13210786, 0x0bad5b33, 0x27208882, 0x01250386, 0x142c2c69, 0x29038214, 0x1b3b3b65, + 0x1a3b3b1a, 0x104155ab, 0x2a162c07, 0x2b2a2a40, 0x2b2b2b40, 0x84010140, 0x2c142423, 0x841b1a1a, 0x2b012127, 0x2306035a, 0x401a1100, 0xc44e0083, + 0x2082830a, 0x27828222, 0x27070717, 0x17373727, 0x17210484, 0x5c8e1807, 0x62112009, 0x212506e4, 0x3a3a1b01, 0x2003831b, 0x8281836b, 0x2a172103, + 0x25075c5a, 0x2b01c0c0, 0x1c841b01, 0x2a3a1b22, 0x1430a285, 0x1a11c02c, 0x2a01111a, 0xfe2b1a11, 0x000400d6, 0x07d57d18, 0x1b440420, 0x05cd4406, + 0x240f8b45, 0x23113323, 0x3b038203, 0x3644d5eb, 0x0d09b526, 0x00ff090d, 0x090c0c09, 0x562a2a6a, 0x5a952b2b, 0x0cbc2e44, 0xcb181286, 0x002d0951, + 0x00400009, 0x01c0012b, 0x000500eb, 0x265f820d, 0x001f001a, 0x442c0024, 0x26080573, 0x36270701, 0x27173233, 0x15151633, 0x17270614, 0x34352623, + 0x17371736, 0x37222306, 0x16163723, 0x26260707, 0x5f321627, 0xf067052f, 0x26222205, 0x08328234, 0x37171661, 0x15271716, 0x1c013523, 0x2b24313a, + 0x5d3c530a, 0x46cb1402, 0x4f130265, 0x2b212d3d, 0x2b73880f, 0x2b792b16, 0x3b082916, 0x7c57577c, 0x112b0157, 0x70a07019, 0x471b5070, 0x0e101e16, + 0x67018074, 0xd81c4c64, 0x01070e6d, 0x6b9e3315, 0x3214080e, 0x195369c3, 0x2d094caa, 0x2c094b6b, 0x83586b16, 0x16b53036, 0x714f1c45, 0x1a719e71, + 0x110d1f11, 0x412b2b6a, 0xd530069d, 0x0400d501, 0x21001500, 0x21370000, 0x37270727, 0x220d2d43, 0x49373315, 0x352c0582, 0x15331533, 0x5600016b, + 0x40aa2a40, 0x2107a546, 0xed7540aa, 0x6a6b2705, 0xaa554055, 0x2a781a11, 0x16402105, 0x57821685, 0x2b002b24, 0x6182de01, 0x61820720, 0x2e001a23, + 0x081a7800, 0x07171723, 0x05b94827, 0x1516322a, 0x37230714, 0x17373717, 0x080ca743, 0x2307062d, 0x35012111, 0x2c1f1f2c, 0x1e428720, 0x281a1943, + 0x38503837, 0x2a3beb4b, 0x1a2b6c3a, 0x11d5fe11, 0x76111919, 0x016b010a, 0x8240012b, 0x2c202624, 0x421e421d, 0x2923820f, 0xdb1a2838, 0x074b324b, + 0x22836b2b, 0x112b0127, 0xfe16151a, 0x0a9755d5, 0x8e820520, 0x15010023, 0x23d48227, 0x27070125, 0x8a417782, 0x35172c05, 0x2b2b0127, 0x01dbfe80, + 0x597a1b65, 0xc02c0643, 0x2a446b01, 0xfe55556f, 0x257a1b9b, 0x21054c59, 0x4b84c006, 0x0a421520, 0x18142006, 0x8208ae5c, 0x14113bcb, 0x26270707, + 0x36341135, 0x1ec0d533, 0x011e4ca2, 0x131a112a, 0x1a13adad, 0x0f84ab11, 0xba82d620, 0x0e15ec2a, 0x150e7474, 0x1a111401, 0x220a9257, 0x501b000b, + 0x222806aa, 0x33151506, 0x16373335, 0xd7604c82, 0x32363107, 0x4a2b0117, 0x0c096b4a, 0x06a4562a, 0x1206c006, 0x06840382, 0x4b4acb28, 0x55090d35, + 0x12890f40, 0x0606c039, 0x00000600, 0x00022b00, 0x0700e001, 0x25000f00, 0x35002d00, 0x77003d00, 0x272410ff, 0x35231517, 0x3422b182, 0x2f613737, + 0x15332405, 0x45272722, 0x1e45073c, 0x34262305, 0x2a652224, 0x01310805, 0x2c2c3e76, 0x5a1d2b3e, 0x3d5a3e3e, 0x452a2f45, 0x083c0c0c, 0x290f1316, + 0x2d3f2c20, 0x2b3ece11, 0x1e2c3e2b, 0x5a3d3d5a, 0x225c013e, 0x19221a1a, 0x2210824b, 0x828a3e2c, 0x5a3d252d, 0x6a84315e, 0x122b2d82, 0x0c0c3c0c, + 0x2d2b2029, 0x8af8fe11, 0x19c9211d, 0x00273083, 0x00550004, 0x62ab0140, 0x31250814, 0x35010000, 0x5e981821, 0x093c4508, 0x9b823420, 0x18151521, + 0x220a10a1, 0x7c141523, 0x352c055a, 0xff800126, 0x121cd200, 0xae121c12, 0x2b2b0584, 0x1658a658, 0x0915090c, 0x820daa0d, 0x160c2905, 0x6b6b1501, + 0x131a1380, 0x032f0287, 0x222233d5, 0x141cd533, 0x0c0c0926, 0x83161609, 0x14262105, 0x2e08a855, 0x00030095, 0x0013000b, 0x1300002d, 0x43232721, + 0x8c8707c6, 0x88172521, 0x8821207a, 0x36372a09, 0x6b323333, 0xea202a01, 0x206784dd, 0x220584d7, 0x822c2901, 0x0c09235f, 0x068400ff, 0x19062c28, + 0x150119ea, 0x8b8aca60, 0xab80c222, 0xab228489, 0x7b821580, 0x15002b26, 0xeb01db01, 0x24228f82, 0x83823800, 0x17371524, 0xb4410135, 0x34352105, + 0x352f6782, 0x32331533, 0x17151516, 0x23070716, 0x82062722, 0x05232302, 0x0a871533, 0x33352325, 0x82163732, 0x80490802, 0xd4fe8080, 0x1b0f0128, + 0x8040111a, 0x1b1a1140, 0x01280715, 0x60252531, 0x01312525, 0x2d2a2a56, 0x285a2829, 0x2a2a2d29, 0x5c27282e, 0x80012827, 0x552a2a55, 0x028eebfe, + 0x09060e05, 0x401a1163, 0x63111a40, 0x8e140709, 0x2c00822a, 0x14152b2b, 0x1c2b1514, 0x001c1b1b, 0x0cb54105, 0x17000f27, 0x00002900, 0x169a1801, + 0x8a27200a, 0x07d35d0b, 0x21151734, 0x26223735, 0x01343535, 0x1c3d6b80, 0x121c1212, 0x04826b55, 0x2d2a0282, 0x1f2c58a6, 0x2000ff20, 0xaa412c1f, + 0x416d2009, 0x013007b3, 0xcb33222d, 0x0b202b1f, 0x1f2b200b, 0x030033cb, 0x081cc818, 0x0b000322, 0x4205804b, 0x27210931, 0x06294235, 0x86230621, + 0x80012b70, 0x226f00ff, 0x1a221a1a, 0x678a5880, 0x6a6a2b23, 0x28138296, 0xe006221a, 0x33232333, 0xfe6086e0, 0x022408db, 0x15008000, 0xe0019501, + 0x21001900, 0x03130000, 0x15173733, 0x37273533, 0x22353316, 0x23262727, 0x07230622, 0x37201082, 0x07d64618, 0x2d3cd135, 0x2d2b2c27, 0x3e472e0d, + 0x150f161d, 0x6f030b03, 0x8460262b, 0x420134ee, 0x2babd3fe, 0x402ba080, 0x22342a35, 0x642f0215, 0x43490f48, 0x8f180576, 0x022e43ca, 0x55001500, + 0x9501eb01, 0x16000e00, 0x507a0000, 0x15212406, 0x82331123, 0xa44718a0, 0x95013b07, 0xfe2b3323, 0xab2b2b80, 0x2626343c, 0x6b012634, 0x40c02333, + 0xc0400140, 0x0e828096, 0x34264008, 0x40000200, 0xc0013f00, 0x0700d501, 0x00000d00, 0x27262625, 0x06061737, 0x07173707, 0x00013727, 0xc0269109, + 0x0a9026c0, 0xc0c0239d, 0x7107ab23, 0x1d95951d, 0x1b7b3f70, 0x001b9595, 0x822b0003, 0x01d52e3a, 0x000f00eb, 0x00180014, 0x07011300, 0x23358227, + 0x07273717, 0x27224683, 0x0d820605, 0x4f821320, 0x8f01462b, 0xc06a501b, 0x1e4b9d23, 0x3851822d, 0x95015a45, 0x3ea83b1b, 0x1f191fa7, 0x70feeb01, + 0x9552511b, 0x1e3b7b1b, 0x2b5f8222, 0x15905a36, 0xfe30a82e, 0x1e131feb, 0x46f39018, 0x09656018, 0x33001322, 0x2216fd59, 0x51352335, 0xe2430660, + 0x0a127407, 0x65152321, 0x5f1805cc, 0x962909cc, 0x0940552b, 0x16090c0c, 0x2a08872a, 0xff000180, 0x192b0100, 0x5c00ff12, 0xfe26071d, 0x162a16ea, + 0x2882090c, 0x08881620, 0x60180020, 0x09220945, 0x8c822600, 0x214a2720, 0x37072405, 0x48161436, 0x3527080e, 0x34353632, 0x82352326, 0x3221338b, + 0x22151516, 0x46174c01, 0x5b21215a, 0xab4c1747, 0x214a1119, 0x18122105, 0x01210983, 0x350e8256, 0x053a579a, 0x3a055454, 0x22463157, 0x1a11551a, + 0x1955111a, 0x09861112, 0x290cc67c, 0x1300000f, 0x21213733, 0x95601507, 0x35273b05, 0x26c29f21, 0x4701f2fe, 0x00ff6bab, 0x8001ab6b, 0xc02a6b01, + 0x6a2b2b6a, 0xea432bc0, 0x01d52206, 0x210982c0, 0xd07d0007, 0x01212205, 0x0a4b6935, 0x08088045, 0x5601552e, 0x5601aafe, 0x18122b2b, 0x322b1218, + 0x33238023, 0x15012b6b, 0x196b4040, 0x18124012, 0x33332340, 0x0700d523, 0x15004000, 0xef01c001, 0x2708e245, 0x00430038, 0x3700004e, 0x202ce845, + 0x05d75026, 0x15163724, 0x0a941614, 0x2d200946, 0x18ea1807, 0x10131aeb, 0x59200808, 0x0683121c, 0x0d855820, 0xcb60eb22, 0x84051445, 0x80c32805, + 0x0d0d09aa, 0x83151509, 0x80aa2d05, 0x0d132a16, 0x0a0a1d09, 0x130d1525, 0x064c0992, 0x4909200a, 0x012005e5, 0x2206f059, 0x82271533, 0x15332b09, + 0x35331523, 0x33373523, 0x0e822311, 0x3311233e, 0x55012135, 0x2b161515, 0x2a2a4055, 0x40d52b40, 0x40aa56aa, 0x00012a01, 0x402b2b6b, 0x162c0282, + 0x16154015, 0x56eafe40, 0x40160156, 0x20089255, 0x080982d5, 0x18000e4d, 0x37010000, 0x32161721, 0x26343536, 0x15062727, 0x03210314, 0x23230606, + 0x01272622, 0xe0fe0987, 0x26346d09, 0x40101020, 0x2b800180, 0xd6101802, 0x01021810, 0xea565655, 0x3a131a26, 0x2b481313, 0xfe44011a, 0x1515107b, + 0x4b040010, 0x072a086a, 0x37003100, 0x00003d00, 0xf4692200, 0x34072905, 0x34352637, 0x17323336, 0x8206d845, 0x1516230a, 0x03820714, 0x22230622, + 0x2105cc49, 0x0a823535, 0x22172627, 0x16323526, 0x2f2b8215, 0x16010614, 0x2c1f1f2c, 0x1f1fbe1f, 0x0f0f1620, 0x10230982, 0x8320160e, 0x0d11210c, + 0x0e280c82, 0x89201610, 0x70507050, 0x01220282, 0x2a83208b, 0x0f214630, 0x2016210f, 0x2016040a, 0x0a041620, 0x0f841620, 0x04091f2e, 0x161f1f16, + 0xe41f0904, 0x4f714f71, 0x71200282, 0x28069242, 0x00c001b5, 0x000b0007, 0x09e44a35, 0x23350729, 0x15162515, 0x82061415, 0x210b8288, 0x29631123, + 0x32332107, 0x16221683, 0xa8853632, 0x37343530, 0x77013727, 0x120c0c12, 0x01806b0c, 0x92820f26, 0x1ad62029, 0x1a118011, 0x821a1115, 0x0c092814, + 0x2d221f16, 0x822b0117, 0x2502820b, 0x0f3b6a6a, 0x8883cb17, 0x01a06b37, 0x1a1a1155, 0x111a9511, 0x0c0c0960, 0x1f049a09, 0x2d0e2416, 0x22948216, + 0x452b0015, 0x23220643, 0x4f182b00, 0x012309e6, 0x82211733, 0x07142c7d, 0x23230607, 0x33140707, 0x82211533, 0x3734249e, 0x68232737, 0x26080727, + 0x19225a01, 0xfe1a2219, 0x011446d5, 0x030c093c, 0x9f190c4c, 0xf7050113, 0x191100ff, 0x2b4d1d05, 0x1a1a226f, 0x82801922, 0x22193603, 0x0d2a6f01, + 0x8a090109, 0x05032316, 0x0a111a2b, 0xfea2350a, 0x431984d5, 0xda4a0ae4, 0x23352105, 0x09366b18, 0x7e4e8282, 0x8001270b, 0x55555655, 0x2c666a56, + 0x83d52009, 0x5555220f, 0x0ceb50eb, 0x20476146, 0x085b6105, 0x0f000728, 0x27001700, 0x0d632e00, 0x0668420a, 0x07863620, 0x330f3c4e, 0x15163713, + 0xcb220614, 0x6a4b4b6a, 0x0c121e4b, 0x330d120c, 0x95220584, 0x6b451912, 0x78442507, 0x55463219, 0x4b241f82, 0x0d0b016a, 0x09cf4f18, 0x12183739, + 0x1812aafe, 0x56011218, 0xc4fe1812, 0x23241979, 0x00020032, 0x411f0040, 0x112406ab, 0x22000000, 0x3a056b4b, 0x15333607, 0x23260722, 0x1a013235, + 0x34262634, 0x70504026, 0x6f51516f, 0x82550170, 0x3426270c, 0x4cea4b71, 0x8343ea4c, 0x00eb2408, 0x8211000b, 0x360025c9, 0x23353632, 0x2620a082, + 0xc3820582, 0x34331523, 0x0e6d4117, 0x36343322, 0xd4231182, 0x822b3f58, 0x852b2548, 0x55802634, 0x2e097841, 0x3f583f2a, 0x1a2c3eeb, 0x2c1a2626, + 0x821a2697, 0x065a5000, 0x11000129, 0x3f3f2c1a, 0x4907002c, 0xc020066e, 0x270c7152, 0x0100002b, 0x17152335, 0x12e06018, 0x5d440120, 0x481a8206, + 0x3325050b, 0x80013315, 0x2000832b, 0x210584aa, 0x06820001, 0xaa2c0a84, 0x2b40012b, 0x2a2a552b, 0xab2b2b56, 0x01220887, 0x2d84fe2b, 0x314d3384, + 0x6007200a, 0x534f05c8, 0x4d052005, 0x3528082d, 0x33363435, 0x68173233, 0x3005714b, 0x960c0c74, 0xc00c240c, 0x9611190c, 0x6b010c12, 0x20168313, + 0x21118275, 0x14820c96, 0x11961224, 0x53820c19, 0x40008026, 0xc0019501, 0x1120dc82, 0x3220c882, 0x23275382, 0x32371523, 0x82061416, 0x11233c07, + 0x19111a01, 0x40451119, 0x354b4b35, 0x15015540, 0x561a221a, 0x4b6a4bab, 0x42800180, 0xeb2208e7, 0x90830b00, 0xe7422520, 0x07152c0b, 0x35211517, + 0x21352737, 0x18071737, 0x2007bfce, 0x28cf842b, 0x321f0f01, 0x402bd518, 0x22028240, 0x82802ac0, 0x808025e1, 0x4313562a, 0x0ab95718, 0x00001c26, + 0x37171613, 0x4825bd18, 0x2005bf50, 0x22e482d5, 0x4214000f, 0x262109f1, 0x05d14c14, 0x17322627, 0x22ef0303, 0x20dc821a, 0x2d038240, 0xe622221a, + 0xc0c0c04d, 0x1919221a, 0x1683a222, 0x55401926, 0x5501abfe, 0x49753148, 0xa8180733, 0x04233f75, 0x6a002b00, 0x032d050f, 0x0f000b00, 0x00001d00, + 0x35211501, 0x069b5104, 0x23350729, 0x16323715, 0x82231515, 0x35233f14, 0x01333634, 0x0100ff80, 0x0d0d120c, 0xaa2b0c12, 0x55261aea, 0x265500ff, + 0x55c0011a, 0x1584c055, 0x6a6aa139, 0x801a26ea, 0x1a805555, 0x00020026, 0x013a003a, 0x00c101d6, 0x82170011, 0x07300859, 0x07270717, 0x36263727, + 0x16363637, 0x06060706, 0x34262707, 0x3d011737, 0x931e931f, 0x0cd01e93, 0x4c1f1911, 0x191f092e, 0x195aa840, 0x0a019619, 0x182f1786, 0x091f1940, + 0x191f4d2e, 0x195a1b10, 0x65951946, 0x04206cb6, 0x2806c94b, 0x000700ab, 0x0013000b, 0x09375029, 0x15233723, 0x072a4133, 0x15172522, 0x36076844, + 0x35262206, 0x36343523, 0x01152133, 0x12121c72, 0x3540121c, 0x84a8fe5f, 0x4b012709, 0x34262b40, 0x03828026, 0x111a2b2d, 0x13752b01, 0x1a13131a, + 0x848b35ad, 0x55cd2607, 0x26261a6b, 0x2303831a, 0x561a11eb, 0x830c1c65, 0x4f31207b, 0x35222e73, 0x774f1533, 0x80352224, 0x1f794f35, 0x47062553, + 0x09310547, 0x1e001100, 0x32360000, 0x26263736, 0x16070622, 0x061f4612, 0x62322621, 0x273105d8, 0x34352626, 0x134a46dd, 0x584e5801, 0x34871301, + 0x32f08226, 0x5170a090, 0x3e31313e, 0x1c287a51, 0x1d25261c, 0x8209011c, 0x34262d15, 0x424f7150, 0x31311166, 0x4f426611, 0x080c0d4b, 0x00001522, + 0x15273525, 0x11153213, 0x27070714, 0x35220707, 0x37373411, 0x40013717, 0x080bf580, 0x03728078, 0x6b310584, 0x01fd2dfd, 0xbefe0b28, 0x2d290208, + 0x010b012c, 0x7b088442, 0x07210a6b, 0x2c971800, 0x00012e6a, 0x01400060, 0x00d501a0, 0x01000005, 0x2fb88213, 0xa0000127, 0x0f91910f, 0x7afed501, + 0x0f40400f, 0x6b249982, 0x95012b00, 0x032c2282, 0x1a000d00, 0x21370000, 0x14132115, 0x08052e4a, 0x1706223b, 0x07070614, 0x3435022e, 0x6b163236, + 0xd6fe2a01, 0x1924196a, 0xab1a221a, 0x0e202040, 0x6a4b472b, 0x012a554b, 0x1818122a, 0x1a1a1112, 0x25752b11, 0x7c340f25, 0x4b4b352b, 0x8ca11800, + 0x18072009, 0x6843bfc3, 0x032209b3, 0xa7830c00, 0x2335252c, 0x37332307, 0x26272736, 0xa4590707, 0x11073108, 0x01333634, 0x602b7580, 0x08089335, + 0x93070826, 0x0a41c318, 0x2b2bd525, 0x82070893, 0xcb93212e, 0x24052c55, 0x11800155, 0x591c4419, 0xbf630420, 0x82042008, 0x551120b3, 0x272008ce, + 0x22050b48, 0x82153523, 0x0fc84808, 0x2a016b2e, 0x4a364a60, 0x3e2b573e, 0xea261a2c, 0x2d090248, 0x40608080, 0x2c3e5820, 0x27416b3f, 0x81492a1a, + 0x8203200c, 0x01552b68, 0x00ab01c0, 0x00110003, 0x66180015, 0x23200737, 0x3d05564c, 0x17213735, 0x35211527, 0x01800001, 0x552b1540, 0x011515d6, + 0xfe151556, 0x555580aa, 0x00828055, 0x6b6b2b25, 0x732b2bab, 0x0b5426e8, 0x00c02b07, 0x00130007, 0x004d001f, 0xa5451200, 0x36172b06, 0x27263436, + 0x14062223, 0x0b8b3316, 0x06143725, 0x83331507, 0x080c5404, 0xe96e2620, 0x35332205, 0x26098326, 0x33333634, 0x85151632, 0x24ee3023, 0x19241919, + 0x1919112b, 0x19120111, 0x88011219, 0x24ac2d09, 0x1c24401c, 0x09aa090d, 0x40241c0d, 0x0d840285, 0x012c1582, 0x18241940, 0x01842418, 0x01192219, + 0x6a223f82, 0x08841801, 0x1ec01834, 0x1e18082d, 0x0919082c, 0x19090c0c, 0x181e2c08, 0x03822d08, 0x161e2c22, 0x16201083, 0x183b1982, 0x3e000200, + 0x95011600, 0x1a00e001, 0x00002200, 0x17372737, 0x23150737, 0x55323735, 0x0721097e, 0x20108217, 0x07d05127, 0x95d33008, 0x27226908, 0x0b036f2a, + 0x150f1503, 0x2e473f1d, 0x2d2b2d0d, 0x1a1a2249, 0x1d631922, 0x0fad152b, 0x022f6449, 0x2b332215, 0xa02a4035, 0x82cb2a80, 0x22192117, 0x250a1543, + 0x001c000b, 0x95480100, 0xd9c6180a, 0x0694480c, 0x577c5322, 0x0adac618, 0x402a2b23, 0x22028240, 0x183e57aa, 0x200ddbc6, 0xee631803, 0x00092408, + 0x821f000e, 0x27363256, 0x22232627, 0x07170707, 0x15072737, 0x15163236, 0x33c71814, 0x3e012f07, 0x02140606, 0x0f020403, 0x1f47501f, 0x618c0247, + 0x82055f21, 0x2119861b, 0x678fd51f, 0x09bc6018, 0x63820520, 0x27230331, 0xc0013527, 0x923815a1, 0x80fec001, 0x44153892, 0x09300a4c, 0x22001100, + 0x32250000, 0x26343736, 0x16150622, 0x8d07b74b, 0x16002ee5, 0x343b0d32, 0x24491e3b, 0x19241919, 0x288b8b69, 0x13131bd5, 0x2e131919, 0x221882d6, + 0x8f432419, 0x095b438b, 0x0d000626, 0x1b001400, 0x15296c82, 0x37273723, 0x35230717, 0x22058217, 0x82333527, 0x372735fe, 0x07271533, 0xc0013727, + 0x1f3e3180, 0x3180cf3d, 0x4f3e1f3d, 0x17820b8a, 0x1d85118e, 0x4e020021, 0xd52206ec, 0x5c830700, 0x36340127, 0x35231133, 0x18568223, 0x24087e8f, + 0x15333535, 0x08038233, 0x41550121, 0x6a36352a, 0x35222e2a, 0x2a2b2e22, 0x1e80012b, 0xaa56fe37, 0x2295956b, 0xc0c00231, 0x62223102, 0x55280636, + 0xb5014000, 0x0500c001, 0x3729b282, 0x37370000, 0x33073523, 0x063c4336, 0x944e3720, 0x55ab2b28, 0xcc2b552b, 0x120c0c12, 0x954e3b0c, 0x95802417, + 0x824ba06b, 0x120c2220, 0x21954e2f, 0x97824020, 0xeb01eb37, 0x14000c00, 0x00002000, 0x17161413, 0x11352607, 0x33333634, 0x78551806, 0x36072407, + 0x82173233, 0x23233efa, 0x18f53435, 0x1a0dd111, 0x20109a11, 0x3f3f583f, 0x40344858, 0x111a1f21, 0x18800195, 0x26188239, 0x112a0111, 0x834e1e1a, + 0x473f2819, 0x117f0b27, 0x820f751a, 0x2b2f08f2, 0xd5012b00, 0x1600d501, 0x26002200, 0x36002e00, 0x35250000, 0x22232634, 0x14151506, 0x15073316, + 0x17333733, 0x32273533, 0x16160336, 0x82211115, 0x3637267e, 0x15330732, 0x21828723, 0xf9583436, 0x01470805, 0x3b3e4280, 0x18172145, 0x203c2024, + 0x21171820, 0xfe2e2b04, 0x2b2b2e56, 0xd5d5bba2, 0x0d120c0a, 0x0d89120d, 0x120c0c12, 0x1a2693ad, 0x1793261a, 0x20081821, 0x21180820, 0x44102e01, + 0x01e8fe2d, 0x10442d18, 0x4e6b9511, 0x29840520, 0x50560d20, 0x0007280a, 0x000f000b, 0x49300017, 0x2724095f, 0x07233533, 0x220a2c57, 0x82163213, + 0x230628b4, 0x27231517, 0x57230723, 0x3e2c0630, 0x1c520102, 0x121c1212, 0x2a6b6b2b, 0x38063357, 0x2c585380, 0x2a2b201f, 0x20302a51, 0x351c2c1f, + 0x1a139535, 0x831a1313, 0x20008255, 0x570a8496, 0x2b2a0837, 0x2b200b2b, 0x241bcb1f, 0x96470610, 0x000b220c, 0x05d1452a, 0x26050f4c, 0x14371406, + 0x88332306, 0x2626347a, 0x36343535, 0x35233737, 0x07231533, 0x01151616, 0x845dd66b, 0x1db52386, 0x7a85021a, 0x2017222f, 0x66113b44, 0x3f1046d6, + 0x6b6bd541, 0x30788460, 0x20261c0f, 0x0a2a2a0a, 0x17240522, 0x021f29b4, 0x25008220, 0x002a1e02, 0x5e660004, 0x00e02805, 0x00210019, 0x562f0028, + 0x26200fe0, 0x56065d44, 0x13270be0, 0x35071735, 0x82373523, 0x15260883, 0x3b7b3727, 0x2b2e252d, 0x472d0d2c, 0x140f311d, 0x0709190b, 0x61262a70, + 0x221a1a22, 0x3535ab19, 0x75753575, 0xf7563535, 0x2ca12d06, 0x1d2a3740, 0x03142218, 0x1047642e, 0x2805f856, 0x3525b7fe, 0x5a202636, 0x84068220, + 0x01c02a8e, 0x004001d5, 0x00150011, 0x569c8223, 0x232007c4, 0x2206497b, 0x4c333634, 0x3520091f, 0x34241583, 0x15023b36, 0x01251e84, 0x200c09c0, + 0x24018215, 0x2aeb090c, 0x2a0b8235, 0x090c202a, 0x2030806b, 0x82400130, 0x4b602908, 0x096b604b, 0x2020400c, 0x20210d83, 0x220b8220, 0x4f606020, + 0xd52206be, 0x0982d501, 0x0e000b25, 0x82370000, 0x077e42d7, 0x23170331, 0xd5abab40, 0x38385038, 0xea754d50, 0x832eabe0, 0x01382309, 0xb641c0aa, + 0x00132f0a, 0x00280017, 0x36342500, 0x22263435, 0xdd4f1506, 0x0e142405, 0x82171502, 0x450220a1, 0x132e0c91, 0x2c3e2c38, 0x161e1626, 0x26111611, + 0x05452b26, 0x14ed350b, 0x2b1f1832, 0x160f1f2b, 0x140c0f16, 0x3d151c0d, 0x25012525, 0x180f0c45, 0x3209a849, 0x000d0005, 0x001a0015, 0x00490022, + 0x17150100, 0x5b352707, 0x3d42070f, 0x33272307, 0x2c5b3526, 0x4b012008, 0xb15b0526, 0x35353d16, 0x32333634, 0x01363316, 0x4d103d60, 0x3f3f5817, + 0x1c273e58, 0x121c1212, 0x802dadc0, 0x02820682, 0x3e150125, 0x5b364a58, 0x582e0cc7, 0x04120453, 0x5bab012d, 0x6b2e1a24, 0x36833ec0, 0x1a13be29, + 0x6d1a1313, 0x84ea3f2b, 0x6d012a08, 0x53383e58, 0x141b4208, 0x09375526, 0x1b14262a, 0x012333d5, 0x00010041, 0x2505554e, 0x001c006b, 0xa1851200, + 0x36354508, 0x26343536, 0x06062226, 0x17161415, 0x35071735, 0x34352626, 0x477db0a8, 0x282f2739, 0x28526252, 0x55552f3c, 0x6b015342, 0x35212c3f, + 0x1f0a2c0c, 0x171d0c0d, 0x0f0c1d17, 0x553a0823, 0x370b4556, 0x02002c24, 0x95315882, 0x6b01d501, 0x11000500, 0x37370000, 0x07270727, 0x054e5025, + 0x82262221, 0x5a9a2ceb, 0x0f274c0e, 0x37261401, 0x83f02637, 0x5acc2704, 0x0f284b0e, 0xc3833f69, 0x98823f20, 0x80008023, 0x08018201, 0x0008002c, + 0x35232500, 0x17371533, 0x55013307, 0x2b9540d5, 0xd5806792, 0x952b9065, 0x15000400, 0xeb011600, 0x0300eb01, 0x14000a00, 0x68822400, 0x2115213b, + 0x36342125, 0x05161636, 0x14152135, 0x22212306, 0x34350526, 0x27272627, 0x29458233, 0x06060333, 0x40011623, 0x0382c0fe, 0x42bf3608, 0xfe425f5e, + 0x0d4101bf, 0x09ebfe09, 0x346c010d, 0x6a063c1f, 0x02246b2a, 0x2a950d13, 0x10423155, 0x15c64210, 0x0c0c0915, 0x323fab0c, 0x5732111f, 0x0da1fe57, + 0x0c815112, 0x180a4676, 0x53073e7e, 0x55250519, 0x7d7db07d, 0x05b164b0, 0x0a832320, 0x37847d20, 0x2705794f, 0x0012000a, 0x06220100, 0x21053461, + 0x7e182607, 0x00330879, 0x6a123f1a, 0x5a7b7c59, 0x32942c6a, 0x46323246, 0x821a2901, 0x6b582a10, 0x3346b72c, 0x00324633, 0x06b14107, 0x7c52ab20, + 0x001b2606, 0x002f001f, 0x26f98333, 0x21272111, 0x58252111, 0x22230b0c, 0x43353526, 0x144a0bb3, 0x31138207, 0x23153323, 0xfe560155, 0xaa012aaa, + 0x400156fe, 0xe7822b16, 0x83400921, 0x8b552004, 0x2a2a2e0b, 0x2b000180, 0x5680aafe, 0x090c8056, 0x821f8380, 0x220d8d04, 0x180900aa, 0x18088644, + 0x25110d43, 0x33352500, 0x03862715, 0x76823720, 0x4e6a0720, 0x20078306, 0xd0451833, 0x56552607, 0x56d65656, 0x8265822a, 0x82562006, 0x56d62208, + 0x200c8355, 0x846a8256, 0x25048607, 0x56560001, 0x6e880100, 0x0cc47418, 0xfcfeab2c, 0xabab1e77, 0x1501771e, 0x0883782a, 0x29827820, 0xc000952f, + 0x2b016b01, 0x00000200, 0x95073313, 0x200b82d6, 0x0ac2416b, 0x0a000227, 0x37250000, 0xbb411823, 0x55002b08, 0x7db003aa, 0xd57db07d, 0x0582aa56, + 0x84b07d21, 0x82d52043, 0x82402043, 0x37002936, 0x6b951737, 0x6b6bd56b, 0x1729848e, 0x21372707, 0x01272135, 0x26808300, 0x0401fcfe, 0x82ab0177, + 0x2a78220a, 0x226d8a78, 0x5a13000b, 0x07270561, 0x07170727, 0x18173717, 0x23082b7e, 0x1e4d4d6b, 0xa5200287, 0xbe187f84, 0x40200cf7, 0x49298a87, + 0xc0016b00, 0x05008901, 0x2a8a8300, 0xc0372701, 0x00ff1ee2, 0x85a71e77, 0x43437a06, 0x6b000122, 0x95246482, 0x0b009501, 0x2709c151, 0x37173727, + 0x77779501, 0x1600bf18, 0x80000128, 0x8001b700, 0x98835501, 0x4f170121, 0x80260500, 0x1e62621e, 0x06845501, 0x76189882, 0x21830afa, 0x01173725, + 0x82801e62, 0x4901211c, 0x00210684, 0x20778804, 0x2a798205, 0x00170011, 0x15330100, 0x6c233523, 0x2721057f, 0x210c8235, 0x0482021d, 0x2b013536, + 0x40402a6a, 0x6ac06a2a, 0x016a4040, 0xd6406a95, 0x962a6a40, 0x56201382, 0x47981482, 0x83033321, 0x84152041, 0x15352147, 0x35220b83, 0x38825501, + 0x406a2a2d, 0x6a6a2aaa, 0x2a55012a, 0x82d6fe6a, 0x82ea2045, 0x2a118214, 0x00030040, 0x01800040, 0x188001c0, 0x180c9d56, 0x21118091, 0x90828001, + 0x2b6b2a22, 0x2605a05b, 0x01ab01d5, 0x1807002b, 0x180d6afb, 0x540f2344, 0x9a260567, 0x221a1a22, 0x0584e61a, 0x822b0121, 0x82028d0a, 0x00d52676, + 0x012b0155, 0x874e87ab, 0x22078846, 0x83342622, 0x854e850b, 0x843c203d, 0x84ab204e, 0x849a200c, 0x84442005, 0x01002305, 0x4d825600, 0x4d82ab20, + 0x00001923, 0x26bc1801, 0x16142607, 0x37363233, 0x084a6d33, 0x79011638, 0x26459632, 0x4b4b3534, 0x0d472535, 0x3b5c0e2c, 0x46646446, 0x1785471e, + 0x4b6a4b2e, 0x48382332, 0x1d648e64, 0x9e000200, 0x62205082, 0x05205082, 0x31052b42, 0x37173727, 0x07173703, 0x62010727, 0x441e6262, 0x0584a644, + 0x848d0121, 0xc8fe2106, 0x36840684, 0x62014025, 0x8400c001, 0x83252036, 0x37372330, 0x07822707, 0x44000123, 0x8324841e, 0x847c2005, 0x84c4200b, + 0x0d6e4305, 0x2a821320, 0x2311272b, 0xab550711, 0x2a771fab, 0x0a754378, 0x6b232882, 0x83014000, 0x000a2ae5, 0x07171300, 0x11333533, 0x2f928223, + 0xc44d1eeb, 0x1e4def2b, 0x1e400180, 0x00ffd64d, 0x54840982, 0x95014022, 0x2b82c082, 0x81822520, 0x33112331, 0x37273315, 0x1e809501, 0xc42bef4d, + 0x82c01e4d, 0x00012408, 0x8d1e4dd6, 0x82012080, 0x1117262b, 0x01371133, 0x24818bab, 0xfcfe0401, 0x2adf8277, 0x01800080, 0x00800189, 0x82090003, + 0x837f8283, 0x0717305b, 0x012b2b80, 0x80801e09, 0x8001621e, 0x841e00ff, 0x202d8209, 0x06eb4677, 0x01202d84, 0x27202d82, 0x3725de83, 0x2b2b5501, + 0x202d88de, 0x820984e2, 0x00c02685, 0x012b0195, 0x2a37826b, 0x27150100, 0x016b2b01, 0x826bd66b, 0x82d52017, 0x85402017, 0x35372517, 0x956bd517, + 0x00281584, 0xf9002d00, 0x0500d301, 0x07218782, 0x27b58217, 0x26adadf9, 0xad01d3d3, 0x36820684, 0x2b008524, 0xb8528001, 0x17373f05, 0x17072737, + 0xd5d52685, 0x2550af26, 0xb025d5d5, 0x6b000400, 0x95011500, 0x0700e101, 0x51530f00, 0x18002005, 0x270ed75e, 0x15151637, 0x37343521, 0x3634b482, + 0x17371732, 0x15213501, 0x26220614, 0x0c123701, 0x740c120c, 0xad350584, 0x3dd6fe3d, 0x2031122d, 0x12312044, 0x2a01e6fe, 0x01577c57, 0xe1691840, + 0x120d3608, 0x164b2d57, 0x2d2d4b16, 0x10103111, 0xdbfe1131, 0x583e5555, 0x20b58258, 0x209e8240, 0x7daf18c0, 0x7bae1808, 0x47042063, 0x07260862, + 0x15001100, 0x29581900, 0x05105909, 0x26222008, 0x33053634, 0x35152315, 0x22c41533, 0x19221a1a, 0x6464472a, 0x64644647, 0x2a2a1c01, 0x831ad52a, + 0x65bc2b13, 0x8e64658c, 0x556b4064, 0x00762a2a, 0x00172c0e, 0x36322500, 0x07273435, 0x18142716, 0x2311a7c4, 0x7230ef25, 0x39300382, 0xb0536546, + 0x7db07d7d, 0x39466555, 0xab25ef30, 0x65210483, 0x0507468f, 0x2009a453, 0x82a38208, 0x822520a1, 0x23262b4f, 0x13070622, 0x27373632, 0x09731506, + 0x1887200a, 0x202a60f8, 0x0adf5204, 0x65000b21, 0x072553f1, 0x0118ea18, 0x1cd35f2b, 0x2008396b, 0x240982eb, 0x0021001b, 0x08e41800, 0x50332013, + 0x07210613, 0x059a4607, 0x18d6fe21, 0x32074d5f, 0x12191912, 0x2baa2b15, 0x17447f1f, 0xea6b682d, 0x535501ea, 0x192105c4, 0x20228312, 0x2000822b, + 0x8e1a84ac, 0x9d272068, 0x27032268, 0x24698337, 0x07170717, 0x0b787a27, 0xb9236e87, 0x82343417, 0x34162402, 0x94341634, 0xd5fe2174, 0x05842185, + 0x8308e857, 0x000724e4, 0x8223001f, 0x2315257d, 0x21350535, 0x1014cf18, 0x1f82ea88, 0x962b0124, 0xeb910001, 0xd5d61525, 0x936a2a2a, 0x2b9522ea, + 0x0cb05a2b, 0xe2621b20, 0x4f37200b, 0x2122065e, 0x85502622, 0x01172b05, 0x4837117f, 0x37481d1d, 0x117a3f11, 0x2b802d0a, 0x06304795, 0x30064343, + 0x1ac62547, 0x09318418, 0x6e505a85, 0x00042905, 0x37000012, 0x27072721, 0x24086955, 0x36341107, 0x05675533, 0x1911f62e, 0xd5fe1119, 0xd5111955, + 0xa0406080, 0x180b1656, 0x220da661, 0x50260017, 0x524d090e, 0x56078707, 0x222d087e, 0x36372727, 0x1a880133, 0x131a1313, 0x34058457, 0x12121c59, + 0x3501121c, 0x111a1a11, 0x0e16c2fe, 0x140e7373, 0x0a3a62e0, 0x12221d83, 0xc818ce1c, 0x15200c40, 0x2206a76e, 0x4f1d0007, 0x342405fb, 0x15062226, + 0x4b054d68, 0x35260a2c, 0x16323634, 0x1a832715, 0x21261d82, 0x26221501, 0x5a82c001, 0x0d095525, 0x836a090d, 0x2c1f2c04, 0x3828351f, 0x01eafe15, + 0x18070296, 0x2a1515a5, 0x06283860, 0x01401d13, 0x4101c196, 0x22280afc, 0x28002500, 0x00003600, 0x21077e7c, 0x6d822622, 0x2905a455, 0x15161714, + 0x16070714, 0xeb821716, 0x16173225, 0x82371527, 0x27073102, 0x17372737, 0x07173335, 0x35230717, 0x0c09ab01, 0x0938df18, 0x2f07023b, 0x2f265314, + 0x04030807, 0x14140324, 0x3b0f5a14, 0x0a310f3b, 0x3d2e2e3d, 0x3adf180a, 0x0304230e, 0xdf18050a, 0xb12c073c, 0x28701428, 0x3c0f7914, 0x51310f3c, + 0x51232c83, 0x52000200, 0x222207ab, 0x9da52900, 0x35233525, 0x9a173533, 0x55552290, 0x24849a6b, 0x40564060, 0x0892436b, 0x0700c02d, 0x32000f00, + 0x34010000, 0x70352326, 0x078306d5, 0xb2420720, 0x1a274106, 0x2640012b, 0x2a3f2c1a, 0x70503e57, 0x171d4115, 0x1a00012c, 0x2c3f2b26, 0x702b573e, + 0xcf184b50, 0x01220ac3, 0x19412229, 0x268f880b, 0x000c00d5, 0x82360015, 0x074a538f, 0x33152325, 0x4f232335, 0x152605b8, 0x27260707, 0x77183637, + 0x152307f0, 0x85171616, 0x36322202, 0x822f8235, 0x01670817, 0x121219ab, 0x2b801519, 0x09090c2a, 0x5235480c, 0x0208352e, 0x080b0210, 0x030c0959, + 0x4719161b, 0x2e56262c, 0x070a0d09, 0x95010c4e, 0x19191116, 0x6a6a1611, 0x0d0d0816, 0x2f36de08, 0x0b083651, 0x0d0a074f, 0x26562e09, 0x1619472c, + 0x090c031b, 0x020b0859, 0x0200030f, 0x43000000, 0xc0010002, 0x2a001f00, 0x60250000, 0x262e0606, 0x35352627, 0x15072226, 0x07060714, 0x80822206, + 0x36373426, 0x25163233, 0x2d051b74, 0x07173717, 0x0606fa01, 0x06120635, 0xda181d1c, 0xfe291014, 0x4b8020bd, 0x95158060, 0x10da189c, 0x4bc62319, + 0x22822080, 0x21419620, 0x82c02008, 0x83262009, 0x33012483, 0x41172315, 0x032021a5, 0x01248a82, 0x162b2b95, 0x2517a241, 0xc0012b18, 0x9b417695, + 0x0b012519, 0x04009595, 0x0e3c7c18, 0x00001925, 0x52233501, 0x232106af, 0x088a4415, 0x35262228, 0x80013713, 0xac18152b, 0x7c18245e, 0xe5590b90, + 0x82172006, 0x62132055, 0x4d820a49, 0x2a152108, 0x11952a2a, 0xff111a1a, 0x011a1100, 0x6a6aeb7f, 0x012b2b56, 0xfe111940, 0x191911aa, 0x80000111, + 0x97189e82, 0x9e891206, 0x210e4e5b, 0xd9182b6b, 0x538b254e, 0x78629e82, 0x259e8807, 0x36341107, 0x9e830133, 0x7645c020, 0x2b012308, 0x9e835555, + 0x0c50df18, 0x55000237, 0xab011500, 0x0e00eb01, 0x00001d00, 0x07173525, 0x35262235, 0x53041934, 0x00032445, 0x823d003d, 0x82ab205d, 0x00273b5d, + 0x0100002d, 0x15161607, 0x36270714, 0x27263435, 0x37073507, 0x06270701, 0xb1483507, 0x37172506, 0x26372315, 0x37217d83, 0x36238206, 0x33ab0137, + 0x201a1e15, 0x2f10160f, 0x4f011bee, 0x1818321b, 0x83ac0908, 0x8380200e, 0x06662518, 0x16191f0a, 0x14382482, 0x2b2f1d47, 0x161d1e1f, 0x802f1034, + 0xb0fe1b1e, 0x060e321b, 0xac05032c, 0x33201286, 0x02252085, 0x050f2006, 0x0be14800, 0x1700132c, 0x00002700, 0x15333537, 0x98820737, 0x9a868a83, + 0x13820320, 0x36342729, 0x06061537, 0x85161415, 0x2aeb2e99, 0x483232ab, 0x15322338, 0x2a553010, 0x300986d5, 0xeb323280, 0x33c08080, 0x5c3b4632, + 0x470d2c0e, 0x24868425, 0x2b2beafe, 0x21108b6b, 0x81183233, 0x062a0a9e, 0x1a000a00, 0x07250000, 0x67823327, 0x18111721, 0x25127f65, 0x40555555, + 0x7818562a, 0xeb250ad7, 0x6a6a5656, 0xded41880, 0x00043212, 0x0115002b, 0x00eb0195, 0x001c0014, 0x00290021, 0x9a8a1800, 0x27262b08, 0x15231133, + 0x34352726, 0x8a183336, 0x01760c2c, 0x233c0806, 0x19116b01, 0x032d1119, 0x19d64111, 0x6a111911, 0x712a8961, 0x40261a4f, 0x3e2b573e, 0x19ea012c, + 0x1195fe11, 0x012a2b19, 0x030b8015, 0xeb1a119d, 0x714f6289, 0x961a2680, 0x3f2c3e58, 0x4a0c4b41, 0x0628792d, 0x40000000, 0xc0010002, 0x0f115218, + 0x28115541, 0x15333513, 0x23153337, 0x068d5205, 0xaa550128, 0x12120eb5, 0x0483c00e, 0x152bf527, 0x6bfe2b2b, 0x2801822b, 0xd6fe2a01, 0x0e125501, + 0x2f1884fe, 0x120e4001, 0xd6d6d5fe, 0xd62b80ab, 0x80802bd6, 0x270c0054, 0x25000015, 0x23350735, 0x0b086618, 0x24057e43, 0xabab5580, 0x087e4380, + 0x44abd526, 0xbb45ab44, 0x3d0df748, 0x01150015, 0x00eb01eb, 0x002f000a, 0x004d0037, 0x22353700, 0x27353526, 0x16141506, 0xd2693337, 0x35262205, + 0x08105a34, 0x06141523, 0x2a698223, 0x15151632, 0x36173233, 0x56373435, 0xb04805f3, 0xd5220816, 0x04671911, 0x012bfe56, 0x7d59587d, 0x211f597d, + 0x0c2b111a, 0x09802b09, 0x0a1f150d, 0x1e152f2c, 0xc0485915, 0x2a412c0b, 0x66161119, 0x61411610, 0x830e07b7, 0x7d583d30, 0x1a11360a, 0x2a0d092a, + 0x1d40090d, 0xb20e442f, 0x16160f0a, 0x090d0a0f, 0x0c0c0955, 0x0d280482, 0x2020160a, 0x00030016, 0x07b79118, 0x17000f24, 0xc6821e00, 0x22230622, + 0x0a444218, 0x21071422, 0x37052358, 0x35211525, 0x98163233, 0x121b1c11, 0x1c121213, 0x80141319, 0xaa80aa01, 0xfe380482, 0x3223c0eb, 0x111213fe, + 0x14121a1d, 0x1a1b1213, 0x2b2b2a3c, 0x33802a6a, 0x202f5d82, 0xe0016b00, 0x1300a001, 0x24001b00, 0x82130000, 0x8326205d, 0x3736225e, 0x324d8236, + 0x14151617, 0x05370706, 0x23152707, 0x25072535, 0x82161737, 0x0a9c2811, 0x07221112, 0x860f1506, 0x0f8b3107, 0x610e9501, 0x0f3001aa, 0xb62df8fe, + 0x26012217, 0x0f3f1b89, 0x22110e0e, 0x28922830, 0x04602222, 0x42795f28, 0x11192f08, 0x15000200, 0xeb019500, 0x55006b01, 0x322205ae, 0xbe831516, + 0x210ecb6f, 0xc96f2afe, 0xd680220b, 0x09c66f96, 0x40002b39, 0xc001ee01, 0x20001400, 0x16250000, 0x27070706, 0x35262223, 0x83153335, 0x371729b5, + 0x14251636, 0x15333316, 0x32081485, 0x0a07e701, 0x95494f0c, 0x4b80261a, 0x4805160b, 0xfe190c18, 0x801a2674, 0x2a3e2c80, 0x061a0c90, 0x1a269524, + 0x0a0e80ab, 0x08050b95, 0x2b261a65, 0x49c02c3f, 0xd52006a4, 0x13226382, 0x63821f00, 0x20056057, 0x21658935, 0x628c1515, 0x130db525, 0x83600d13, + 0x116b2462, 0x84d6fe19, 0x2b3f255d, 0x121c1280, 0x1a235c84, 0x8c809511, 0x82ad2059, 0x000b2559, 0x13000021, 0x1625a88b, 0x35232306, 0x20648a37, + 0x2ecf8207, 0x551a266b, 0x2b3f2c55, 0x13033f01, 0x8215600f, 0x82802047, 0x1e2a2463, 0x4901130c, 0xc0260569, 0x170fa6fe, 0xc4835540, 0x0f236782, + 0x66000300, 0xd8260587, 0x27001b00, 0xbd823000, 0x27071722, 0x27285482, 0x35263427, 0x33373634, 0x26061160, 0x27061537, 0x84151717, 0x17332919, + 0x02331616, 0x36362626, 0x55080882, 0x7b5a0106, 0x16925120, 0x011d0425, 0x01011018, 0x0d110105, 0x30343023, 0x9663163e, 0x2a063e26, 0x24042a2a, + 0x061c3f18, 0x0e0e2314, 0x60c01407, 0x161e4020, 0x0106017e, 0x01031c11, 0x0a251b0a, 0x5722082e, 0x26342b55, 0x1f17cad1, 0x23141301, 0x0b0a071c, + 0x97821c23, 0x3500552c, 0xd601ab01, 0x22001600, 0x97822a00, 0x35209684, 0x2005954b, 0x26788217, 0x27221533, 0x41073315, 0x36200a12, 0x34058453, + 0x1fab0106, 0x261a6c4b, 0x1301131d, 0x39111e10, 0x4a383e1a, 0x066441bf, 0x1a1a2f35, 0x541a1a22, 0x1a264b1f, 0x101d137b, 0x2f181321, 0x41154f2f, + 0x1520056d, 0x22221a83, 0x7950001a, 0x00032609, 0x000b0007, 0x0d536a28, 0x06223722, 0x21199170, 0xf0821501, 0xea2a2a24, 0x8d701911, 0x1812260f, + 0x2a2a4b01, 0x20028460, 0x206982a0, 0x098d7055, 0x19191223, 0x4df08212, 0xd52c0505, 0x06000200, 0x00001d00, 0x05071713, 0x12806718, 0xfd4e3320, + 0x95c03f05, 0xfe000195, 0x12800180, 0xfe111a19, 0x191a1180, 0x0f46a212, 0x460f5555, 0x55562b01, 0x7471012b, 0x05024908, 0x85191221, 0x2466841c, + 0x01eb0140, 0x206684c0, 0x21da821a, 0x66873507, 0x06140323, 0xe9f81823, 0x2163880d, 0xf8181901, 0x152308e6, 0x8bd6ab55, 0x2b2b275e, 0x00011218, + 0x82181912, 0x12212d85, 0x82528919, 0x00ff2165, 0x1031f918, 0x52180120, 0x1420085d, 0x3229a582, 0x07151516, 0x27352315, 0x008a1835, 0x56013f09, + 0x6a4b1a10, 0x01101a4b, 0x012a562a, 0x75101b6b, 0x4b40404b, 0x551b1075, 0x04005555, 0x7b6e5500, 0x000f2508, 0x002b001d, 0x2108d36c, 0x28422206, + 0x23132e05, 0x36372335, 0x32333336, 0x23171716, 0x053a6805, 0x152b0c82, 0x01152315, 0x19192472, 0x84d91924, 0x40b53b05, 0x18043640, 0x180d020d, + 0xfe403604, 0x111a20f5, 0x201a1140, 0x24198001, 0x20831818, 0xfe330582, 0x0ca28092, 0xa20c1212, 0x1175a080, 0x75111a1a, 0x680300a0, 0xa12206bf, + 0x8b740900, 0x36372a05, 0x26071732, 0x07062226, 0x22098317, 0x82203627, 0x2220080e, 0xaf3e6b07, 0x3f122a3d, 0x2b123f34, 0x401b4a1b, 0x130162eb, + 0xe0502b61, 0x3d3deb50, 0x1a1a122b, 0x14821582, 0x2b616124, 0x52824f4f, 0x2405124b, 0x000b00eb, 0x6bd28313, 0x27240be6, 0x34353315, 0xf44b5d82, + 0x22212207, 0x052e4326, 0x2005374f, 0x06636315, 0x27845725, 0x4bc22736, 0x1a26072f, 0x583f1511, 0x6963ab3f, 0x2bd52805, 0x27271b2b, 0x18111946, + 0x2707c781, 0x3f3f2c2b, 0x05002b2c, 0xaa24c986, 0x0c000600, 0x1b327882, 0x00002a00, 0x07173637, 0x33070606, 0x16372726, 0x05833717, 0x21171623, + 0x2a148236, 0x25070626, 0x15031532, 0x82230606, 0x34560881, 0x6b363737, 0x151c5c40, 0x0bd60f32, 0x18200c0f, 0x0b31272b, 0xfe15461d, 0x4f9b3b2a, + 0x2d773d19, 0x340b1301, 0x120f1803, 0x036f0519, 0x3d0340eb, 0x0b0f1903, 0x18103e0a, 0x3c14272a, 0x3b152c0b, 0x08390e2f, 0x0a802d29, 0x0e01edfe, + 0x0b121914, 0x0008f80a, 0x2f730002, 0x82eb2005, 0x00232898, 0x27151300, 0x18333636, 0x2008d0ce, 0x05074127, 0x27070124, 0x04412306, 0x37240805, + 0x27be3727, 0x2c293b05, 0x1a11153f, 0x362774dd, 0x1a020127, 0xff060818, 0x171a1100, 0x80011a2c, 0x3628271a, 0x1933e982, 0x2bdcb211, 0xfe27271b, + 0x02181a94, 0x19d61119, 0x421a2b0c, 0xd5220649, 0xfd82d501, 0x12000a31, 0x00002b00, 0x35071701, 0x17333523, 0x18152335, 0x20084f74, 0x07866a33, + 0x3521f482, 0x22198233, 0x83153727, 0x01280893, 0xab40406b, 0x495515ab, 0x120c0c12, 0xaa2ad60d, 0x2b263426, 0x56961a11, 0x11eb4040, 0x40d5011a, + 0xd62b2b40, 0x0d804040, 0x332a1f83, 0x26261a2a, 0x4011191a, 0x17822a40, 0x00111a23, 0x21e18203, 0x995f0115, 0x00102905, 0x3700001d, 0x27232733, + 0x6782da84, 0x37363426, 0x27230527, 0x1438fb84, 0x33270706, 0x1f2b4a95, 0x1ca00165, 0x5843363b, 0x3c10167d, 0x9a4a5601, 0x63310a85, 0xbb2aeb1f, + 0x3c1b60fe, 0x1c587d26, 0x9f3b1746, 0x2008859a, 0x65d41864, 0x0002282e, 0x014000d5, 0x82c0012b, 0x000b289a, 0x11331300, 0x59341423, 0xd5310507, + 0x24195656, 0x01241919, 0x6700ffc0, 0x24181824, 0x245b8219, 0x012b003a, 0x212d82ba, 0x476e000f, 0x27072105, 0x2a06c643, 0x17372737, 0x35270717, + 0x82331533, 0x322f0803, 0xed9a1516, 0x0b5f1b33, 0x47014b6a, 0x0ae7441b, 0x2a562acb, 0x66011b10, 0x5f1b32ee, 0x4b40400a, 0x48030575, 0x0b9b451b, + 0x555535cb, 0x6a101b55, 0x11240a62, 0x22001500, 0x21052244, 0x50821411, 0x45272321, 0x03280623, 0x27230121, 0x27070137, 0x29065753, 0x12c00137, + 0xf5230819, 0x0c45422b, 0xde350805, 0x00ff1f01, 0x011b2b1f, 0xfe2a1b9f, 0x131a11b6, 0x1895010e, 0x0d00ff12, 0x2af5230b, 0x56560f47, 0xd6fe470f, + 0x1c490001, 0x2b1b60fe, 0x0001111a, 0x0003170f, 0x246d8204, 0x01ea0155, 0x2c0982da, 0x001a0016, 0x37000021, 0x07173236, 0x21688303, 0x7f820622, + 0x27373622, 0x33080682, 0x07053736, 0x07371627, 0x36270726, 0x4a1bc016, 0x1bd5401b, 0x971b6a01, 0x2a123e19, 0x31303727, 0x30272b28, 0x4c142901, + 0x542a7c39, 0x9f51357a, 0x401b1b95, 0xfe3b1f82, 0x1a971b96, 0x27012a12, 0x27142f0f, 0x9317272b, 0x2e0f4b15, 0x3607562b, 0x52002e11, 0xc026050c, + 0x0800c001, 0xf0822500, 0x15330728, 0x15333523, 0x9d6f0537, 0xae01291b, 0x15805987, 0x30eefe8a, 0x14cbec18, 0x1686b126, 0xa6865b80, 0x19d1ec18, + 0x08075554, 0x0f000923, 0x33250000, 0x11070606, 0x23171616, 0x26261127, 0x16013634, 0x4c6c07bf, 0xbf076c4c, 0x6f6f512b, 0x210882ea, 0x1082aa01, + 0x56febf26, 0x7aa67a08, 0x220a764f, 0x820a0004, 0x8217203f, 0x36362d41, 0x14262337, 0x06111716, 0x2e331537, 0x0808785d, 0x57361522, 0x56c09407, + 0x94693f40, 0xb0a75307, 0x7db07d7d, 0x36570757, 0x08608256, 0x08085201, 0x33533a94, 0x28077357, 0x01550055, 0x00ab01ab, 0x21518207, 0x14190019, + 0x062008ac, 0x82068542, 0x32333c96, 0x23061416, 0x563bde22, 0x08563c3c, 0x18182419, 0x1d28d524, 0x1c28281c, 0x8319011d, 0x703b3713, 0x24191924, + 0x28385c19, 0x00273a27, 0x002b0001, 0x01d50176, 0xa0820095, 0x82070121, 0x272622dd, 0x05b07907, 0x22232622, 0x08051d60, 0xd5013722, 0x2b072541, + 0x55561906, 0x55a02080, 0x49553b3d, 0x5a481e3b, 0x013d4766, 0x483b496c, 0x56612e33, 0x56271782, 0x1e344546, 0x88444f40, 0x828a2052, 0x055e69a5, + 0x27071723, 0x2b38824b, 0x55b51e97, 0x56a02076, 0x56cc1eaa, 0x0ab1db18, 0x33001b24, 0xc3423f00, 0x14152605, 0x27272206, 0x45048607, 0x332607c2, + 0x33161715, 0x4b613732, 0x35352106, 0x37260c83, 0x37321617, 0x64452737, 0x16172105, 0x38081b82, 0x261a8001, 0x2e0c2219, 0x0c230c2e, 0x220c2e2d, + 0x6b1a2619, 0x1e164d2a, 0x090c1416, 0x0c09aafe, 0x161e1713, 0x3e151717, 0x114b1715, 0x2424071a, 0x40011907, 0x11211a26, 0x83328319, 0x11193003, + 0x2b261a21, 0x0d16952b, 0x0c0c0962, 0x830d6209, 0x17152f2e, 0x0b111abe, 0x0b3f3f0b, 0x0019120b, 0x314a000c, 0x82c02005, 0x180720be, 0x220cef48, + 0x822f002b, 0x003925c6, 0x23152500, 0x841df818, 0x09894318, 0x14000a26, 0x24001c00, 0x32239a82, 0x82151616, 0x2734239e, 0x0a842236, 0x34352123, + 0x07e46a36, 0x18481620, 0x55013506, 0x8038421c, 0x38b9072a, 0xd5fe3742, 0x26347838, 0x85253426, 0x26290583, 0x172410eb, 0x1e2c3535, 0x23078401, + 0x263a2417, 0x05841684, 0x05002308, 0x55000000, 0xab010002, 0x1b000b00, 0x38002a00, 0x00004200, 0x15233501, 0x15331523, 0x35333533, 0xd6633205, + 0x22232d05, 0x14150606, 0x22171616, 0x1515030e, 0x2e228282, 0x97823703, 0x07061425, 0x8235023e, 0x82172050, 0x8230820c, 0xd5012b09, 0x2a2b2b2a, + 0x17abfe2b, 0x02821727, 0x05831820, 0x2d11183e, 0x0118272e, 0x2e271855, 0x110f4f2c, 0x22150f11, 0x41221313, 0x152b110e, 0x2b400121, 0x2a222f82, + 0x2c88402b, 0x2d080882, 0x140e0715, 0x4040111c, 0x0e141c11, 0x2c11bf07, 0x112b1818, 0x15251703, 0xce182416, 0x4015220d, 0x14191040, 0x40000a00, + 0xc0014000, 0x5075d501, 0x001b290c, 0x0023001f, 0x2500002c, 0x6518c682, 0x0f830f46, 0x17862720, 0x372e0b83, 0x11211533, 0x17373533, 0x2a2a9501, + 0x0382562a, 0x07850283, 0xfe80d52e, 0x40408080, 0x552b2bc0, 0x00012a2a, 0x09821e82, 0xb7180c84, 0xaa27088f, 0x2a2b01d5, 0x18004040, 0x18093d5b, + 0x536f7f52, 0x778a07d1, 0x16323624, 0x21422317, 0x9f881810, 0x4adb260f, 0x0dda0d3b, 0x90aa1822, 0x29d52416, 0x18692121, 0x211890aa, 0xd4490002, + 0x00cb2d05, 0x001a0013, 0x15172500, 0x35373521, 0x0ddf1c19, 0x3526223d, 0x01061433, 0xaafe2b80, 0x122d332b, 0x332d121c, 0x56191280, 0x152bab1a, + 0x196a2b15, 0x240b661c, 0x111218ea, 0x08284a19, 0x0700cb23, 0x06bb5b00, 0x20055359, 0x205d9237, 0x255d8406, 0x4e2e5501, 0x608ad52e, 0x1a226f2b, + 0x29809556, 0x80293737, 0x22669116, 0x86111119, 0x01c02165, 0x1922b983, 0xbb822700, 0x36362728, 0x32373337, 0x734a3336, 0x16162206, 0x255d8515, + 0x17161603, 0xd8842707, 0x3727372d, 0x03bf8001, 0x0601020a, 0x84020601, 0x246e36cb, 0x18845619, 0x2b1b36cb, 0x112bdbfe, 0xc9c71b3c, 0x03010501, + 0x3b1d1902, 0x2ed48208, 0x193a0112, 0x2b1b39d0, 0x296b2b15, 0x461c3b20, 0xcb26085b, 0x19000500, 0x7d832000, 0xc7842420, 0x91153721, 0x261733e2, + 0x16372726, 0x06062517, 0x37362307, 0x19241201, 0xe98a5655, 0x2c022a34, 0x05531e1d, 0x2d1dcdfe, 0x53052b02, 0x1211192b, 0xf28f6ad2, 0x5024272c, + 0x67401e15, 0x24501589, 0x60414067, 0x0009240a, 0x4324001d, 0x332605e6, 0x35331507, 0x7f911723, 0x84071521, 0x0106289a, 0x3b3b6a35, 0x41863b6a, + 0x01270fc6, 0x4926262f, 0x8f3b2626, 0x41322073, 0xfc6d05cd, 0x00082609, 0x001a0011, 0x06294623, 0x37233008, 0x27133507, 0x06141533, 0x27352323, + 0x23153707, 0x023d2622, 0x33333634, 0x23172715, 0x1a119501, 0x5656166b, 0x111a6b16, 0x56166a80, 0x821a1180, 0x210e8208, 0x0785c001, 0x83d5fe21, + 0x406b2113, 0xaa202185, 0xe1752d84, 0x000d260a, 0x002f001b, 0x05245f00, 0x84162321, 0x37162965, 0x14150622, 0x35263317, 0x26206583, 0x2f0fcc71, + 0x17333733, 0x3f2c0001, 0x26042d02, 0x3421551a, 0x77200988, 0x0dd65618, 0x2c3f952a, 0x070e0c09, 0xd62b261a, 0x40200988, 0x2705c057, 0x0001111a, + 0x2a2a1a11, 0x0a464918, 0x2065bc45, 0xb6491807, 0x00072c08, 0x0017000f, 0x0029001f, 0x7d3e0031, 0x891809f3, 0x062509e0, 0x36321614, 0x260f8734, + 0x26343517, 0x46072223, 0x26250556, 0x15150622, 0x05a45225, 0x33363433, 0x01361732, 0x1a1a2271, 0x3e0c1a22, 0x2c3e2c2c, 0x370b8afa, 0x1a2447e0, + 0x47200b26, 0x2b014748, 0x2afe602b, 0x312f2b60, 0x19750131, 0x5c262283, 0x2b2b3e2c, 0x0b8a493e, 0x0a1aa127, 0x0d0d0c1c, 0x2d06821a, 0x601a0a1c, + 0x3a3a1f27, 0x1616271f, 0x84670200, 0x21b68308, 0x7a873600, 0xe34e2220, 0x6cca3605, 0xceaafe75, 0x46323246, 0x262fd532, 0x5a262b2b, 0x33334632, + 0x089c4e46, 0x0700ab29, 0x1b001300, 0x86240000, 0x33272138, 0x23052454, 0x33353335, 0x20080f47, 0x2345830a, 0x2b404015, 0xe3200282, 0x85204c8a, + 0x40211083, 0x2052856b, 0x27898804, 0x00110009, 0x00210019, 0x162b8d83, 0x35211515, 0x32363634, 0x82061416, 0x22162293, 0x20108406, 0x06b77626, + 0x4c40e027, 0x3faafe3f, 0x34548449, 0x01565881, 0x1a266f04, 0xeb1a261a, 0x401a2a12, 0xd22a1a40, 0x2b198333, 0x170c21b6, 0x1ae10c17, 0x26191926, + 0x8026f184, 0x95019501, 0x67820500, 0x37010028, 0x07352311, 0xb7891507, 0x60350135, 0x5660362a, 0x56562a56, 0xfe177e01, 0x020be2eb, 0x82552b55, + 0x08f05d02, 0x2005bb48, 0x20f7830b, 0x0aa65a25, 0x100a6c18, 0x2766b118, 0x20090862, 0x06ad5217, 0x34353629, 0x14152726, 0x56232306, 0x07200c2d, + 0x4a095956, 0x330808fa, 0x303b2d7e, 0x0d2a111a, 0x09802a09, 0x881e150c, 0x05661a11, 0x7db00457, 0x8d7db07d, 0x56354330, 0x19110913, 0x2b0c092b, + 0x5440090c, 0x15111a29, 0x41121466, 0x0a1b5518, 0x078e5018, 0x0c000639, 0x17010000, 0x07352315, 0x37171727, 0x01270715, 0xc02beb00, 0x829556eb, + 0xc0013d00, 0x6994ab80, 0x52525980, 0x00515156, 0x00400001, 0x01c0012c, 0x002600d5, 0x16322500, 0x222fa282, 0x37343526, 0x22230627, 0x33363426, + 0x82371732, 0x4b36200e, 0x273b0545, 0x07141607, 0x80013617, 0x3225241a, 0x13970125, 0x26261a19, 0x9613191a, 0x82342602, 0x14183108, 0x98020296, + 0x1925a912, 0x1a25251a, 0x1158040a, 0x11231682, 0x82050a57, 0x26342825, 0x0a0a5812, 0x1810580a, 0x33085461, 0x000b00f2, 0x37000020, 0x34353632, + 0x06070627, 0x13161415, 0x08915318, 0x0d823720, 0x19833320, 0x27263308, 0x0c3b2bfa, 0x283c441f, 0x644b4043, 0x2c45648e, 0x08292021, 0x2b3b6b04, + 0x0e292a2c, 0x271c350d, 0x95348701, 0x64644654, 0x08526c46, 0x222d2e21, 0x72713414, 0x000e240b, 0x821e0016, 0x822e20db, 0x072225dd, 0x27263126, + 0x0623d383, 0x47260706, 0x6a710fb7, 0x16003010, 0x0a010b14, 0x1e22241c, 0x13011302, 0x19658c5d, 0x2608db24, 0x131a136a, 0x84831a13, 0x0ba02a05, + 0x130b010c, 0x02150113, 0xf88f180b, 0x1830200c, 0x2009cc49, 0x0ac64813, 0x20075044, 0x09c36423, 0x07e54018, 0x0723808f, 0x18231533, 0x8b0b7b5a, + 0x807e2275, 0x7f5a1880, 0x216d8b0c, 0x6f8a1560, 0x13000b28, 0x23001b00, 0xff822b00, 0x1637322a, 0x22230617, 0x16373627, 0x1329fca3, 0x22231d03, + 0x13090c1d, 0x2afa962f, 0x03160bab, 0x09101212, 0x8365560b, 0x1b012621, 0x7d7db07d, 0x44f896b0, 0x29200708, 0x1627f883, 0x22262317, 0x6f362307, + 0x02410798, 0x4adb2117, 0x07cced18, 0x83961a20, 0x2129d526, 0x57212a2a, 0xc84980a2, 0x3337250a, 0x26220606, 0x95267c9f, 0x483a0dd6, 0x7897183a, + 0x2f2f2623, 0x3f76985a, 0x002b0002, 0x01d5012b, 0x001700ab, 0x13000021, 0x33333637, 0x15151632, 0x27070714, 0x37262726, 0x2105ac57, 0x6a582534, + 0x34370805, 0x392e3336, 0x15ad180d, 0x09890d1d, 0x0103070c, 0x19117614, 0x092aaa01, 0x01090d0d, 0x1d158313, 0x0d12a715, 0x0e0c0a88, 0x1a630707, + 0x9f0a1711, 0xc0090ceb, 0x83000d09, 0x82552065, 0x85d52065, 0x07253165, 0x22232306, 0x34353526, 0x16173737, 0x07071617, 0x05217385, 0x23078535, + 0xd2012306, 0x14216683, 0x21668a1e, 0x668456fe, 0x1583ed24, 0x658c141e, 0x88a00921, 0x050d4c65, 0x0500c024, 0x4e181500, 0x54530d5b, 0x5c4e1805, + 0x1912250b, 0xd6fe1219, 0x95260583, 0x4ca21fc0, 0x0e87c01e, 0x122a0123, 0x0ab65019, 0x13000f23, 0x08155d00, 0x28069451, 0x11210533, 0x11950121, + 0x09e1791a, 0x01d6fe25, 0x89c0012a, 0x1a11240f, 0x5bd6fe2b, 0x0f200cee, 0x43114843, 0x25430b34, 0x11f6670c, 0x42078176, 0x36200780, 0x8b069b46, + 0x58a92542, 0x3f583f3f, 0x1320488c, 0x3f231082, 0x4e010058, 0x230806ff, 0x000900d5, 0x37072500, 0x17373727, 0x01170717, 0x74238400, 0x993c3c99, + 0x50902374, 0x8d0d6596, 0x96650d8d, 0x23086c70, 0x000500d5, 0x2525b482, 0x27372717, 0x202d8227, 0x2a378527, 0x15500001, 0xd5245e47, 0x85842374, + 0x30b7293d, 0x56083e5b, 0x50966543, 0x36824385, 0x00000126, 0x0002ff01, 0x13266d82, 0x43001f00, 0x0f824d00, 0x16322008, 0x26262317, 0x17270727, + 0x15232334, 0x36373233, 0x17322735, 0x14151516, 0x23230607, 0x62160735, 0x23250570, 0x33352622, 0x555d1814, 0x18342008, 0x20079282, 0x081f8332, + 0x0717373d, 0x33272622, 0x00011616, 0x20089364, 0x1d354505, 0x142f6f51, 0x020a2413, 0x0513352f, 0x31231615, 0x06051c31, 0x18190f05, 0x0c0f1b1e, + 0x10101f1c, 0x1c191a1d, 0x1816100f, 0x181d481d, 0x08079ece, 0x87000235, 0x19603b63, 0x39fb511c, 0x1107227b, 0x160c2f59, 0x16152608, 0x1c0b53aa, + 0x040c0a0a, 0x0b17180c, 0x3216360e, 0x0d0f1117, 0xd7191718, 0x8801511c, 0x786a3563, 0x0b220a6d, 0xd0821300, 0x23112325, 0x83152335, 0x26212105, + 0x39068d41, 0x2b80c001, 0x01802b2a, 0x1a22d180, 0x011a221a, 0x80ebfe40, 0x2b150180, 0x0f83196a, 0x2206ed44, 0x18eb01c0, 0x2e0ac876, 0x15171300, + 0x33053521, 0x35052315, 0x82031521, 0x82272007, 0xcbf53903, 0x2a016bfe, 0xd6fe4040, 0x40eb9501, 0x40408040, 0x2b6beb01, 0x6a96552b, 0x00220982, + 0x3b639696, 0x01d52b07, 0x000700c0, 0x0025000b, 0x41182400, 0x33220886, 0x73510715, 0x34112807, 0x32213336, 0x77151516, 0x012b07c2, 0x13131a48, + 0xd535131a, 0x42111a15, 0x012805fe, 0xc01a112a, 0x12191912, 0x3405f166, 0x2baaaa47, 0x191a1115, 0x122a0112, 0x15111a19, 0x12aa1219, 0x0aa96319, + 0x0f000727, 0x00001f00, 0x24b48237, 0x06222634, 0x23048336, 0x27321614, 0x46186886, 0x802c079b, 0x50580001, 0x3426c058, 0xda342626, 0x2c434c83, + 0x19122805, 0x1d151595, 0x83742525, 0x95262117, 0xfe216183, 0x426d83d6, 0x80450af1, 0x2f401805, 0x06142715, 0xde342622, 0x40184b44, 0x982f0c2a, + 0xb07d7db0, 0x1d28667d, 0x1d25261c, 0x8407011d, 0x82662074, 0xb07d3312, 0x15000400, 0xc3012b00, 0x1d00eb01, 0x2d002500, 0xba823900, 0x47181420, + 0x35300bba, 0x16171633, 0x36331716, 0x06071737, 0x16072323, 0x4106ca41, 0x372c07d2, 0x33352335, 0x33153335, 0x99152315, 0x09c94718, 0x14462108, + 0x0a240514, 0x25074b96, 0x9f190c52, 0x1922c013, 0xbc1a2219, 0x221a1a22, 0x40408019, 0xc540402a, 0x07d44718, 0x2b2a2a2c, 0x88154d09, 0x1695150e, + 0x1e824823, 0x05842782, 0x2b40da23, 0x47028240, 0xd8240802, 0x0f000700, 0x1920ad82, 0xfc83a982, 0x22263424, 0xe6431406, 0x15372907, 0x35270717, + 0x37270727, 0x3ff3df18, 0x0b00d824, 0x66181300, 0x01200774, 0x470a814a, 0x72870769, 0x6c822520, 0x03820720, 0x84150121, 0x7c2935cf, 0x577c5757, + 0x7070a045, 0x950170a0, 0xcb1b621b, 0x01621b62, 0x1b3edf18, 0x2300052a, 0xd5012b00, 0x0300d801, 0x1e277382, 0x32002200, 0x82130000, 0x27132a51, + 0x16141506, 0x16033233, 0x59d58200, 0x36220571, 0x19822737, 0x82052721, 0x54072004, 0xee6305be, 0x12ab3d08, 0xd2d2131f, 0x343e5722, 0x19014cf6, + 0x372f1b25, 0x1c705047, 0x1e181113, 0xb2011d18, 0x733c8982, 0x2a21181b, 0x1370502a, 0x01570921, 0x0f1e0fba, 0x2ad2a0fe, 0x01583e35, 0xe8fe4c7a, + 0x2f3b2f82, 0x4a1d4f71, 0x1f141116, 0x212e1d13, 0x09582053, 0x4f711420, 0x1820282c, 0x41573e1c, 0x77470a7e, 0x00192605, 0x3700001d, 0x20988237, + 0xe1671837, 0x0614250a, 0x37342622, 0x26067e41, 0x801769e1, 0x410f1644, 0x68250a10, 0x01621b62, 0x218a8248, 0x1a836aca, 0x8358a221, 0x71fe2a1b, + 0x9e71719e, 0x5220527e, 0x3b758252, 0x15000300, 0xeb018000, 0x19008e01, 0x31002500, 0x37010000, 0x26272636, 0x26070706, 0x262df082, 0x06060726, + 0x06061717, 0x26262107, 0x4e6d1805, 0x8a33200a, 0x0125080b, 0x03022877, 0x030b0405, 0x2d642d28, 0x050a0428, 0x28020205, 0x01053d32, 0xfe3d05d6, + 0x0f0f0bec, 0x10100b0b, 0x200382cb, 0x390b820b, 0x05443601, 0x0202030a, 0x13134505, 0x03020545, 0x44040a03, 0x3939601d, 0x26845e60, 0x2e832283, + 0x7b430782, 0x0003220a, 0x25a68207, 0x23352500, 0x74183715, 0x16660b9a, 0x2bc02613, 0x8080552b, 0x0f9762c0, 0x2205a95d, 0x82130003, 0x181f20e7, + 0x2515a14f, 0x35231517, 0x05841533, 0xc0013524, 0x671880fe, 0x552a0b24, 0x6ac06a2a, 0x2c016a40, 0xd318d4fe, 0x80230d4e, 0x832b6b40, 0x58104d02, + 0x48000521, 0xeb20053e, 0x22064c54, 0x5f290013, 0x44180d45, 0x415007b7, 0x36362b10, 0x01171632, 0xd6d6d66b, 0xb4709696, 0x44802005, 0x058305ee, + 0x20075925, 0x1807202a, 0x27099c49, 0x120c2b01, 0x0c120d0d, 0x230b2b48, 0x13181813, 0xeb2cd788, 0x0f000700, 0x2d001700, 0x35250000, 0x18050153, + 0x18083145, 0x2016594b, 0x2c818533, 0x58505880, 0x2626349a, 0x12372634, 0x1bf3180c, 0x1e6b2813, 0x1d25251d, 0x8200011e, 0x34262222, 0x2088a27b, + 0x238a820b, 0x12000025, 0x20065c46, 0x06395517, 0x6d082f68, 0x808407fd, 0x7584f720, 0x00822a20, 0xff90aa20, 0xf2829520, 0xcd120c29, 0x2b558080, + 0x9040012b, 0x410320fc, 0x0624087c, 0x24000e00, 0x2324fa83, 0x35170735, 0x241e7341, 0x6b6b5555, 0x27eb9509, 0x6a4055c0, 0x0001406b, 0x7091e496, + 0x82233721, 0x182320dc, 0x4117bc4c, 0x00240662, 0x4056406b, 0x2416e341, 0x55556b80, 0x246ea0d5, 0x000d0005, 0x079d4a23, 0xd5266d9d, 0x378d1eab, + 0xdf95891e, 0x1eab9525, 0x971e378c, 0x0e9e696f, 0x16012808, 0x23061415, 0x15372715, 0x34353632, 0x06222727, 0x07171415, 0x36343526, 0x07173533, + 0x651b9001, 0x35555546, 0x82710f4b, 0x841f2003, 0x5b01330c, 0x65463229, 0x40555640, 0x1e1e354b, 0x20354b44, 0x11861f1c, 0x58020021, 0x06270833, + 0x00001900, 0x18273325, 0x3142d3b4, 0x012b0055, 0x00d501ab, 0x00140004, 0x37151300, 0x67433517, 0x3580220f, 0x08336b36, 0x01111a29, 0x2020abab, + 0x6b192aab, 0x562f0732, 0x01001911, 0x40006b00, 0xc0019501, 0x4b000a00, 0x272005b4, 0x3205b944, 0x9519116b, 0x01111995, 0xfe111ac0, 0x014040ab, + 0x821a1155, 0x222c87c5, 0x820f0004, 0x231128c5, 0x32133711, 0x87111516, 0x6bd62133, 0x80273686, 0xebfe1501, 0x8a11012f, 0x0003223c, 0x20698255, + 0x246982ab, 0x00070003, 0x09284437, 0x2315372b, 0x33151516, 0x14152315, 0x2a058207, 0x26220606, 0x33352327, 0x82353526, 0x34352205, 0x20058237, + 0x08f07436, 0x17160735, 0x56562b01, 0x022dd656, 0x2d022b2b, 0x463b113c, 0x863c113b, 0x0f24080c, 0x2f1e2318, 0x2f0f1e0f, 0x0e19231e, 0x2b2b0001, + 0xaa2a2a55, 0x15080e2a, 0x0e07152b, 0x23231d2b, 0x070e2b1d, 0x083a0c82, 0x11192a0e, 0x032e1e23, 0x231e2e03, 0x01001911, 0x0d000e00, 0xee01eb01, + 0xd5821600, 0x06163108, 0x27060707, 0x27260627, 0x17372626, 0x16362737, 0x07161617, 0x0107e401, 0x0f0f3108, 0x1e5124c2, 0x5e141020, 0x58265c40, + 0x0f111e20, 0x0713046b, 0x0f2f1683, 0x58201e11, 0x5c405c26, 0x1e200e12, 0x18002451, 0x08099da7, 0x1d000e27, 0x33130000, 0x34332707, 0x17323336, + 0x22232607, 0x23172506, 0x22230614, 0x33163727, 0x23353632, 0x56554080, 0x22301940, 0x15012108, 0x1c2f0c86, 0x404b3520, 0x55550001, 0x1f1b6546, + 0x86204b0f, 0x4e352007, 0xab20081d, 0x05380982, 0x13010000, 0x21071321, 0xfed50001, 0x0188d556, 0xfeab0110, 0xda0501aa, 0xd85d2584, 0x00052205, + 0x083f430d, 0x2b06ad49, 0xa21ec0d5, 0xb03d1e4c, 0x7db07d7d, 0x2005cf4d, 0x05ff49d5, 0x52000521, 0xab22056b, 0xf75b0300, 0x25002108, 0x4d0a366b, + 0x172407d2, 0x35231533, 0x15200382, 0x01200382, 0x0c621719, 0x8496d521, 0x016b3800, 0x01ebfe15, 0xfe111a40, 0x1a1a11eb, 0x11150111, 0x8a20e01a, + 0x52201520, 0xbb420828, 0x0002293d, 0x0180002b, 0x008001d5, 0x2206da78, 0x5d173727, 0x072805d1, 0x63633701, 0x8c80801e, 0x1e240382, 0x62629e63, + 0x03830783, 0xd4826220, 0x8305867f, 0x000725de, 0x01000017, 0x5406627a, 0xab241016, 0x5601aafe, 0x56180383, 0x012709f8, 0xd52b2b55, 0x18018080, + 0x470ce856, 0x0f20105e, 0x33275482, 0x35112315, 0x6a211533, 0x152507fc, 0xfeababab, 0x25048280, 0xff80c001, 0x4482d500, 0xd5d5ab22, 0x220a5043, + 0x82110007, 0x082f8335, 0x1733372a, 0x11211103, 0x23230614, 0x95012622, 0x164ad6fe, 0x01cb166a, 0xaa111a00, 0xab011a11, 0x15152b2b, 0x0001c0fe, + 0x1a1100ff, 0x2107b562, 0x4f6601ab, 0x000a2205, 0x21448218, 0x73462733, 0x4c172008, 0x132d075c, 0x01333634, 0x40767615, 0x80aaaaaa, 0x05835780, + 0x11190128, 0xe0754001, 0xd4822b2b, 0x82550121, 0x19112195, 0x56201182, 0x0c347218, 0x17000726, 0x2f001f00, 0x2009ce46, 0x0ac47425, 0x54823520, + 0x8f07e646, 0x22842917, 0x19221a1a, 0x0c094001, 0x2205935e, 0x902f090c, 0x40012111, 0x19282282, 0x090c6622, 0x0d0d0980, 0x0c230482, 0x8319abfe, + 0x84672025, 0x2216840c, 0x7d000100, 0x1d311685, 0xff1ee3a6, 0x001e7700, 0x00090003, 0x01f9016b, 0x08098489, 0x00000d21, 0x07173737, 0x27011701, + 0x07371737, 0x1e093727, 0x5a011e77, 0x7800ff1f, 0x8787591f, 0x83e2871e, 0x841e200f, 0xc459243a, 0x4d881e88, 0xeb2008a9, 0x1b200982, 0x0020ed82, + 0x4d2ac618, 0xa7470220, 0x00c02406, 0x51200017, 0x35300d18, 0x11211533, 0x35231521, 0x13333634, 0x33352337, 0x0720b282, 0x32072551, 0x012b1912, + 0x2bd6fe2a, 0x376c1219, 0x1e37cece, 0x51016b6b, 0x192e062d, 0x01555512, 0x1255552a, 0x38f3fe19, 0x1982382a, 0x280c8f4a, 0x0013000b, 0x07372500, + 0x087a5307, 0x3606f243, 0xaf512f01, 0x7db02851, 0xcb7db07d, 0x140d0d14, 0x51afd10d, 0x825501af, 0xb07d220e, 0x250e8241, 0x0100140d, 0xa5752b00, + 0x842f2006, 0x08da56aa, 0x29065649, 0x35262223, 0x36323335, 0x8d732634, 0x5c332005, 0x33390601, 0x15151632, 0x2016b501, 0x19201620, 0x30225111, + 0x19115122, 0x21211820, 0x280e8218, 0x1f2c1f56, 0x01191156, 0x87078515, 0x86258716, 0x5b562034, 0xd52508ec, 0x17000f00, 0x514e1800, 0x34352307, + 0x76820627, 0x87054756, 0x4e0420d2, 0xba2b0e73, 0x1607658c, 0x1a652e1b, 0x79014f21, 0x012705c9, 0x1010160a, 0x84701016, 0x65552c05, 0x051a1646, + 0x23502535, 0x54460c06, 0x532106cc, 0x201a830f, 0x8405840f, 0x01392cf7, 0x00c001d5, 0x25000014, 0x6e032e27, 0x72650508, 0x06290806, 0x1f000107, + 0x163b3035, 0x263a3243, 0x43323a26, 0x39453d34, 0x442e301c, 0x44311d37, 0x31442d2d, 0x3e3e5427, 0x2b000200, 0x22438500, 0x822d0018, 0x823e2045, + 0x23262644, 0x23070622, 0x31068326, 0x021e1415, 0x32131717, 0x0e141516, 0x27070702, 0x6386022e, 0x02012108, 0x15362e30, 0x2b19202b, 0x2b082808, + 0x152b2019, 0x02302e36, 0x16433260, 0x1f35303b, 0x343d451f, 0x22087684, 0x3c2c2b74, 0x2a20162e, 0x1c16161c, 0x2e16202a, 0x022b2c3c, 0x31444e01, + 0x2e44371d, 0x3e1b1c30, 0x8327543e, 0x0c0a428c, 0x72000721, 0x624840b1, 0x00072405, 0x18000021, 0x39072a46, 0x35362717, 0x06222634, 0x32331614, + 0x23061737, 0x35262221, 0x33363413, 0xbd501733, 0xc5270805, 0x583f1252, 0x1f2c3f3f, 0x0e0b5e1c, 0x1a1100ff, 0xab111901, 0x2634d180, 0x4d263426, + 0x2c1f1c52, 0x3f583e3e, 0x44085f12, 0x803e056d, 0x55000200, 0xca013600, 0x1400ab01, 0x00002400, 0x27071725, 0x22232306, 0x35072726, 0x307f0733, + 0x22272906, 0x36230706, 0x16323336, 0x3c051f72, 0x1f676301, 0x01302868, 0x2c123e19, 0x2d1f3680, 0x2b083c24, 0x3e248e05, 0x54082b07, 0x25148638, + 0x671f68bd, 0x1f841a1d, 0x25233227, 0x362332a5, 0x210d854a, 0x93430d00, 0x00032408, 0x50100007, 0x222c0643, 0x2b002600, 0x34002f00, 0x3c003800, + 0x35238782, 0x82031533, 0x18052003, 0x2507878e, 0x14333505, 0x11822706, 0x03820720, 0x26220528, 0x15133335, 0x92823523, 0x07231522, 0x03240882, + 0x36342315, 0x08ff8218, 0x2b2b4030, 0x0100ff2b, 0x1200ff00, 0x2b550119, 0x0f84111a, 0x2b19122e, 0x11aa2a55, 0x2a802b1a, 0x12192b2b, 0x95291382, + 0x00012b2b, 0xff2a2b2b, 0x270f8200, 0x2bd60001, 0x2bab1a11, 0x2a232482, 0x83121956, 0x111a2218, 0x292184d5, 0x2aab1912, 0x2b2b562a, 0xbb8c0900, + 0x98500b20, 0x00282706, 0x0030002c, 0x99823700, 0x03823320, 0x40753720, 0x46152006, 0x35250546, 0x33363435, 0x20178213, 0x20038201, 0x83b98311, + 0x820383c6, 0x802a257e, 0x1a11d5d5, 0x12286782, 0x80121919, 0x2bd5fe2b, 0x9982a582, 0xc2832b20, 0x1c822b20, 0x82000121, 0x1a11281c, 0x12d51219, + 0x8480fe19, 0x21da828d, 0xc2821219, 0x2a2a562b, 0x6b000200, 0x95015500, 0x5cbf1801, 0x2c575524, 0x2b000423, 0x05c04800, 0x2005df4d, 0x09b3531f, + 0x07475618, 0x9c180220, 0x012d0eb9, 0x20202c3f, 0x1f551f2c, 0x2c1f1f2c, 0x27048355, 0x7db03320, 0x8b7db07d, 0xc1201184, 0xff211184, 0x210c8400, + 0xe07d2b01, 0x5c15200f, 0x012005d0, 0x2a05df42, 0x36343315, 0x07141632, 0x82150607, 0x0737240a, 0x5b152335, 0x161908ce, 0x43200f80, 0x01266484, + 0x231c1410, 0x16193232, 0x21260979, 0x2a2a911b, 0x678f6a01, 0x1b20ce83, 0x2211dd56, 0x48071705, 0x272105c0, 0x66351937, 0x0c01240c, 0x8737371e, + 0x0cad5602, 0x188a0320, 0x00020032, 0x01400015, 0x00c001d5, 0x001e0005, 0x15330100, 0x26204d82, 0x0623c182, 0x4a262223, 0x3c08056a, 0x06222634, + 0x27073315, 0x01343327, 0x104b2000, 0x719e3a5b, 0x4f214f71, 0x3d2c1e17, 0x7c58583e, 0x02564057, 0x55014053, 0x371a2d5a, 0x70a070d5, 0x2c1f1721, + 0x57577c57, 0x5303563e, 0xc2481850, 0x00c02c08, 0x3700000a, 0x37233523, 0x82152317, 0xd53c0806, 0xd5d5406a, 0x55566a40, 0xabc0c0ab, 0x00030080, + 0x012b0080, 0x00d50180, 0x00090004, 0x01000013, 0x15233537, 0x15072717, 0x15210333, 0x21151707, 0x01273735, 0xaaaa5500, 0xd5aa5555, 0x55320882, + 0x555500ff, 0x4b550b01, 0x5555c04b, 0x8080014b, 0x03835555, 0x88010021, 0x00092348, 0x3a881300, 0x32888020, 0x2987d520, 0x4d000321, 0x0950050c, + 0x82272005, 0x84352072, 0xcc6518ea, 0x0b7c7d08, 0x36343523, 0x07b84633, 0x2742012b, 0x22312736, 0x1a221a1a, 0x0d2d6dab, 0x2b550128, 0x1b27271b, + 0x1a82c02b, 0xa6221a22, 0x5e102e6d, 0x0324090d, 0x0f000700, 0x4209cf4c, 0x41190823, 0x01270976, 0xab2b2b40, 0x19018080, 0x26107741, 0x000b0003, + 0x82170013, 0x333521dd, 0x1808646c, 0x220b3192, 0x5a5b2aeb, 0xc0210aa5, 0x2049832a, 0x0b9b5aeb, 0x8080c322, 0x2b0a936f, 0x001e0006, 0x23353700, + 0x17353335, 0x480b0c4e, 0xeb230b69, 0x7055d6d6, 0x2b3a0850, 0x80fe8001, 0xab111a2b, 0x55402a40, 0xfe1219c0, 0x191911d5, 0x01565611, 0xf14d562c, + 0x55420805, 0xab013400, 0x0600d001, 0x00001200, 0x06071125, 0x37161415, 0x23061416, 0x26272622, 0x01373734, 0x4c265a00, 0x476432ad, 0x3215471d, + 0x015e7932, 0x35265a35, 0x32f94c34, 0x151d648d, 0x79328d32, 0x72180100, 0x0e240889, 0x17010000, 0x3908c95a, 0x32333336, 0x5d5d7801, 0x11ea160d, + 0xea111a1a, 0x83830116, 0x11191283, 0x4d5a11d6, 0x016b2805, 0x009501d5, 0x82130004, 0x27372477, 0x8e251523, 0x4c55253a, 0x0d01ea4c, 0x95243f8a, + 0xeed66b6b, 0x0a204288, 0x300a3c44, 0x0015000d, 0x0020001a, 0x002e0026, 0x00390033, 0x2d528241, 0x27343633, 0x07141623, 0x23373636, 0x0c832706, + 0x17140623, 0x2e0c8217, 0x37362716, 0x15070606, 0x26171616, 0x82332727, 0x06232be4, 0x07063714, 0x26172633, 0x14822726, 0x08067b48, 0x485d0129, + 0x03480606, 0x0e361929, 0x03190a3f, 0x03036403, 0x520d1c32, 0x120c390d, 0x0d0d3719, 0x0a141937, 0x03034850, 0x83ab0648, 0x0e783a15, 0x0c121936, + 0x7d7db0ad, 0x1cd57db0, 0x2c151c1e, 0x172d088b, 0x2c155228, 0x26028215, 0x2c2c297f, 0x82212bd6, 0x17aa2611, 0x2824082d, 0x2213822a, 0x82b91e1c, + 0x822c2015, 0x2b21220f, 0x05414480, 0x30094b4a, 0x001b0008, 0x15330100, 0x27073523, 0x35132337, 0x0bbf5833, 0x112b1682, 0x2b952b01, 0x4cd11ed1, + 0x581a2b6a, 0x952506b6, 0x95c00195, 0x2313824c, 0x9595d6fe, 0x2707af58, 0x00d6fe2b, 0x00400006, 0x01211b82, 0x0c13686b, 0x21130029, 0x35152115, + 0x84251521, 0x15332203, 0x06cb4c07, 0x2b019524, 0x0386d5fe, 0x832b8021, 0x6b012a00, 0x2b2bab2b, 0x552a2a56, 0x6508862b, 0x90430839, 0x0703446c, + 0x21000324, 0x42182900, 0x1a410960, 0x06f74307, 0x88182620, 0x152c0806, 0x34262206, 0x14163236, 0x00ff8001, 0x0b3d9f18, 0x3627c232, 0x583f2927, + 0x1a225a3f, 0x551a221a, 0x0001d6d6, 0x270aff43, 0x1b27271b, 0x2c3f3f2c, 0x7d061a44, 0xeb200816, 0x0b20f582, 0x2306905f, 0x13152135, 0x8b1ea971, + 0x713e207c, 0x7c8912ae, 0x712b2b21, 0x994414b1, 0x0af04905, 0x18001024, 0xf7822a00, 0x26343627, 0x07072223, 0x05764a27, 0x47171721, 0x5e180724, + 0x013811b7, 0x161f1070, 0x0f100f17, 0x1f16170f, 0x1aad5b0f, 0x131a1313, 0x0c0c7401, 0x0ac65e18, 0x2c10ba27, 0x10100f1f, 0x2228830f, 0x820c015b, + 0x1a132120, 0x0ed35e18, 0x2405364c, 0x000002d5, 0x0de14c17, 0x36341124, 0x24503333, 0x01352405, 0x521911ab, 0x2b24077b, 0x012a80ab, 0x8205874e, + 0x00012713, 0x55801a11, 0x354280ab, 0x00d52608, 0x000e0002, 0x244b821c, 0x35132733, 0x085b6b23, 0xd04e1320, 0x2a402511, 0x162a4040, 0x210cd24e, + 0x1383f6fe, 0x01404023, 0x0bd44e2a, 0x09e4a318, 0x1e000622, 0xba465982, 0x07244505, 0x33352325, 0x78152135, 0xb483051f, 0x55000122, 0xea375982, + 0x111a1912, 0xd6fe5555, 0x19125555, 0x2b011219, 0xd6808056, 0x82ff1219, 0xd52b23af, 0x11822bd5, 0xfa5e0020, 0x4b95430c, 0x7a000421, 0x062107b1, + 0x0b561800, 0x07332708, 0x25353327, 0xae833507, 0x23150727, 0x15372715, 0x05864737, 0x402b012b, 0x01406b6b, 0x40406b16, 0x200982c0, 0x84038255, + 0x40402508, 0x4056406b, 0x1d820282, 0x14831520, 0x280a0151, 0x001d000d, 0x25000025, 0x0bd04b37, 0x200f4354, 0x07ee4416, 0x3e1e662b, 0x3850380f, + 0x191a2838, 0x09c94183, 0x202c8a2c, 0x7c1f2c20, 0x1a193e1e, 0x1e823828, 0x67f10f21, 0x6b210be1, 0x511e831f, 0x02205374, 0x2208a06e, 0x822f000b, + 0x06ef47c3, 0x32161423, 0x09d34136, 0x62183620, 0x1622099e, 0xa7181517, 0x3328072f, 0x01173337, 0x1a221a2b, 0x80200282, 0x962ac983, 0x322b3e2d, + 0x3e2b3246, 0x0e83962d, 0x80274424, 0xb977eb27, 0x1a112205, 0x06467c1a, 0x47082d31, 0x3333232f, 0x08472f23, 0x01111a2d, 0x18191100, 0x2108d870, + 0xe54401c0, 0x0f7e5808, 0x200f4c41, 0x069f4b33, 0x78580120, 0x5e688409, 0x152a0558, 0x802baa2b, 0x25251d15, 0x7058151d, 0x1a662206, 0x05ed5d11, + 0x4b2a0121, 0x00220594, 0x00820003, 0x02fd0129, 0x00070000, 0x4b54004a, 0x37340911, 0x07151617, 0x27060715, 0x07070627, 0x22232314, 0x27262735, + 0x35280e83, 0x37373427, 0x36342634, 0x37241082, 0x17173637, 0x0ea01719, 0x15161525, 0x82070714, 0x56062004, 0x2d0805e4, 0x26070123, 0x131a8801, + 0x6f131a13, 0x15010217, 0x031a0403, 0x2a06040f, 0x0a080406, 0x1502051a, 0x01170201, 0x02031701, 0x1a050215, 0x1884060c, 0x880e0421, 0x424f2918, + 0x01f7025e, 0x4b0e01ab, 0x133a3f82, 0x0211021a, 0x25010103, 0x030b0205, 0x04041d07, 0x0b06041d, 0x01250502, 0x18820301, 0x08020835, 0x04031201, + 0x0b020425, 0x041c0308, 0x09021c04, 0x8204020b, 0x0201301c, 0x07031202, 0x5eaa0802, 0x010e0842, 0x1802f7ab, 0x20081a4b, 0x089454eb, 0x410c9254, + 0x172407d9, 0x37352315, 0x01210382, 0x0acc7f6b, 0x2a2a8024, 0xcb7f6b2a, 0x80d62511, 0x2b2b5680, 0x55215982, 0x05697200, 0x285dcf68, 0x00000003, + 0x0100022b, 0x227182d5, 0x181f0016, 0x460abd47, 0x424f079e, 0x086d4e05, 0x01952008, 0x4b354b2b, 0x1a1a11e0, 0x11abfe11, 0x1119011a, 0x00ff2b80, + 0x80fe8001, 0x60c01a11, 0x186b6040, 0x28091a48, 0xfe2b2a19, 0x11192ad5, 0x8c8d1801, 0x00042a0b, 0x01000025, 0x07231533, 0x1f441817, 0x18072014, + 0x2409eb46, 0x80c00001, 0xdb461840, 0x0904220c, 0xdb46182f, 0xc0012408, 0x18364095, 0x210d1944, 0x4618090d, 0x002007cd, 0xc020d787, 0x07340982, + 0x00000d00, 0x23353313, 0x15233517, 0x01173213, 0x2aeb3601, 0x15350082, 0x00ff7888, 0x017600ff, 0x80d52b55, 0x5b150180, 0x3b01c6fe, 0x0aa57a5a, + 0x044b0320, 0x7b252005, 0x05221209, 0xf15c2315, 0x55012210, 0x12ee5caa, 0x8080552c, 0x0b000100, 0xf5015500, 0x8983ab01, 0x07170136, 0x03273723, + 0x33372723, 0x01131707, 0x55606095, 0x55a83860, 0x01210685, 0x220082ab, 0x83f2fe63, 0x0e012105, 0x250abe64, 0x001a0016, 0x7c180100, 0x172c093f, + 0x14150606, 0x35363216, 0x27272634, 0x2a088c83, 0xa070447c, 0x1e1c2870, 0x7c572017, 0x49172057, 0x3a92012a, 0x70705058, 0x18562450, 0x1d44131e, + 0x3e57573e, 0x4d12441d, 0x1800d5d5, 0x4c5dff63, 0x885f0981, 0x2d001905, 0x4b02203d, 0x2619082f, 0x04214a8e, 0x534e1800, 0x00192c07, 0x0021001d, + 0x37000025, 0x89371711, 0x27112201, 0x20018807, 0x06895725, 0x07820520, 0x95204021, 0x20012100, 0x26055451, 0x00ff0001, 0x8baa012b, 0x56fe2124, + 0xf5230d8a, 0x51552b2b, 0x0520052f, 0x39062846, 0x000c00d5, 0x00180010, 0x00420020, 0x23352500, 0x27260717, 0x37270706, 0x6f831523, 0x5c07355d, + 0x5e7b075e, 0x35262910, 0x32333634, 0x36371717, 0x30051454, 0x6dab0107, 0x0840232d, 0x2d234008, 0xfe56016d, 0x05e25caa, 0x56200585, 0x3d093258, + 0x1a26042f, 0x0b0b1421, 0x1a0e2007, 0x80d50426, 0x0b57193c, 0x3c19570b, 0x2a2a6a80, 0x69184001, 0x1e250aaf, 0x12ea1219, 0x2c048419, 0x261a070e, + 0x0c0f0f1c, 0x071a2610, 0x0826430e, 0x2005b273, 0x09a4730a, 0x13130735, 0x2a2a1501, 0xebebd62a, 0x555656d5, 0x01402b2b, 0x506bfe95, 0x63186106, + 0xc6425804, 0x00402a45, 0x01b5014b, 0x000700c0, 0x0962511a, 0x07171725, 0x6c273527, 0x323c05f9, 0x06141516, 0x50a31707, 0x38503838, 0x6a206ae0, + 0x3a342606, 0x50745151, 0xd5060d14, 0x02821282, 0x11351482, 0x74502106, 0x153a5151, 0x00061035, 0x002d0002, 0x01d3012b, 0x205582d5, 0x2255893f, + 0x5c161737, 0x0582052b, 0x22232323, 0x06714727, 0x37372626, 0x27373426, 0x6d470682, 0x33362805, 0x17173233, 0x82371716, 0x3530820e, 0x3ee11416, + 0x2c3e2c2c, 0x05072dea, 0x3509042b, 0x02080f15, 0x03825608, 0x3511132a, 0x052b0409, 0x01012d07, 0xb5201a99, 0x2c3b3982, 0x05230a3e, 0x03074a09, + 0x38060f15, 0x08380909, 0x0703150d, 0x2305094a, 0x97071c07, 0x08e75818, 0x3b00c02d, 0x53004b00, 0x34240000, 0x82363727, 0x070722b3, 0x82058226, + 0x22c582bf, 0x82262707, 0x14152805, 0x14061717, 0x83060717, 0x37162308, 0xbd821637, 0x3722c382, 0xf1823637, 0x27210582, 0x0fd84827, 0x3408254a, + 0x05200170, 0x06031e04, 0x060c0d25, 0x063c0502, 0x09100601, 0x27118225, 0x01200201, 0x01022001, 0x04231a92, 0x6a262005, 0x2108095c, 0x1a1a2284, + 0x14f61a22, 0x06041805, 0x0f020534, 0x0627050a, 0x07072806, 0x3306020f, 0x01050301, 0x1a820518, 0x03050123, 0x231c8f01, 0xcf180406, 0x200b926a, + 0x32468295, 0x0200221a, 0x40000000, 0xc001c001, 0x1f001700, 0x53120000, 0x3321140f, 0x05b87034, 0xb0323636, 0x507070a0, 0x1e16441b, 0x573e3126, + 0x40577c57, 0xeb405556, 0x01284984, 0x70a070c0, 0x1b1e1117, 0x57251582, 0x5055553e, 0x29a9843f, 0x6b000600, 0x7a010000, 0x6a820002, 0x13000522, + 0x455a6682, 0x15273705, 0x33371511, 0x23071707, 0x37270735, 0x35173727, 0x33351333, 0x024a2315, 0xc7021907, 0x2b403a0e, 0x2a2b2bd6, 0x015028cf, + 0x5b285007, 0x62a27a5c, 0x1e77781e, 0x00fea262, 0x2300842b, 0x80000500, 0x80206782, 0x985d6782, 0x07054916, 0x69836587, 0x18550121, 0x2c0abcd0, + 0x2a802b95, 0x01ab2b80, 0x0100ff00, 0x05564855, 0x01111a25, 0x881a1155, 0x00042163, 0x2005fc5d, 0x246d82c0, 0x00190015, 0x35718229, 0x34363215, + 0x27350726, 0x37333537, 0x17153317, 0x07231507, 0xaa471727, 0x00012812, 0x6f26261a, 0x87352020, 0x64e02002, 0x01260da8, 0x34268040, 0x1e889526, + 0x41200882, 0x8211b564, 0x00112679, 0x01ef0175, 0x2609828b, 0x000d0009, 0x82170011, 0x07172c85, 0x07273727, 0x37153335, 0x83352315, 0x07272107, + 0x013a1283, 0x2174747b, 0x2a6f5d5d, 0x2bab2b56, 0x215d5d1a, 0x8b017474, 0x701b8b8b, 0x98788570, 0x852a2806, 0x8b1b7070, 0x8203008b, 0x01222cda, + 0x00eb01eb, 0x001c000b, 0x18000028, 0x200b1498, 0x20d68205, 0x21618227, 0xd05a2635, 0x26142105, 0x12259818, 0x4900013e, 0x1e40401e, 0x2c1f2049, + 0x577c731f, 0x3f583f2a, 0x8aeb012a, 0x70705061, 0x46926150, 0x46311c85, 0x1f16240d, 0xb924161f, 0x3f2c3e57, 0x003e2c3f, 0x08c74d06, 0x16000a2d, + 0x2d002200, 0x45003900, 0x82250000, 0x061422ca, 0x23cc8207, 0x33150326, 0x91540682, 0x05545f05, 0x01208485, 0x21842283, 0x89372621, 0x252e8c2d, + 0x18806b01, 0xfc822b13, 0x0c2b8033, 0x2bab0c12, 0x120d2a80, 0x8055fe0c, 0x18132b2a, 0x241a82ab, 0x5518132a, 0x331b832a, 0x2a2aab0d, 0x5a072015, + 0x57010f5a, 0x55808055, 0x5e0d0d09, 0x092b0685, 0x2a2ad6fe, 0x5a5a0f2d, 0x86152007, 0x20072323, 0x24863f01, 0x46bfbe40, 0x0b2609ab, 0x00001d00, + 0x814d1513, 0x35333607, 0x07153317, 0x27352315, 0x34353335, 0x32333336, 0x2aab1516, 0x25018216, 0xaa40152b, 0x6e5f1540, 0x2a402106, 0x40230082, + 0x84808040, 0x19112503, 0x07001119, 0x2008d041, 0x08a85c07, 0x3b003326, 0x32240000, 0x85074444, 0x10897107, 0x94591f87, 0x21748405, 0x06521406, + 0x3e012705, 0x1a13131a, 0x05843d13, 0x70a0a52c, 0x5f70a070, 0xc28a8ac2, 0x1184938a, 0x0e12ab25, 0x83120e40, 0x82832004, 0x1a132825, 0x121c12c0, + 0x847d1c12, 0x82d8200b, 0xa070232b, 0x2c823b01, 0xa1c28a22, 0xd4201884, 0x7d203484, 0x00210584, 0x08d34306, 0x13000329, 0x19001600, 0x68001c00, + 0x132b1666, 0x15272707, 0x07172527, 0x68231727, 0xeb2b0f66, 0x35552b2b, 0x35353501, 0x4b562b80, 0xfe26127d, 0x803636eb, 0x00822b56, 0x6136b621, + 0x24260c11, 0x2c002800, 0x50180000, 0x884c19a8, 0x1527240a, 0x82233523, 0xaa501803, 0x0b8f4c10, 0x2b2b1827, 0x2b40012a, 0x17924c60, 0x83828b20, + 0x05002b24, 0x74825500, 0xd501ab24, 0xf1820300, 0x24067b4a, 0x15333521, 0x0bda4b03, 0x200cd94b, 0x069d4511, 0x0a315c82, 0x648e644a, 0x3d1e1f2b, + 0x244b6a4b, 0x2a2a2d1a, 0x38548280, 0x5834a101, 0x46646446, 0x1e155225, 0x4b354826, 0x401e354b, 0xd5d5530f, 0x211b82fe, 0xf4822b2b, 0x15005a2e, + 0x0002a601, 0x12000800, 0x2a001a00, 0x32287f82, 0x22260717, 0x07362707, 0x08144618, 0x08ee6418, 0x0fd3cf18, 0x4363003e, 0x38a0381e, 0x2c09451e, + 0x0d1e2c7c, 0x0d2d242d, 0x1a1a223b, 0x096b1a22, 0x80090c0c, 0x02240483, 0x381e4500, 0x81212182, 0x2320822c, 0xa10d1212, 0x29073f61, 0x0d0900ff, + 0x0001090d, 0xf7820c09, 0x77826b20, 0xeb01952c, 0x13000f00, 0x23001700, 0x0f822700, 0x23066944, 0x14333526, 0x35218082, 0x23e98603, 0x35262236, + 0x21056b44, 0x13831415, 0x19950121, 0x3b086c54, 0x2a802b31, 0x26263405, 0x2bab2634, 0x52362b01, 0x08464608, 0x3e2f3652, 0xd5fe2f3e, 0xeb25ef83, + 0x1a801a26, 0x21048326, 0xfc82effe, 0x07614a18, 0x0200d524, 0xfc820600, 0x37370029, 0x33153727, 0x62331735, 0x11200782, 0x2c086643, 0x15a0a0c0, + 0x18802a56, 0x12aafe12, 0x20068218, 0x22058256, 0x826b556b, 0xebfe3055, 0x12191912, 0x122b1501, 0x00121818, 0x60150004, 0x5385068c, 0x00002526, + 0x35273725, 0xd3555584, 0x23558808, 0x14211505, 0x37058b5e, 0x75000135, 0x6b2b5575, 0xd5fe1219, 0x196a1812, 0x19125512, 0x5501c0fe, 0xd5257082, + 0x55c01912, 0x4b6a8340, 0x2b20056b, 0x80216f83, 0x206e83eb, 0x0a684beb, 0x0a000724, 0xe6492300, 0x33272a09, 0x32331727, 0x06061516, 0x08618307, + 0x2627272c, 0x33363435, 0x33363733, 0x22ef1732, 0x1a221a1a, 0x6f408015, 0x0a0d0966, 0x20090528, 0x0920eafe, 0x090d0136, 0x0c065d66, 0x8548050d, + 0x5e913105, 0x28090c5e, 0x1f1f1391, 0x090402c6, 0x09098c0c, 0x84367718, 0x0bd29618, 0x0b000722, 0x20063242, 0x09cb5a25, 0x650ffb7f, 0x24680824, + 0xab802705, 0x6b6babab, 0x00832b2a, 0x0a926e18, 0x2b550124, 0x0284402b, 0x05848020, 0x01210b82, 0x0bf56c00, 0x3400032e, 0xeb012000, 0x0500c001, + 0x10000800, 0x0806de47, 0x3327172d, 0x23271727, 0x33132307, 0x1ecd0113, 0x4e1e6ccb, 0x552c5897, 0x2d187819, 0x016d286d, 0x6dcb1e09, 0x76b94f1e, + 0x014040e0, 0x66ebfe15, 0x09250ade, 0x00001100, 0x4b7c1825, 0x08805b08, 0x50185a3b, 0x69292969, 0x585a1850, 0xb07d7db0, 0x4567807d, 0x08616009, + 0x01366745, 0x0550591f, 0x46636e18, 0x55000428, 0xab016b00, 0x41599501, 0x083d5908, 0x2115352a, 0x23151735, 0x56015535, 0x31054f66, 0x9501d6d6, + 0x2b2bab2a, 0xab2b2b80, 0x04002a2a, 0x3a822b00, 0x3a82d520, 0x12000a2d, 0x22001a00, 0x32370000, 0x82150617, 0x36342432, 0x7c321636, 0xa8580770, + 0x58162005, 0x260806b0, 0x331d16c0, 0x97423795, 0x11ea504a, 0x34262634, 0x1f2c7626, 0xeb1f2c1f, 0x302e1c06, 0x10241735, 0x301a2016, 0x82601a30, + 0x34262218, 0x0583553b, 0x40000222, 0xc0206882, 0x06256882, 0x00000d00, 0x07445601, 0x23153334, 0xc0012715, 0xd6969655, 0x01559696, 0x2a405540, + 0x03828040, 0x9d665520, 0x2231840a, 0x82231713, 0x17232894, 0x33270733, 0x83c03335, 0x40ea2227, 0x85068255, 0x5555223c, 0x5ffd8296, 0x318307b0, + 0x00001525, 0x82352325, 0x27172334, 0x32821533, 0xf4732720, 0x35752508, 0xa04b352b, 0x2d2a0483, 0xb07d7db0, 0x5555c07d, 0x0382cb4b, 0x95414a20, + 0x00022c05, 0x01350015, 0x00b501eb, 0x581e0017, 0x15271250, 0x11211123, 0x83033523, 0x33152487, 0x1811c001, 0x24083096, 0x80018080, 0x21c28480, + 0x8718b501, 0x012e07cc, 0x2a19112b, 0x2b01d5fe, 0x55ebfe2a, 0x2d5dc0c0, 0x6f05200a, 0x352206b9, 0xfd671123, 0xabc02210, 0x0b646fd5, 0x55d56b26, + 0x5501d6fe, 0x27058e55, 0x2a01111a, 0x0f001a11, 0x200a5847, 0x248c1807, 0x4525201b, 0x3720066e, 0x07250782, 0x06143335, 0x065a6201, 0x07821320, + 0x03200383, 0x2005e641, 0x07996103, 0x17821720, 0x36340322, 0x2e09735b, 0x802a6b01, 0x2b2b802b, 0x9afe1a2b, 0x182a2a2a, 0x2108258c, 0x13821a11, + 0xd62b8024, 0xb061111a, 0x2aab2e08, 0x112bab2a, 0x2b55011a, 0x2babfe2b, 0x2107832b, 0x078200ff, 0x111a2b29, 0x80fe8055, 0x672a111a, 0x3b8206f1, + 0x2a2aaa22, 0x00212682, 0x0c9a6b07, 0x18070644, 0x586a6579, 0xc03605e9, 0x1a000300, 0x33010000, 0x32032311, 0x14151516, 0x26270707, 0x50793535, + 0x372e0806, 0x01333637, 0x55565695, 0x8c0d1a11, 0x87150917, 0x41031a11, 0xc0011d0a, 0x000100ff, 0x11d5111a, 0x09178d0d, 0x1962070d, 0x08082b11, + 0xe6411a96, 0x00eb2108, 0x8305d153, 0x7906204e, 0x152b0a44, 0x32330715, 0x33110516, 0x83eb0111, 0x89c02048, 0x2afe2457, 0x842b0156, 0x24578b45, + 0xff0001fc, 0x20568200, 0x24048300, 0x17000002, 0x05236700, 0x3621a887, 0x20a98a36, 0x216e9027, 0x6f830606, 0x0ee00132, 0x116a0912, 0x010b0307, + 0x020c096f, 0x50140931, 0x90200483, 0x0135158b, 0x8b0d132b, 0x1169090e, 0x340e0a07, 0x1b090c07, 0x14710803, 0x8c058455, 0x17b85d18, 0x33352528, + 0x15332715, 0x07821523, 0xc05d2120, 0x15212408, 0x832b9501, 0x80fe2100, 0x2509c05d, 0x802a2aeb, 0x1583ab2b, 0x5005bd5d, 0xeb200824, 0x07250982, + 0x00001f00, 0x18488213, 0x221b275f, 0x186b6b95, 0x2313235f, 0x556b2b01, 0x13215f18, 0x0a924018, 0x13000b28, 0x00001b00, 0xc0181412, 0x3f740915, + 0x4021080f, 0x48382332, 0x99233848, 0x6a4b4b6a, 0x658c3a4b, 0x01658c65, 0x0d474a25, 0x765c0e2c, 0x0d2c0e5c, 0x221682ec, 0x82e06a4b, 0x8c652216, + 0x06855c00, 0x00d50123, 0x08c15536, 0x33363424, 0xfa7e1533, 0x55352008, 0x272108cb, 0x09064a37, 0x26371589, 0x3e970127, 0x7d7db07d, 0x1a161558, + 0x1c161a22, 0x32463224, 0x82261e19, 0x2e3d2365, 0x6682573f, 0x82151d21, 0x58592221, 0x0824827d, 0x190cb027, 0x111a1a11, 0x082d0c19, 0x32231e2c, + 0x1b212332, 0x3534261e, 0x2f354b4b, 0x082b0847, 0x65464160, 0x471d4665, 0x22f28415, 0x82eb012b, 0x00023e97, 0x0024000a, 0x27332500, 0x27231337, + 0x13230723, 0x07270707, 0x27263727, 0x36171633, 0x08377737, 0x06064408, 0x53010707, 0x60162345, 0x1865182b, 0x114d602b, 0x6d1e6b42, 0x152b1828, + 0xef162e1c, 0x3f962a96, 0x01172e0a, 0xff395d95, 0x01404000, 0x422c6c00, 0x2c6b1e6a, 0x331f2835, 0x2a2a2b3f, 0x1a51202b, 0x6d010001, 0x0a20081d, + 0x37207182, 0x17306683, 0x15371737, 0x68315501, 0x801e9e55, 0x80318655, 0x2e820989, 0xab00402e, 0x5501d501, 0x00000600, 0x21350701, 0x01250182, + 0xc0fe55d5, 0x23608201, 0x402a4055, 0x0122508d, 0x51821533, 0x172eba82, 0x80550137, 0x80558631, 0x68559e1e, 0x0a888001, 0x2f6a5970, 0x00400002, + 0x01c00115, 0x000500eb, 0x3700000f, 0x072aeb83, 0x14151713, 0x26260706, 0x13723535, 0xc0802d05, 0x6e52526e, 0x8c1eab95, 0x00011e37, 0x0818d918, + 0x52610020, 0x000f3509, 0x2500001f, 0x15062221, 0x33161415, 0x35363221, 0x27263435, 0x01210f8e, 0x05aa5b95, 0x522a0121, 0x0b8409b1, 0x1219eb23, + 0x82128355, 0x89d52004, 0x0300210a, 0x2b087547, 0x00070003, 0x0100000b, 0x03331123, 0x01290386, 0x554040c0, 0x40ebd6d6, 0x23568340, 0xd6fe2a01, + 0x33820383, 0x86071248, 0x33132633, 0x33172315, 0x25038211, 0x552b2315, 0x32826a55, 0x01555529, 0x012ad66b, 0x92d62a2a, 0x23112362, 0x2e821311, + 0x07820320, 0x72390127, 0x9c727287, 0x88608b72, 0x05165364, 0x1300032b, 0x00001700, 0x21152113, 0x0edd6d05, 0x21350324, 0x3a822b15, 0x80016b28, + 0x090c0c09, 0x058395fe, 0x95011522, 0x2b20b882, 0x09a06c18, 0xc082fe20, 0x02490020, 0x4405201a, 0x02490683, 0x050a4908, 0x2a950125, 0x462b2b56, + 0x06200682, 0x4c0e2741, 0x002505bc, 0x23353337, 0x20038215, 0x21038235, 0x47822117, 0x35250382, 0x40352115, 0x24008455, 0xfe15016b, 0x260385eb, + 0x55c056d5, 0x82c05580, 0x55d52305, 0x4e960055, 0x23150124, 0x4a821735, 0x55820320, 0x33153724, 0x5c832135, 0x25410b82, 0x72152b05, 0xf2fe7287, + 0x01727272, 0x00828a95, 0x82d6fe21, 0x22028204, 0x828a8aa0, 0x073c49dd, 0x23059241, 0x0100000f, 0x13204b82, 0x05274786, 0x01112311, 0x8572f9c0, + 0x873e8340, 0x2a01243c, 0x4900d6fe, 0x0f26097a, 0x00001f00, 0xfa7b3537, 0x07c44c06, 0x240a6f42, 0x06222123, 0x054a7c40, 0x850bcb54, 0x2b952a0b, + 0x12191912, 0x1919112b, 0x5f0988e7, 0x5c830a5b, 0x5e822f20, 0x20070754, 0x05624e33, 0x34112530, 0x22232326, 0x14111506, 0x32333316, 0x0f8e2736, + 0x821d7221, 0x83112050, 0x52012204, 0x83078419, 0x199c2304, 0x6d831c12, 0x55200482, 0x00208f82, 0xff200b83, 0x2b210582, 0x8b0a8801, 0x82192016, + 0xf6a11887, 0x05044e54, 0xc001ea2d, 0x15000500, 0x36002600, 0x83130000, 0x7b1520d8, 0x37210612, 0x050e7b27, 0x37273726, 0x26260701, 0x272a0d84, + 0x26373636, 0x07221726, 0x2a823627, 0x82061721, 0x35600807, 0x03fd2634, 0x0c9f261a, 0x18172c3f, 0x1a060821, 0x1b970226, 0x051b7a01, 0x322b0e35, + 0x0b1c804f, 0x2b0c162f, 0x2e1314d2, 0x7f4f2e27, 0x3e31181c, 0x40013f08, 0x33041a26, 0x3f2c1718, 0x2602210c, 0x9708061a, 0x1b86fe1b, 0x120e3405, + 0x3f1a4858, 0x372c0c11, 0x580f2e08, 0x3e2a3b48, 0x3f2c1413, 0x2b259e82, 0xd5014000, 0xba675a01, 0x0bea6018, 0x19731c20, 0x1415290d, 0x15232306, + 0x23350727, 0x21053250, 0x1e730133, 0x55563a0c, 0x18125655, 0x2b011218, 0x2b6b8080, 0x1815012b, 0x1912eb12, 0x6a2a2a6a, 0x20088219, 0x08085d18, + 0x644ed520, 0x5a2d2006, 0x232305c5, 0x83152335, 0x65052003, 0x755b062e, 0x34353610, 0x32333336, 0x01151516, 0x802b40ab, 0x5601402b, 0x806baafe, + 0x095e5b6b, 0x12194028, 0xd5191280, 0x00822a80, 0x2205525b, 0x5b2b2b2b, 0x2b200949, 0x2b222983, 0x035c0200, 0x00032208, 0x21d8831d, 0x55841523, + 0x18073050, 0x230c20cc, 0xd6562b01, 0x56226089, 0xd9821218, 0x92800121, 0x82012055, 0x014b2655, 0x00c001d5, 0x5ace8222, 0xd4750560, 0x6b342008, + 0x33200669, 0x705a5b82, 0x01280806, 0x6b1f6a6b, 0x15351006, 0x14201f28, 0x38382813, 0x584a3850, 0x39523552, 0x0e14513a, 0x206ad506, 0x0d06106b, + 0x081f1314, 0x38251882, 0x39555528, 0x087d5a52, 0x6b006b26, 0x95019501, 0x063ac882, 0x17010000, 0x15210721, 0x8e000121, 0x0107e4fe, 0x01d6fe2a, + 0x2a2bd595, 0x11630300, 0x00072408, 0x8223000f, 0x27272692, 0x17173737, 0x07875407, 0x17331322, 0x20061244, 0x83681823, 0x00012508, 0x1b3a3a1b, + 0x47230382, 0x183f3f58, 0x301082ce, 0x1a1b3b95, 0x1b1a3b3b, 0x3e583f50, 0x0101583e, 0x05c44f2b, 0x7105ff62, 0x13220aaf, 0x70821b00, 0x00002723, + 0x18ea8412, 0x180c52da, 0x320f8b45, 0x15333517, 0x403246dd, 0x1418142a, 0x2a1a221a, 0x18658c0f, 0x33087d47, 0x80012ac0, 0x391b2332, 0x0f211717, + 0x19110e16, 0xf9231119, 0x220bec6a, 0x452b2bd8, 0xa968138a, 0x07684607, 0x80014024, 0x038980fe, 0x210c6846, 0x1f5c0003, 0x000b2b07, 0x00260013, + 0x15230100, 0x79493523, 0x07294106, 0x24122d5c, 0x152b0001, 0x2002822b, 0x13355c5d, 0x832b0121, 0x6b2b211a, 0x89153c5c, 0x00032a72, 0x001e000b, + 0x15331300, 0x07164123, 0x95236a92, 0x940e6b6b, 0x15402265, 0x31619556, 0x00150005, 0x01eb01c0, 0x00030040, 0x0017000f, 0xbc4d001f, 0x31401906, + 0x06345908, 0x1520eb86, 0x07200783, 0x0a08b618, 0x2bcb012e, 0x13130d2b, 0x75202b0d, 0x96202060, 0x55350382, 0x202b2020, 0x150b0120, 0x0d133515, + 0x2b130d15, 0x20202080, 0x28188260, 0x2b0b6060, 0x80353580, 0x08d4432b, 0x0900c02c, 0x11000d00, 0x00001900, 0xb1432325, 0x82052007, 0x4c2520e3, + 0x233f063b, 0x01152335, 0x111ad66b, 0xfe1a1180, 0x014040c0, 0xfe40406a, 0x405601c0, 0x11aaebd6, 0x82111a1a, 0xab402f0e, 0x40408080, 0x35000200, + 0xcb014000, 0x4e82d501, 0x4e821520, 0x27272625, 0x82021f35, 0x16340802, 0x06060716, 0x15210527, 0x522b0121, 0x141f227c, 0x713b296a, 0x04030d0d, + 0x98fe0d16, 0x6afe9601, 0x0a2017cc, 0x1c32086e, 0x1ec00bb0, 0x0d0d1704, 0x2b43030c, 0x27204e82, 0xda224e82, 0x4e85b401, 0x0616002b, 0x020f0607, + 0x17372726, 0x20038337, 0x334f8436, 0x0d0d06d4, 0x2271527c, 0x2a1f3107, 0x9329586a, 0x78fe0d72, 0x01335183, 0x04161a3f, 0x0a1e1621, 0x2008540c, + 0x890b991c, 0x83e2041e, 0x00802d52, 0x01800155, 0x000b0095, 0x37000012, 0x08055055, 0x06143346, 0x33372622, 0x27073315, 0x322b8033, 0x4b2b3246, + 0x2a6b4b6a, 0x4b60604b, 0x323223d5, 0x4b4b3523, 0x606077f5, 0x6b000300, 0x9501c000, 0x09004001, 0x23001f00, 0x23010000, 0x23153315, 0x33352315, + 0x15163223, 0x33220982, 0xb4713335, 0x3b26080a, 0x01231502, 0x2b2b4095, 0x09d56020, 0x202a4a0c, 0x0940090c, 0x75090c0c, 0x20012020, 0x802b2015, + 0x400b090c, 0x12832b20, 0x0c095623, 0x0acd4a80, 0x13000322, 0x20056345, 0x05054825, 0x2408f243, 0x01d66b01, 0x096c7e00, 0x2a2aeb23, 0x0cd550d5, + 0x220b5562, 0x82110009, 0x27372ae2, 0x17072707, 0x12152335, 0x05d85832, 0x1e8fdc2e, 0xd61e2971, 0x7db013d6, 0xd57db07d, 0x9c220d84, 0x4a762b2b, + 0x00200806, 0x005a0006, 0x01af0152, 0x000700a7, 0x0012000f, 0x00180015, 0x2400001b, 0x22263436, 0x12161406, 0x21084485, 0x33350736, 0x21352311, + 0x33112315, 0x44350115, 0x44446144, 0x7c58586e, 0x556c5656, 0x55550155, 0x11838855, 0x01446123, 0x2513830a, 0x5540587c, 0x1884abfe, 0x830a6552, + 0x002f215f, 0x08fb4318, 0x172c9f87, 0x14151522, 0x35363233, 0x06071433, 0x1805b046, 0x220a62a5, 0x44ba2627, 0xd2350a72, 0x140f2828, 0x1e151626, + 0x18142a28, 0x15132126, 0x02050326, 0x0c64710a, 0x063a1b38, 0x190d113a, 0x2a301213, 0x1b172906, 0x071c1513, 0x0a020a06, 0xdc620500, 0x00382e08, + 0x0067004c, 0x00930080, 0x26232500, 0xf5e01827, 0x05366408, 0x0622232d, 0x14150607, 0x27061617, 0x62343526, 0x06210740, 0x210c8222, 0x18842226, + 0x07161726, 0x16142706, 0x3221b282, 0x210b8316, 0x29832223, 0x07323322, 0x09830782, 0x16323625, 0x68221415, 0x142105e2, 0x20228417, 0x240e8203, + 0x36373637, 0x210e8332, 0x5a821415, 0x07207682, 0x25206882, 0x23233382, 0x82060722, 0x08f4855d, 0x010607d7, 0x212e033e, 0x36261b13, 0x1a261927, + 0x4c2e405b, 0x030e0c13, 0x0f100314, 0x49345715, 0x26362767, 0x2819261a, 0x02092a1c, 0x29373d02, 0x09090e02, 0x0c0b0201, 0x331a280e, 0x04390a0b, + 0x17101b03, 0x16476447, 0x133a523a, 0x08081b0d, 0x020b8a03, 0x78323020, 0x021f3132, 0x2a1e0410, 0x2d2e6c2e, 0x2c01031c, 0x3c3b0104, 0x0a053641, + 0x41473a05, 0x04050940, 0x13210c2b, 0x251a1b41, 0x18111a25, 0x563c1118, 0x2319272f, 0x060a2528, 0x272b2909, 0x63362d1e, 0x24241a45, 0x1919111a, + 0x1c283811, 0x080c010b, 0x0236259c, 0x020b0503, 0x3a231302, 0x1b03a30b, 0x2f34281e, 0x0a2f4444, 0x3737270a, 0x17223027, 0x0308071d, 0x020a0201, + 0x1a182e04, 0x042d181a, 0x36ec8202, 0x01171529, 0x04281718, 0x1e1e0170, 0x07060603, 0x05202003, 0x6b000609, 0xda21053a, 0x05c45001, 0x0f000b29, + 0x17130000, 0x82372707, 0x37072c03, 0x21250701, 0x78522115, 0x82f2793c, 0x3c5a3003, 0xfe3c2e01, 0xff000177, 0x79360100, 0x82f2783c, 0x3c5a3403, + 0x1a3cd2fe, 0x0003002b, 0x012b006b, 0x00d50195, 0x6d20000e, 0x82410558, 0x17162906, 0x35331517, 0x15163226, 0x0a149818, 0x34352622, 0x0806876f, + 0x26222333, 0x3f2e3d01, 0x131b3f58, 0x7c695612, 0x090c4057, 0x400c0980, 0x090c8055, 0xe90c0956, 0x3f2c3720, 0x32172c3f, 0x31310d0e, 0x4e3e57f9, + 0x0c09312c, 0x3b39190c, 0x5b03200c, 0x17270cb2, 0x11250000, 0x48251121, 0x112406ad, 0x21333634, 0x07207a82, 0x29071967, 0xfe111aab, 0x1a1a1180, + 0x05820111, 0x1a675620, 0x290f8406, 0x1919112b, 0x80808111, 0x7d680400, 0x00093308, 0x00280024, 0x13000038, 0x27170733, 0x33273707, 0x4c823737, + 0x21244b82, 0x23152111, 0x4c068a5e, 0x92180742, 0xf9490cee, 0x41ff3e06, 0x35341435, 0x15413514, 0x2a1812c0, 0x150180fe, 0x2bab2b2b, 0x19191295, + 0x6bc00112, 0x84cb836b, 0x40013304, 0x27273e26, 0x5540263e, 0x6b6b1218, 0x2b2b00ff, 0x326d2a2a, 0xfe182805, 0xc0969680, 0x83c0090c, 0x2d04822b, + 0x65000200, 0xa5010000, 0x1c00c001, 0xed822c00, 0x15151631, 0x23060607, 0x27272223, 0x32333637, 0x5a173316, 0x332206a5, 0x0f431732, 0x41072008, + 0x2708058c, 0x10139201, 0x910c1201, 0x116a090d, 0x03010a07, 0x1a134901, 0x08031113, 0x50382b71, 0x2c202a38, 0x1409ad1f, 0x0f0c7104, 0x01361e83, + 0x120ee50f, 0x02800e12, 0x28341c32, 0x35283838, 0x1f16501b, 0xe941161f, 0x0013240a, 0x8235002d, 0x82332081, 0x39ef827e, 0x15373634, 0x14150606, + 0x36323316, 0x17363427, 0x17161533, 0x15331617, 0x404a2722, 0x35232205, 0x08258323, 0x32363456, 0x22061416, 0x072c1201, 0x3e2c243e, 0x18132332, + 0x21151a26, 0x01162a36, 0x241c0607, 0x40323832, 0x6b2a1911, 0x24191a11, 0x80241919, 0x2c3e3223, 0x2c073e24, 0x1a152107, 0x18d11826, 0x03010d1c, + 0x2a271f06, 0x111a4929, 0x111a6a75, 0x181824d9, 0x02001924, 0x22081a58, 0x820d0006, 0x37273393, 0x23153315, 0x07173507, 0x01352335, 0x95555540, + 0x04828095, 0x5555eb25, 0x82562a40, 0x2a40210e, 0x200a9244, 0x06187803, 0x38822720, 0x15213522, 0x200fdf56, 0x06856233, 0x82150721, 0x220386c2, + 0x18fe9501, 0x3710d773, 0x2a2b2b15, 0xeb552b2b, 0x1a5601eb, 0x11d5fe11, 0x01121819, 0x2a1a112b, 0x96200082, 0x45056061, 0x1b200e8e, 0x36326f82, + 0x06333736, 0x26370706, 0x16352726, 0x06271716, 0xe3531406, 0x01240807, 0x07493015, 0x50680840, 0x30490780, 0xea086850, 0x324e4e32, 0x516f6f51, + 0x3048076c, 0xea076950, 0x41074830, 0x7f2b1e82, 0x566c5608, 0x7a084108, 0x58087aa6, 0x19200e56, 0x60866183, 0x1b305f92, 0x6908980d, 0x1c0c284f, + 0xea08694f, 0x111a1a11, 0xc3335d83, 0x6c4d2008, 0x0820ea07, 0x4d6c0798, 0x28220728, 0x85980722, 0x000b285b, 0x01550040, 0x59ab01c0, 0x132208ba, + 0x3b411700, 0x002b2b08, 0x15211300, 0x33351721, 0x03822115, 0xa7180783, 0x0b830bb8, 0xa7183720, 0x402f0ab0, 0x80fe8001, 0x80feabd5, 0x802baaab, + 0x822a802b, 0xea2b2b03, 0xf56af56b, 0x56ab016b, 0x00822b55, 0x0382ab20, 0x56200286, 0x20063f41, 0x5a819004, 0xd04a083c, 0x56ab2a17, 0x9640406a, + 0x2b401616, 0x082d522b, 0x0700802a, 0x2f001400, 0x32240000, 0x39056847, 0x33352727, 0x06222326, 0x32331614, 0x16323736, 0x26220614, 0x35363435, + 0x06670607, 0x33332205, 0x08bf8227, 0x01341729, 0x1f1f2c5f, 0x3d82202c, 0x16270c3d, 0x10161f1f, 0x3828bc1f, 0x01385038, 0x2137062d, 0x28373828, + 0x5e4d2aad, 0x83209556, 0x01052325, 0x2b822520, 0x82801621, 0x2838271f, 0x1b020602, 0x0a822e21, 0x562b2a3e, 0x00020001, 0x01320055, 0x00ce01ab, + 0x00160006, 0x34213700, 0x06072727, 0x14151637, 0x22227182, 0x7c832726, 0x37373308, 0x26000180, 0xf9265a5a, 0x47153232, 0x3215473a, 0xd579151d, + 0x5d5e2637, 0x46324826, 0x1d153247, 0x4732151d, 0x7915461d, 0x2b000500, 0xd5012a00, 0x0782c001, 0x3b003333, 0x4b004300, 0x1e250000, 0x07160607, + 0x26060706, 0x20d98223, 0x22548227, 0x83373636, 0x36372d02, 0x32333633, 0x16173217, 0x36161617, 0x20068f43, 0x20078e26, 0x080f8606, 0x0272012e, + 0x030d040d, 0x0309010c, 0x270b0305, 0x041c5307, 0x2707531c, 0x1114030b, 0x0a210a16, 0x03041312, 0x050c0b06, 0x12130403, 0x1f032209, 0x7f20f883, + 0x9f200584, 0x21080b8a, 0x040d02c3, 0x060e050e, 0x04110710, 0x0a01082a, 0x2a08010a, 0x16122a14, 0x160b280b, 0x01010206, 0x0a820602, 0x202c5126, + 0x751f2c20, 0x08834183, 0x202c1f23, 0x2d118436, 0xab000200, 0x55012b00, 0x0e00d501, 0xd7821600, 0x994b1520, 0x22a08305, 0x87161615, 0x55013bb8, + 0x262a4040, 0x19112634, 0x18241995, 0x56eb2418, 0x1a966a6a, 0x071a2626, 0x23449b26, 0x00042605, 0x01400015, 0x7b4782ea, 0x01280822, 0x27071416, + 0x07273436, 0x06270786, 0x15151632, 0x41343521, 0x2f080715, 0x3e3eac01, 0x232c2c23, 0x0e242020, 0x756cb80e, 0x3256aafe, 0x46323246, 0xab41d501, + 0x8333223e, 0x58232530, 0x2d132420, 0x262faa13, 0x8c262b2b, 0x32241b83, 0x40000b00, 0xc0226882, 0x265ec001, 0x001b3b08, 0x0023001f, 0x002b0027, + 0x0033002f, 0x23150100, 0x23263435, 0x32333523, 0x5d440116, 0x5a332006, 0x148206e7, 0x82071521, 0x2003830b, 0x20078227, 0x35038205, 0x23153307, + 0x262bc001, 0x2c6a6a1a, 0x2b80fe3f, 0x2a2b2b2a, 0x50762b80, 0x2b2b2205, 0x820e8201, 0x6a552805, 0x2b261a6a, 0x43bffe3f, 0x01210533, 0x82078355, + 0x2bab2604, 0x2a2a562b, 0x24328256, 0x0003002b, 0x267d8255, 0x00eb01c0, 0x8222001a, 0x2500218f, 0x2405ea69, 0x37361635, 0x063e5037, 0x12821420, + 0x17070623, 0x071a5e33, 0x17033d08, 0x01270723, 0x974040c0, 0x381a0d07, 0x13101e12, 0x141d1301, 0x861d144c, 0x1a225120, 0x601a221a, 0x204b2b36, + 0x20404040, 0x012e0197, 0x10211319, 0x1a7b141c, 0x11314c14, 0x6b01860d, 0x1a3c1f82, 0x36fafe22, 0x0100204a, 0x80001500, 0x8001eb01, 0x00003400, + 0x23061400, 0x07272223, 0x22075a58, 0x88062737, 0x1834200d, 0x240a7057, 0x17071415, 0x7e571836, 0xeb012807, 0x0701111a, 0x82024c03, 0x37022555, + 0x61060a06, 0x1a2c0983, 0x61030811, 0x1a221901, 0x10033601, 0x01311c84, 0x01192266, 0x1105064c, 0x05111919, 0x02023706, 0x820b8261, 0x011926aa, + 0x11080361, 0x2330831a, 0x4b010136, 0x064c1483, 0x0005270a, 0x01000025, 0xff821715, 0x3723172d, 0x06072626, 0x021e1406, 0x4b373632, 0x2b08051c, + 0x34262722, 0x32363637, 0x01371716, 0x5b0f4a0b, 0x2c3b91d5, 0x1a122c7b, 0x323e241a, 0x2b2b123f, 0x38a03838, 0x4f173838, 0x3a174f42, 0x3b05157c, + 0x2c3c2d6a, 0x3d122b01, 0x1a243d32, 0x3d2b121a, 0x3838374f, 0x17389d37, 0x3c172121, 0x0f714618, 0x27372525, 0x5d152335, 0x5a2308f5, 0x7d206011, + 0xa6250527, 0x806f3a1c, 0x05ec5dea, 0x15000122, 0xeb24a182, 0x2c000002, 0x11200782, 0x20054241, 0x05ce4327, 0x4708f647, 0x078c07fe, 0x33eb0136, + 0x19249b23, 0x07011ba8, 0x5c06070a, 0x15131a13, 0x15121c12, 0x16200782, 0x01380382, 0x23cafe8b, 0x1aab1932, 0xfe340306, 0x0d13130d, 0x120ecb96, + 0xb6cb0e12, 0xb6210b83, 0x21058276, 0xd3420100, 0x00283108, 0x37322500, 0x22230617, 0x35232726, 0x37342633, 0x36310582, 0x16323336, 0x23260717, + 0x33070622, 0x14062315, 0x08058217, 0x01161640, 0x26273340, 0x633e4a36, 0x01414b14, 0x144b4101, 0x4c1e3e63, 0x33272616, 0x7b104823, 0x89020289, + 0x7548107b, 0x48312622, 0x1e062b38, 0x48382b06, 0x2226141d, 0x0e2b1f2c, 0x1f2b0e0e, 0xd775002c, 0x00172609, 0x0037001c, 0x297a824b, 0x23263411, + 0x35331723, 0x61821533, 0x17070636, 0x07172707, 0x27363233, 0x37361717, 0x35363207, 0x15232734, 0x23089148, 0x37173233, 0x4705d745, 0x232107d4, + 0x08f25527, 0x01173708, 0xc1090dcb, 0x611b1f1c, 0x46240f29, 0x2a164214, 0xb20d098a, 0x0d1f1211, 0x03392ed3, 0x20023f64, 0x27271c1d, 0x1c111b1c, + 0x3e2c291f, 0x1157013e, 0xc0111a1a, 0x0683ab15, 0x16953608, 0x092a014b, 0x1b1b510d, 0x4628321c, 0x36424213, 0x1832dc0d, 0x3a732822, 0x2515012e, + 0x1c282013, 0x1b11281d, 0x3e583f1c, 0x111a0001, 0x1a11c0fe, 0x01111a40, 0x82068240, 0x000030d4, 0x01e50100, 0x000700e5, 0x00180011, 0x1800002d, + 0x33088851, 0x16322127, 0x07071415, 0x27330706, 0x14070723, 0x06270705, 0x3421af83, 0x08b68437, 0x3737342d, 0x84372727, 0x221a1a22, 0x01c0e119, + 0x030c091f, 0x6cc70c4c, 0x0113322b, 0x3d1b4c01, 0x1a11150d, 0x119f1e12, 0x2f1d0519, 0x82801b5e, 0x22193f24, 0x090dc085, 0x168a0901, 0x03232b2b, + 0x3d1ba505, 0x16111912, 0x111a1d0d, 0x63350a0a, 0x48181b5e, 0x18330a5d, 0x00002600, 0x34363225, 0x07222326, 0x27331527, 0x6b333636, 0x272305ff, + 0x78161623, 0x00360e4d, 0x2c3f3f2c, 0x551b203a, 0x13270822, 0x1f2c2c1f, 0x0c251627, 0x5a784c35, 0x82802009, 0x1c312cf9, 0x18102255, 0x202c3e2b, + 0x1801231d, 0x300e3447, 0x01060000, 0x00db01d5, 0x00140011, 0x00200018, 0x069f4100, 0x33270722, 0x0731c918, 0x2733173d, 0x15233517, 0x27070103, + 0x27110723, 0x1911ab01, 0x69951118, 0xaba91594, 0x822b297e, 0x65240800, 0x7a1bba01, 0x012b55c0, 0xff1119d5, 0x01191100, 0x2b152b95, 0x2bc07e29, + 0x012b2b6b, 0x1b46fe06, 0x6a01557a, 0x2a059a4c, 0x01950140, 0x000700c0, 0x821d0013, 0x1533336a, 0x37333521, 0x07170733, 0x37173717, 0x07273727, + 0x48180727, 0x4b2b0946, 0x4ad6fe4a, 0x2e816a16, 0x862d1e2d, 0x18532002, 0x200b5248, 0x261886bd, 0x2e2e1e2e, 0x820001b6, 0x1a1a2179, 0x0abe5518, + 0x17000724, 0x9a180000, 0x1725072c, 0x11070617, 0x3ac58223, 0x27261123, 0x01321637, 0x1a1a2211, 0x0b8a1a22, 0x2a2b4e32, 0x0b324e2b, 0x4101ce4e, + 0x1a2d05a7, 0xfe070e2b, 0x018080eb, 0x2b0e0715, 0x0e284a15, 0x4f001521, 0x252210b7, 0x40180717, 0x37250ff9, 0x1e6aab1e, 0x0c8e4f4c, 0xab1e0625, + 0x824c1e6b, 0x006b214d, 0x21070241, 0x4d82000b, 0x02410120, 0x33152207, 0x22fa9135, 0x8bd5aa8a, 0xd58022f0, 0x870f82d5, 0x059a75e7, 0x0500d126, + 0x00000b00, 0x083a4818, 0x01170733, 0xfe5aa601, 0x5a5ab4b4, 0x1e5af2f2, 0x01100178, 0x230e85d1, 0x1d59f2b6, 0x00210e82, 0x21818501, 0x8d82c001, + 0x2113002c, 0x01402115, 0x0180fe80, 0x19822bc0, 0x1b828020, 0x6b008022, 0x37201983, 0x80251982, 0x00ff0001, 0x058a566b, 0x0c944b18, 0x07352323, + 0x07224533, 0x4868f52f, 0xb04d4a6a, 0x7db07d7d, 0xd086d055, 0x374218fa, 0x0655630f, 0x33353723, 0x27368235, 0x15231537, 0x36371533, 0x6306426a, + 0x8b200d44, 0x820e6263, 0x00552f87, 0x0195012b, 0x001600ca, 0x002e0026, 0xf64d2500, 0x22232705, 0x23373726, 0x2a472707, 0x020f2105, 0x33284d85, + 0x14062215, 0x35363216, 0x08083548, 0x19116b3a, 0x1a176b2a, 0x0e2f270a, 0x1d0b0e29, 0x0a1a186f, 0x583f1824, 0x1a2c3f3f, 0x26342626, 0x18241940, + 0x1ae02418, 0x296b7511, 0x0c215715, 0x15281a26, 0x3e2c4b4e, 0x2b3f583e, 0x26311e82, 0x1924f81a, 0x00192419, 0x002b0002, 0x01d50115, 0x209082eb, + 0x6e84821b, 0x33231247, 0x83153335, 0x05625803, 0x2a096a7a, 0x2ad62a16, 0xfe150140, 0x6e8001eb, 0x2b200bbc, 0x4c820082, 0x1805a05b, 0x210d3d86, + 0x01841521, 0x080e0f56, 0x6b2a2b2d, 0x01002a2b, 0x6b004b00, 0x9501b501, 0x00000900, 0x33273737, 0x07171732, 0x674b2306, 0x0d16ea67, 0x160d5d5d, + 0x1295956b, 0x42128383, 0x06240a68, 0x18001000, 0x3322b382, 0xa1820727, 0x46212721, 0x262205ac, 0x7b430135, 0x01172805, 0x55552a2b, 0x42ab562a, + 0x153c0768, 0x164ad6fe, 0x56d5166a, 0xffeb5556, 0x1a1a1100, 0x2b400111, 0x0015152b, 0x002a0005, 0x28050442, 0x0015000a, 0x0025001d, 0x2b56822f, + 0x26373632, 0x15062223, 0x34271615, 0x07240984, 0x12171616, 0x21058741, 0x07861634, 0xbf442720, 0x263d0805, 0x00013634, 0x1e135735, 0x06411d34, + 0x0f192828, 0x0e0f441b, 0x2a15263a, 0x1d2a1e1e, 0x1818225f, 0x58761822, 0x59587d7d, 0x3d557d7d, 0x14191830, 0x23580157, 0x11130516, 0x010c3826, + 0x22238213, 0x82042a1d, 0x22182523, 0x7db07d9f, 0xe5820282, 0x5b004032, 0xa501c001, 0x09000600, 0x00001100, 0x11231701, 0x29080182, 0x27073507, + 0x15071537, 0x01271517, 0x2a2b4080, 0x2a6b6b2b, 0xeb2f2feb, 0xfe40a501, 0x9d0a01f6, 0x65102850, 0x146a142c, 0x4286652c, 0x4289b520, 0x33273723, + 0x2a018211, 0x37273337, 0x23272317, 0x84372307, 0x89582041, 0x405b2c33, 0xf6fe0a01, 0xea2a6b65, 0x82ea2f2f, 0x00372640, 0x019e0140, 0x228387ae, + 0x82372325, 0x2737243a, 0x82373717, 0x82272085, 0x30013503, 0x1fbd1e5a, 0x38231ebc, 0x1f5f2a2f, 0x1f2f4b13, 0xbd1e40ed, 0xbb2a0182, 0xed126838, + 0x144c2f1f, 0x47825e20, 0x47824920, 0xa601b722, 0x1520cb88, 0x27283b83, 0x27273707, 0x07270717, 0x01210382, 0x223382b7, 0x89ba1ebc, 0x39012135, + 0x14825982, 0x3038242a, 0x14205e29, 0xee202e4c, 0x87111441, 0x371529d1, 0x37350717, 0x17352735, 0x850b1341, 0x0d1241cd, 0x89826b20, 0xc001b522, + 0x0722d188, 0x01822135, 0x12412720, 0xb5012109, 0x8b0f4841, 0x18378252, 0x2307af4e, 0x000f0007, 0x20059e50, 0x09e44d4c, 0x08987018, 0x51830720, + 0x18083956, 0x4308a0aa, 0x042005d6, 0x51063c42, 0x233706e9, 0x27153315, 0x37352307, 0x35352622, 0x01333634, 0x0c0c12a2, 0x839e0d12, 0x1e0c2c05, + 0x1516c516, 0x0d06091e, 0x84ab0806, 0x1f013c05, 0x10991005, 0x0d12c2fe, 0x800c120d, 0xc02b261a, 0x162a2b6b, 0x26261a16, 0x840cab1a, 0x33058432, + 0x07404074, 0x0a067558, 0x1a1a060b, 0x060a0b06, 0x6b0e5875, 0xe22a1884, 0x2b161a26, 0x2c016b95, 0x31821516, 0x00261a29, 0x00550001, 0x62ab01ab, + 0x352d066a, 0x21350717, 0x55560135, 0x01fffe55, 0x05c65015, 0x2a000337, 0xeb011500, 0x0300d601, 0x20001200, 0x35010000, 0x15051523, 0x25ac8201, + 0x16363317, 0x04821515, 0x27071323, 0x82bf8621, 0x2c012bfa, 0xfe000157, 0x561218d7, 0x02821812, 0x1b152808, 0x12b2fe2c, 0x0e121818, 0x80011b3a, + 0xdc2a2c2c, 0x12072b01, 0x18010118, 0x19012c12, 0x2c1bc8fe, 0x12ea1219, 0x5b1b3a19, 0xd5260835, 0x1d001900, 0x6a822100, 0x200e0361, 0x21748233, + 0x14833333, 0x21150524, 0x88822735, 0x5cab0121, 0xff270f1e, 0x80560100, 0x5c800156, 0x2b300f78, 0x2b2beaea, 0x0006002b, 0x01550095, 0x00ab016b, + 0x2007a44d, 0x05a84f27, 0x180d2f70, 0x1807a06c, 0x4510d3ee, 0x32250592, 0x1a222f01, 0x2002871a, 0x2008843c, 0x20118abc, 0x201b8456, 0x8a8a18ab, + 0x843c2010, 0x84662011, 0x84802005, 0x1132622f, 0x450b415b, 0x395b0a2d, 0x80802106, 0x630ac260, 0x25080563, 0x23273733, 0x37211717, 0x17322127, + 0x8b060717, 0xb54b4bb5, 0x00ff6b4a, 0x00016060, 0x5d5d0d16, 0x6b6b950d, 0x4145956b, 0x61052006, 0xe66712dc, 0x15332305, 0x174e1523, 0x1501250a, + 0xabd5abab, 0x8d520085, 0x0a226205, 0x240dea4e, 0x0031002b, 0x0fea4e00, 0x07012724, 0xed4e1627, 0x32332406, 0x4a17031e, 0x17250869, 0x16323327, + 0x0cfa4e15, 0x6501e73c, 0x03023f1b, 0x3675aafe, 0x1d1f1b0b, 0x155c0b1c, 0x0d322318, 0x0459d538, 0x0c4f3223, 0xfe563d10, 0x053f1b9b, 0x2b2b050a, + 0x06032f26, 0x5c070c08, 0x1823320d, 0x59693815, 0x03002332, 0x8023e082, 0x4601c001, 0x3728087d, 0x25152135, 0x17211521, 0xc02b0782, 0x80fe0001, + 0x80fe8001, 0x19000180, 0x20087e0d, 0x2a318203, 0x01ab012b, 0x001300d5, 0x18230017, 0x081d5393, 0x3507063b, 0x34262223, 0x33400b01, 0x192b3246, + 0x18141a22, 0x362b2b14, 0x4d5e6b96, 0xeb6a4b0b, 0x231b3817, 0x11233333, 0x0e111a1a, 0x17210e16, 0x012b2b4b, 0x494b6a35, 0x6a402587, 0x9d441896, + 0x0007270c, 0x0015000e, 0x99821300, 0x212b9882, 0x33270725, 0x03153335, 0x6c231737, 0x01260ba1, 0x40555500, 0x04836a2a, 0x2b00012b, 0x56962b6b, + 0xfe404056, 0x210f82c0, 0x1b820040, 0x01550027, 0x00ab01ac, 0x21478216, 0x8b563526, 0x07162206, 0x087b4407, 0x065b263d, 0x2a01090d, 0x06010d09, + 0x2b090c7b, 0x01780d09, 0x09070787, 0x06090d0d, 0x83809d07, 0x99802107, 0x0ae94318, 0x0d000929, 0x00001100, 0x83331501, 0x3723238d, 0x9d822517, + 0x03821120, 0x26050c44, 0xff555540, 0x6d560100, 0x0124053b, 0x55558040, 0x95240282, 0x2aaafe2a, 0x2806ba43, 0x00c001c0, 0x00130008, 0x2a8f8217, + 0x27070137, 0x37352307, 0x18151625, 0x3f0750ee, 0x07173707, 0x56012a2b, 0x5078782b, 0x06020178, 0x27502706, 0x85061206, 0x01295029, 0xabfe2b95, + 0x80251784, 0x06080906, 0x21188228, 0x17826706, 0x4e050021, 0x0a370817, 0x20001a00, 0x34003000, 0x27250000, 0x35072337, 0x35331523, 0x63352717, + 0x15200651, 0x84055163, 0x10625516, 0x15331730, 0x30a00123, 0x20262530, 0x0c662620, 0xfa833509, 0x0c093527, 0x01204075, 0x09805b15, 0x20206a30, + 0x304040c0, 0x30308030, 0x0c095615, 0x0483090c, 0x20800c25, 0x5b000160, 0xa0230b97, 0x88070040, 0x82032096, 0x001928ef, 0x00370025, 0x824b0047, + 0x2069829a, 0x20938e37, 0x24a98227, 0x35173315, 0x05c76633, 0x51232321, 0x2222069e, 0xc2821506, 0x20056049, 0x0e1a5c13, 0x4b27b184, 0x0c152020, + 0x82093609, 0x25048289, 0x2020408b, 0xb9832a76, 0x0c2b4a2b, 0x0d096009, 0x15201620, 0x26bd89b5, 0xd52020b5, 0x83556b20, 0x82552020, 0x20742532, + 0x0d209660, 0x0c22ea82, 0x0e826b80, 0x606b0927, 0x01604040, 0x23c88b4b, 0x06004055, 0x0928c88a, 0x1b000f00, 0x3d002d00, 0xb684c686, 0x0120bcb3, + 0x0a20b882, 0x6a20ad82, 0x60200382, 0xd525b19a, 0x6020d620, 0x8ca7a180, 0x001828a5, 0x002a001e, 0x854c003c, 0x413520a5, 0x33220854, 0x51412315, + 0x35232105, 0x092bb4b7, 0x4b090c0c, 0x0c092b40, 0x414b4060, 0xd52f1e6d, 0x090c8b20, 0x200d0920, 0x35090c16, 0xae4b1520, 0x001528c5, 0x0027001b, + 0x42490039, 0x15200b32, 0x0385c282, 0xb7363221, 0x841520c2, 0x402b24c1, 0x420c094b, 0x2d421f30, 0x16202505, 0x0c201515, 0x41222d42, 0x11280c85, + 0x23001700, 0x45003500, 0x2323bf87, 0x83152335, 0x15332203, 0x387e4133, 0x20152a26, 0x20402020, 0x7628b7a1, 0x40404020, 0x60202060, 0x203f7541, + 0x076e4123, 0x34353524, 0x38422326, 0x60152939, 0x094b4040, 0x2b090c0c, 0x2a213742, 0x154b20b6, 0x20090c20, 0x82160c09, 0x1fa343c1, 0x2a0c6a44, + 0x001d0017, 0x003b0029, 0x414f004b, 0x27200577, 0x29085344, 0x23353335, 0x15150622, 0x39421614, 0x076e4433, 0x84363621, 0x20cb84c4, 0x1e014337, + 0x2020b525, 0x865620d5, 0x090d24c8, 0x430c0955, 0x802122ca, 0x0c464220, 0x12000c28, 0x30001e00, 0xce864000, 0x26363727, 0x33152323, 0x2cc3b307, + 0x20204b01, 0x0c031f0b, 0x1d384b0b, 0x82bb9e46, 0x0b6422b8, 0x257c4411, 0x22450820, 0x00072a0a, 0x001b000b, 0x002d0021, 0x0882413f, 0x20063449, + 0x42f54533, 0x2b21c283, 0x45008220, 0xd52729f5, 0x2020a020, 0x45202035, 0x53422bf7, 0x820f200c, 0x002722ce, 0x20d0892b, 0x26c88417, 0x33353315, + 0x88073632, 0x070950d4, 0x33150322, 0x17201a82, 0x1520f483, 0x42087c42, 0x33210578, 0x778a1833, 0x3411230c, 0xd0833336, 0x090d4028, 0x092a204a, + 0xb4468b0d, 0x204b2608, 0x40204b20, 0x06d7464b, 0x2b090c22, 0x0a88ac18, 0x0a20d529, 0x800c0935, 0x462d0d20, 0x162a0ab5, 0x36806020, 0x202a2020, + 0xe784090c, 0x0c092024, 0xc9469515, 0x0300210b, 0x2408a441, 0x0010000a, 0x0c234820, 0x47059644, 0x012c0f61, 0x25303075, 0x25202025, 0xd5204070, + 0x48094547, 0xf5470700, 0x04002110, 0x0b266288, 0x1c001600, 0x64822c00, 0x0a104d18, 0x48330721, 0x84480895, 0x2a709005, 0x201520a0, 0x265b1520, + 0x82263030, 0x40402377, 0x7689f520, 0x2016f523, 0x20028220, 0x067e4835, 0x71487d91, 0x00182a0b, 0x00340028, 0x00560046, 0x0637435a, 0x41130447, + 0x9a4105c7, 0x36322207, 0x34804807, 0x0d097625, 0x474a090d, 0xca200513, 0x20093949, 0x1ad6472a, 0x2020ca22, 0x420e1d47, 0xa220099d, 0x472f9248, + 0x27260cec, 0x33153315, 0xed950735, 0x222b5e49, 0x83204b01, 0x47802000, 0x8b200af0, 0xa848d19a, 0x474b2005, 0xcb200bf0, 0xe644c89e, 0x0018280c, + 0x0039002d, 0x415b004b, 0x372005ae, 0x2320c093, 0x344a1493, 0x20d5832d, 0x82d28515, 0x406022cc, 0x0abb4160, 0xde9ca020, 0xb80ccb48, 0x001528e6, + 0x0036002a, 0x48580048, 0xe3c518d4, 0x090c2a2b, 0x2a2a404b, 0x0c094b40, 0x23e2a8a0, 0x0d09556b, 0x2005eb48, 0x28e0b829, 0x00260011, 0x00440032, + 0x14f54854, 0x4026dcc5, 0x20202016, 0xd8a92040, 0x20070c49, 0x45d6ac15, 0x1f220b30, 0x30452f00, 0x9327200c, 0x664618c9, 0x8001210f, 0x20064f4d, + 0x0a824186, 0x0a4eaa18, 0x2d074845, 0x20090d35, 0x15200c09, 0x2035090d, 0xb445cb15, 0x0d51450c, 0x3b002b22, 0x4d185145, 0x152005e6, 0x180ae24b, + 0x271382da, 0x201620ab, 0x255b1620, 0x2005d845, 0x08b74440, 0x0d092a23, 0x176a45ca, 0x9c891b20, 0x8cbe0d21, 0x097a4e9d, 0x18000328, 0x36002400, + 0x6d454600, 0x2f7f441c, 0xa9432b20, 0x4356200a, 0x7844299d, 0x0bd94120, 0x4f05a546, 0x674c0f2e, 0x18d6410b, 0x090d702b, 0x2b2b404a, 0x0d094a40, + 0x111e47aa, 0x0956152a, 0x1615200c, 0xf40c2015, 0x410c3441, 0x28220dd2, 0xd2413800, 0x418aac0e, 0x362005cf, 0x2105ce41, 0x90896525, 0x2018cd41, + 0x41979730, 0x15260bcc, 0x33002100, 0xcc414300, 0x34352306, 0x064c2326, 0x82152006, 0x36322107, 0x20317345, 0x098f4416, 0xc8411620, 0x0983441c, + 0x481f0747, 0x24220e6d, 0x48413400, 0x0b7b4d1a, 0x4110cf41, 0x50200d44, 0x4105624d, 0x20201940, 0x20065a4d, 0x0cd641e0, 0x260b3e41, 0x001d000f, + 0x413f002f, 0x1520053e, 0x200a5448, 0x050d4937, 0x47233521, 0x3a4a05a5, 0x10104910, 0x20204b22, 0x20052e41, 0x50958515, 0xd52214d6, 0x6a474020, + 0x86b62006, 0x50b6209a, 0x054a17cf, 0x11fa420c, 0x410fec4d, 0xd144102a, 0x60702907, 0x094a4040, 0x2a090d0d, 0x2012cf44, 0x07be4d60, 0xa0150d22, + 0x420c2341, 0x8a8f2bfa, 0x4110196e, 0x65200db5, 0x01219088, 0x17c8440a, 0x98983020, 0x8f1afb42, 0x32fb4287, 0x4408f94e, 0xf54e1dc3, 0x49f6200a, + 0x49411f3a, 0x000a2609, 0x002e001e, 0x0d9d4632, 0x2007e84e, 0x08714533, 0xca413520, 0x3317230f, 0xa0462315, 0x4b702308, 0xb94a0c09, 0x0bd04106, + 0xed534020, 0x20602109, 0x2205eb53, 0x41092009, 0xcb210ed5, 0x0a825420, 0x16000b28, 0x3a002a00, 0x8b433e00, 0x09704b1b, 0x41065350, 0x9b840fdb, + 0x8a0edf41, 0x0be141a1, 0x20202022, 0x9c0e184c, 0x0bcc53a9, 0x9e510f20, 0x43492006, 0x345011a7, 0x092c4c13, 0x4307e84d, 0xb6840fad, 0x2c08b143, + 0x0c093540, 0x402b090c, 0x0d0d094a, 0x138d541e, 0x20208a22, 0x2009b943, 0x0b255096, 0xbe439620, 0x20802117, 0x200cc043, 0x55c18213, 0x23200bea, + 0x8f071c50, 0x08e84199, 0x031f9028, 0x384a0b0d, 0xaf46f01e, 0x0a642211, 0x0fc65512, 0x490e6245, 0xd04d0504, 0x09ab460b, 0xbb6b7a88, 0x4101200f, + 0x85200dc7, 0x01218086, 0x18a54310, 0xa0438893, 0x000c260b, 0x002a0018, 0x05b5413a, 0xf2872720, 0x20319743, 0x248a8236, 0x1d384b0a, 0x1c90465b, + 0x0b645623, 0x22435311, 0x200d8557, 0x1292432a, 0x430d8557, 0x1520138e, 0x220c9243, 0x4335090d, 0x5c480694, 0x2040210a, 0x81570082, 0x0c614811, + 0x16209522, 0x260b4252, 0x0016000b, 0x43360026, 0x9da61e94, 0x200dcc41, 0x47a38965, 0xa1820a2e, 0x58109443, 0xaa91092c, 0x260d2958, 0x0031001f, + 0x55450041, 0xbd5807f6, 0x2de6410f, 0x2e561720, 0x4b012406, 0x4f162020, 0x8248099a, 0x838a201b, 0x0b2558be, 0x231f8748, 0x2015204b, 0x450a2843, + 0x5e41158f, 0x0543490b, 0x43130042, 0x702008a6, 0x4a065841, 0x90450f5b, 0x0551410a, 0x0d092022, 0x200f604a, 0x2f8f4595, 0xfa419ba6, 0x41a18415, + 0x8f450dfc, 0x45a89b0e, 0x2d570b8e, 0x068e4507, 0x4a0df841, 0x8e453377, 0x07f84107, 0x4b402a24, 0xfa410c09, 0x07f8411e, 0x0c092025, 0x410c2015, + 0x002121fa, 0x08c77a01, 0x0000152b, 0x23352301, 0x33353315, 0x82078215, 0x82232009, 0x270d8209, 0x2b95d501, 0x5595952b, 0x80290382, 0x40150195, + 0x40ab40aa, 0x220382d5, 0x84050040, 0x01eb2f3c, 0x001200c0, 0x0022001e, 0x002a0026, 0x63182500, 0x21240d1e, 0x01112115, 0x53845182, 0x07204d82, + 0x37200b82, 0x27200382, 0x01210382, 0xf0cd1880, 0x00012808, 0x560100ff, 0x822b4040, 0x2bd63602, 0x2a2a562b, 0x6b2b2bab, 0x1a116a6a, 0x2a01111a, + 0xfe2b1a11, 0x84aa82d6, 0x55d5261f, 0x00959555, 0x0aab5302, 0xba822e20, 0x09628518, 0xd87c1520, 0x26222107, 0x22084d60, 0x18161714, 0x210c70a2, + 0x6984c001, 0x0c092b23, 0x9b81190c, 0x62a21808, 0x8499820b, 0x0ccb276b, 0x0c094b09, 0x278396d5, 0x0f40a118, 0x5c658183, 0x820b2005, 0x250021fd, + 0x152ce187, 0x06071533, 0x26260706, 0x17373535, 0x263c7582, 0x15062223, 0x2a950114, 0x402a4040, 0x051302bb, 0xc0c06e52, 0x35201a06, 0x3f3f554b, + 0x3730ef83, 0x14010701, 0x56805993, 0x1d1b8056, 0x2b354b0e, 0x280a2447, 0x0019000f, 0x25000029, 0xbe401833, 0x33352907, 0x36321614, 0x15213537, + 0x35210884, 0x0e416137, 0x80400122, 0x2705b34a, 0x26342680, 0x55d6fe55, 0xab460683, 0x40ab2109, 0x40260b83, 0xaf26261a, 0x05825555, 0x2d821a20, + 0x12839520, 0x275e0482, 0x00062a0a, 0x001c0018, 0x34370100, 0x20bc8226, 0x21638236, 0xd96e3307, 0x33332407, 0x82133427, 0x0001227f, 0x325b8240, + 0x6b3f5814, 0xfe1a1180, 0x80111aaa, 0x00ffeb6b, 0x83561501, 0x3e6a2f56, 0x1119962c, 0x19118080, 0xe9fe2c96, 0x5b822b2b, 0x1500152c, 0xeb01eb01, + 0x14000c00, 0xd2821f00, 0x2727362c, 0x06070726, 0x16171714, 0x31710237, 0x05343505, 0x35071735, 0x35231523, 0xa5013334, 0x0d990e0e, 0x0505990c, + 0x6e360582, 0xc48989c4, 0x4a160189, 0x152a564a, 0x9a0a0ef4, 0x089a0a0a, 0x06820808, 0x82910121, 0xc4892c18, 0x4a4b3537, 0x16554035, 0x87000200, + 0x00052267, 0x2365820d, 0x17072737, 0x01345e88, 0x5454084c, 0xc2614c08, 0x8ac28a8a, 0xcece0895, 0x34012208, 0x8a210a82, 0x203782c2, 0x209f8240, + 0x209f82c0, 0x6afb820a, 0x272b054d, 0x36341107, 0x34110133, 0x7f232326, 0x2c08061b, 0x11400111, 0x1a95961a, 0x192a0111, 0x111ad611, 0x011a11d5, + 0xfe111995, 0x014040aa, 0xfe191156, 0x111501eb, 0x1a1a111a, 0x00abfe11, 0x208a8407, 0x205282ea, 0x068b6203, 0x24001c28, 0x00004c00, 0xe1823301, + 0x4f640382, 0x57b31807, 0x16162515, 0x07061415, 0x1f57b318, 0x40013623, 0x2000822b, 0x59b31817, 0x4a572a17, 0x090c1635, 0xaa0d0915, 0x2f05820d, + 0x5358160c, 0x13041204, 0x2b2b0147, 0x3e556bab, 0x1458b318, 0x3d580125, 0x18085635, 0x211459b3, 0x586a261b, 0x000a220a, 0x21cf8214, 0x50181300, + 0x2520090b, 0x2508114e, 0x33373523, 0xb5421517, 0x55260809, 0x12195601, 0x1812d5fe, 0x070e2a01, 0x2b0d0840, 0x552b6a2b, 0xeafe1119, 0x40011911, + 0x181812eb, 0x1540eb12, 0xa3820e08, 0x2a2a2b29, 0x1911eb2b, 0x8aeb1119, 0x0013296a, 0x00210019, 0x27352500, 0x03836182, 0x15062224, 0x03820615, + 0x16150727, 0x23353632, 0x864e1814, 0x6b2c0808, 0x0c1f2116, 0x211f0c12, 0x121c5d16, 0x7db03840, 0xab7db07d, 0x23381515, 0x090a0734, 0x0a090d0d, + 0x38233407, 0x13361515, 0x4d010d0d, 0x7d241b82, 0x000400b0, 0x26079574, 0x002f0017, 0x4543003f, 0x14200a09, 0x07c54a18, 0x2005db70, 0x07214507, + 0x0d47178e, 0x21052c0f, 0x80012111, 0x202b2b20, 0x8340090c, 0x09402376, 0x0e83950c, 0x0e820d20, 0x13840c20, 0x2f061549, 0x12191912, 0xc0fe3501, + 0x15014001, 0x160b400b, 0x21079460, 0x0d8c1609, 0x8206186d, 0x1200262b, 0xeafe2019, 0x39761800, 0x00c03507, 0x000f0007, 0x00180014, 0x1300002c, + 0x23151632, 0x15232634, 0x9a18078b, 0x3a08178b, 0x1f644755, 0x3f2c3a52, 0x121f2d1f, 0x6b012b19, 0x800180fe, 0x19011a11, 0x6baa6b11, 0x111a1a11, + 0x46645501, 0x3e21513a, 0x222d1f2c, 0x01161218, 0x0100ff00, 0xff111a2b, 0x19191100, 0x4508c257, 0x133b0b85, 0x27250000, 0x27072737, 0x17071707, + 0x17111737, 0x27230715, 0x6b013735, 0x871b5050, 0x70702502, 0xb07070a0, 0x0121108a, 0x2111832b, 0xaa4b70a0, 0x620f200c, 0x25210561, 0x09374615, + 0x0a822120, 0x36461320, 0x40402908, 0xfe40402b, 0xd5ababeb, 0xeb200284, 0x2b2a0e83, 0x8001ab40, 0x00ababab, 0x00820003, 0x01eb012f, 0x000200da, + 0x00250017, 0x27333700, 0x0b6b7917, 0x27354f08, 0x17041637, 0x14370717, 0x27232306, 0x27211133, 0x15163221, 0xfed3d340, 0x2aaa2a13, 0x151a1195, + 0x0001181a, 0x2d1c6543, 0x2b15111a, 0x2bc0fe40, 0x1a116b01, 0x2bfed3ab, 0x1a2b2a2a, 0x1c15fe11, 0x6444fe18, 0x1a11ab1c, 0x2a00012b, 0x46181119, + 0x082d0a15, 0x1e000c00, 0x17010000, 0x23372707, 0x78778235, 0x6a18060d, 0x172e0c30, 0x55550001, 0x5858221f, 0xaafec921, 0x736b5601, 0x2b802f09, + 0x55564001, 0x222b221e, 0x01d5d5a2, 0xaa181a00, 0x51180b8e, 0x08220b3c, 0xd5821400, 0x33373008, 0x27372515, 0x16011507, 0x23070714, 0x36373635, + 0x55eb1732, 0xb9c4fe80, 0x1e01b81a, 0x56f30d0d, 0x220d03f0, 0x5656550d, 0xb91ab92b, 0x8204011a, 0x57f3250c, 0x0d0d03ef, 0x3721b091, 0x24b18237, + 0x07352315, 0x21b09417, 0x958255ab, 0xe2222a22, 0xea28ae8f, 0x221e5656, 0x4c225959, 0x0220ae90, 0x08e06018, 0x15000722, 0x0d49a218, 0x70141521, + 0x363f0591, 0x406b0133, 0x11809696, 0x545b8019, 0xc0597c7b, 0x802b2b80, 0x1119ea2b, 0x7c7b5aab, 0x46805b53, 0xd5300632, 0x3700d501, 0x70003a00, + 0x14010000, 0x07141507, 0x0625ed82, 0x06060714, 0x84018207, 0x27220802, 0x36270737, 0x37323736, 0x053e3532, 0x3f363633, 0x36373202, 0x36323333, + 0x05163233, 0x01272737, 0x2d822707, 0x22072228, 0x07070615, 0x03822206, 0x23062322, 0x22240282, 0x37343526, 0x36230282, 0x82373735, 0x3634213f, + 0x42080684, 0x36353632, 0x01273736, 0x020201d5, 0x01010103, 0x05020104, 0x01020501, 0x406f0105, 0x08016f8a, 0x02020101, 0x05030402, 0x02020604, + 0x0c07030a, 0x05080403, 0x040c0307, 0xabfe7d58, 0x01904a8a, 0x853b1ca0, 0x100a2224, 0x2934820f, 0x0803040c, 0x0e060605, 0x37827d58, 0x01020323, + 0x20508203, 0x20058203, 0x2a518301, 0x0e00013c, 0x08050606, 0x820c0403, 0x0b03272a, 0x020a0602, 0x3e82020a, 0x408a6f23, 0x2011826f, 0x216c8402, + 0x2f820402, 0x0203022d, 0xd87d0102, 0xfec64a40, 0x843c1b60, 0x0507241b, 0x84010106, 0x0d582a16, 0x08050706, 0x070c0304, 0x223e8203, 0x82060207, + 0x01042101, 0x23084782, 0x0002003b, 0x0155006b, 0x00ab0195, 0x00090005, 0x37273700, 0x01173717, 0xcd211521, 0x9e382a62, 0x01d6fe2a, 0xba280382, + 0x9e372862, 0x2b00ff2b, 0x08584718, 0xa179c020, 0x821f2008, 0x23072334, 0x03821737, 0x03873720, 0x08822120, 0x33032322, 0x33310582, 0x23072313, + 0x078007bf, 0x06800672, 0x0655076d, 0x31038263, 0x1714016c, 0x2a370f39, 0x099b0932, 0x0f372b32, 0xd149eb38, 0x2a552d07, 0x60972b2a, 0x3737eefe, + 0x00601201, 0x430f775f, 0x1b2d05f7, 0x00001f00, 0x15233525, 0x23153327, 0x20078613, 0x260f8e07, 0x2b559501, 0x8380abab, 0x88552004, 0x556b2609, + 0x01ab8055, 0x20058300, 0x6f0a89aa, 0xd520088c, 0x1f220982, 0xcf822700, 0x01215882, 0x07587106, 0x07063533, 0x23151506, 0x36373435, 0x36373233, + 0x06333535, 0x05137822, 0x40553c08, 0x02400140, 0x2a2b272c, 0x1e04092b, 0x3b2d2d2a, 0x2a211d2d, 0x1a1a2284, 0x80ab1a22, 0x452fa201, 0x80defe0c, + 0x0403fe80, 0x0b0b2a18, 0x1625273f, 0x550a2f1b, 0x1919221a, 0x18010022, 0x2408e651, 0x01000008, 0x06c37117, 0xab00012d, 0x016b806b, 0x00ff80c0, + 0x82019595, 0x2b002718, 0xab011500, 0x9567d501, 0x55212005, 0x8c820559, 0x2335333b, 0x01353335, 0x2bd5feab, 0x2b802ad6, 0xd50155d5, 0x6b552b80, + 0xab40abab, 0x6147182a, 0x00c52208, 0x26378405, 0x32332707, 0x6b012517, 0x373407a3, 0x40d50127, 0x0d16aaea, 0x6b01cdfe, 0x00ff2a1b, 0x220d1a11, + 0xea2c8f82, 0x96fe4212, 0x11192b1b, 0x220d11d6, 0x350a5c47, 0x000e0008, 0x1300001e, 0x21152111, 0x11352622, 0x07273717, 0xd2460727, 0x01552f0f, + 0x11d5fe2b, 0x1e8bdf19, 0xeb1e2c6d, 0x46181911, 0x802e089d, 0x192ad5fe, 0xab2b0111, 0x2c6e1e8d, 0x4618b51e, 0x6a180cb5, 0x0d220938, 0x62831600, + 0x6a183320, 0x15210918, 0x07254517, 0xabab5522, 0xab2d4f83, 0x1e6a6a6b, 0x37d9d937, 0xd6fe9501, 0x06f74b2b, 0x6b6b2a26, 0x382a371f, 0x201b2b42, + 0x06174601, 0x5a4c2720, 0x8237200a, 0x1117320b, 0x21031121, 0x40012111, 0x2a552b2b, 0x2b2b562a, 0x230284ab, 0xaa2a2a56, 0x07ce4b19, 0x832a1521, + 0x05087900, 0x2a01d528, 0x5501d6fe, 0xa76c80fe, 0x00052c0a, 0x00230015, 0x07350100, 0x4b171527, 0x37300f6b, 0x15072723, 0x35352622, 0x17373734, + 0x8bab0116, 0xc8830082, 0x83eafe21, 0x38fd3705, 0x19118b7a, 0x0fa1a411, 0x47240701, 0x95472447, 0x11c01119, 0x04821a1a, 0x4016192e, 0x111acd49, + 0x510815a7, 0x04000951, 0x2108d06a, 0xa0690005, 0x25230806, 0x17372707, 0x15212507, 0x33351521, 0x21350715, 0x1ec00115, 0x4c1e6b6b, 0x1501ccfe, + 0xd5d5ebfe, 0x83b31501, 0x184d200f, 0x83089fb7, 0x01402444, 0x82c001c0, 0x000f24bc, 0x83310021, 0x553a83b4, 0x15210842, 0x0b8e6827, 0x34353324, + 0xe3412326, 0x5301200f, 0xa02008fd, 0x22057c68, 0x51090c20, 0x01240abd, 0x40202000, 0x36251282, 0x80800c09, 0x056f680c, 0x0b826b20, 0x260e2457, + 0x01150055, 0x82eb01ab, 0x00132588, 0x0024001c, 0x143d6a18, 0x23133108, 0x11352622, 0x27331133, 0x37360722, 0x01071735, 0x11abab80, 0xab111a1a, + 0x11191911, 0x1a11d580, 0x321ed52b, 0x343e0e1a, 0x0001ab34, 0x400100ff, 0x3405127f, 0x2b011119, 0x2afe1a11, 0x5501111a, 0x23e5abfe, 0x301c0942, + 0x0ac15530, 0x07000328, 0x0f000b00, 0xff821300, 0x42061742, 0xab220f0b, 0x02422b2b, 0x2b6b210b, 0xfc410083, 0x00042809, 0x01270015, 0x82d501eb, + 0x002224bc, 0x82360029, 0x15162b49, 0x06071415, 0x26020e07, 0x01822726, 0x34353524, 0xca793637, 0x83162005, 0x176c08bf, 0x36320326, 0x16270637, + 0x07263525, 0x33163215, 0x37323316, 0x0be00136, 0x16140a0b, 0x505c5c50, 0x0b140a16, 0x190a140b, 0x19698069, 0x3455cc0a, 0x53368a88, 0x8b165023, + 0x1d013587, 0x0401c8ca, 0x4c754e01, 0x4a013235, 0x0c720b06, 0x31080506, 0x3f11113f, 0x050a0431, 0x050c720c, 0x4538040a, 0x5b043845, 0x43282843, + 0x1c27a2fe, 0x7f2a0682, 0x605f5f60, 0x0e102702, 0xac880300, 0x0c000622, 0x0023ac82, 0x83161637, 0x2213268a, 0x26173607, 0x27b79a17, 0x46501677, + 0x028b1650, 0x8d208c84, 0x9422a995, 0x6f82271c, 0x83430121, 0x9a65207a, 0x0400229b, 0x09734900, 0x1b00152c, 0x00002300, 0x17273313, 0x144f2327, + 0x37273006, 0x23270701, 0x05363435, 0x16162723, 0x78342415, 0x803805b0, 0x35731313, 0x40402b3e, 0xc0011a55, 0x36d4551c, 0x80142001, 0x00ff6034, + 0x2005237d, 0x081d822b, 0x2b404029, 0xfe1c553e, 0x2b551c42, 0x7e6b2719, 0xb2222e03, 0x46333346, 0x00020032, 0x011e001e, 0x00c401c4, 0x00270016, + 0x4b062500, 0x322609a9, 0x17173637, 0x74843736, 0x07822720, 0x36372622, 0x22087a82, 0x16323333, 0x36011415, 0x01348428, 0x090c0c09, 0x0a0c2428, + 0xf9131e2f, 0x1e88011e, 0x0d131f34, 0x8204092f, 0x094b2715, 0x2e208e0c, 0x0782090c, 0x0a050c33, 0xfa0f102f, 0x1e78fe1e, 0x19191eac, 0x240d092f, + 0x20388328, 0x0acb7a7e, 0x00001c24, 0x5f8b2701, 0x22230622, 0x8505e771, 0x73012184, 0x45505688, 0x22758405, 0x881a015d, 0xd596214d, 0x30376c88, + 0x40000400, 0xd5012b00, 0x1100c001, 0x1f001800, 0x00002600, 0x72173725, 0x15220560, 0x8f653727, 0x83052005, 0x15332261, 0x23d38403, 0x33353315, + 0x153bd782, 0x55552b01, 0x22273740, 0x15225555, 0x1100ff1f, 0x1a6b6b1a, 0xc02a4011, 0x82eb1a11, 0x37272212, 0x2a1e8240, 0xab22161e, 0xebc0111a, + 0x86401501, 0x0500221f, 0x3a008200, 0xda01da01, 0x0f000300, 0x1c001400, 0x00002300, 0x23273337, 0x27070103, 0x82233523, 0x27372663, 0x35272305, + 0x07137521, 0x84270721, 0xab31086f, 0x913e6aa8, 0x401cc001, 0x1a2455fe, 0xc0800169, 0x1e000140, 0x120c0c12, 0xc0c2140d, 0x6a6b251b, 0x42fe0501, + 0x8055401c, 0x6b022519, 0x95173e55, 0x251c830d, 0x1b25c089, 0x63180080, 0x032a09a5, 0x25000700, 0x34002d00, 0x164f5000, 0x16073809, 0x33173317, + 0x35363637, 0x22272634, 0x0615020f, 0x1506040f, 0x18171614, 0x31086e93, 0x35263327, 0x05233734, 0x15070614, 0x17230614, 0x5e732115, 0x32332408, + 0x82363617, 0x05164fa1, 0x04075b08, 0x15030605, 0x3e352604, 0x011a1c2c, 0x08050d0a, 0x06030204, 0x86011e2b, 0x221a1a22, 0x1b9b551a, 0xab018202, + 0x1f2c354b, 0x2000ff20, 0x53582c1f, 0x120b1d04, 0x593d193e, 0xab2b2b01, 0x0102516b, 0x3e060101, 0x013f2b25, 0x0106010f, 0x080c070a, 0x12120803, + 0x010a3b20, 0x41831984, 0x2f267c39, 0x35160c0a, 0x1f370757, 0x0b0b202c, 0xe01f2c20, 0x12012233, 0x4b00591a, 0x16220900, 0xdb821e00, 0x2329cb82, + 0x34353723, 0x06072727, 0x25cc8215, 0x37323333, 0x7d723637, 0x012a0807, 0x62090c80, 0x620f060c, 0x77121909, 0x022d0812, 0x7d7db0d8, 0x03017db0, + 0x480d0912, 0x0e060905, 0x6c0d076a, 0x69111912, 0xb34ed704, 0x00082e07, 0x01f8013c, 0x000300c4, 0x00110007, 0x23628215, 0x17372707, 0x25240282, + 0x27070137, 0x373f0b83, 0x27071727, 0x1e4e7f01, 0x8b1f0d4e, 0x1e38fe1e, 0x691e6a01, 0x591e7739, 0x1e77ed1b, 0x826b0177, 0x1fa92918, 0x1e3b1e8a, + 0x681e96fe, 0x3e201784, 0x41511782, 0x01db2406, 0x830600eb, 0x27252156, 0x15215382, 0x084a8214, 0x2607062d, 0x27353526, 0x17021e37, 0x60b9a401, + 0x1b1bc075, 0x52433449, 0x341b2b6e, 0x9e288e76, 0x563460b9, 0x1ba83d80, 0x14103949, 0x83805993, 0x288d2115, 0x200af751, 0x23a68208, 0x25000021, + 0x2a05654c, 0x33272335, 0x15273715, 0x5b331521, 0x01280f3e, 0x5555d66b, 0xd62a0001, 0xff250682, 0x2b012a00, 0x725c1811, 0x40952608, 0x80405555, + 0x21058480, 0x47181ad6, 0x00210a89, 0x08f75104, 0x0f000626, 0x28001800, 0x35266982, 0x33150723, 0x70a11715, 0x2b151524, 0x74987620, 0x1580c025, + 0x982b5516, 0x09e94179, 0x1a001227, 0x34240000, 0x52708426, 0x352405d1, 0x32161423, 0x39089c50, 0x55354b80, 0x32322355, 0x4b2b3246, 0x7db08d6a, + 0xcb7db07d, 0x55404b6a, 0x12824056, 0x35233225, 0x7f55014b, 0x402b09a7, 0xc001eb01, 0x00002400, 0x19163201, 0x26074f5d, 0x22233523, 0x72113526, + 0x152d0608, 0x11213523, 0x15233521, 0x01153727, 0x0cbb4fc0, 0x1a11802f, 0x0180fe2b, 0x5555ab80, 0x111a2b01, 0x09b34f6b, 0x40111a26, 0x6b00ff40, + 0x744f7483, 0x00032e0a, 0x002f0025, 0x2500003f, 0x23153335, 0x71538223, 0x3521056d, 0x56ce8235, 0x67570508, 0x0689440b, 0x22134248, 0x50952b35, + 0x352208f5, 0xf050202b, 0x4a363306, 0x0c0c0956, 0x1a112a09, 0xd6fe111a, 0x12191912, 0xed5040e0, 0x09202306, 0xf750150d, 0x23098205, 0x090c804b, + 0xc3542982, 0x12192706, 0x19122a01, 0x58180100, 0x09230873, 0x18010000, 0x28086b58, 0x6ec00001, 0x016e5252, 0x605818eb, 0xc7751809, 0x0011220d, + 0x28d08221, 0x33071707, 0x17030735, 0x23018201, 0x07270735, 0x0cab7b18, 0x36341137, 0x1e3c0133, 0x2c762c43, 0xf4fe2c4a, 0x2c0c011e, 0x6f1e6fc9, + 0x097242fc, 0x1c84e220, 0x1d851782, 0x826f7621, 0x42cd201e, 0x02210c7a, 0x05357800, 0x0800aa24, 0x70822800, 0x35262232, 0x07373734, 0x16163706, + 0x06071415, 0x27222123, 0x36201182, 0x08df4018, 0x14155308, 0x35362117, 0x00012734, 0xb50d1a11, 0x0ea10c79, 0x180d1c14, 0x0d18d8fe, 0x1a597d1c, + 0x24281643, 0x17654628, 0x12172801, 0x121119ab, 0x0cb5780d, 0x1a44169e, 0x16162f3b, 0x7d583b2f, 0x121a0e14, 0x272e4764, 0x24292e27, 0x80000600, + 0x95015500, 0xae4d9501, 0x059b7308, 0x2006375a, 0x20078637, 0x21078603, 0x008240eb, 0x03826a20, 0x83d54021, 0x40012d04, 0x96961540, 0x0156152b, + 0xd6155540, 0x2b37bd82, 0xd5012b00, 0x0700d501, 0x16000e00, 0x21001a00, 0x31002900, 0x18003900, 0x340811a6, 0x26260713, 0x07173727, 0x27070606, + 0x023f3636, 0x07270717, 0x21108227, 0x45181233, 0xe1470efd, 0x19d53107, 0x24191924, 0x42121fb8, 0x7a071e08, 0x1f084312, 0x722b0382, 0x725e1f5e, + 0x1e55071e, 0x84540106, 0x18c3211f, 0x01282583, 0x1824193d, 0x99012418, 0x19230583, 0x821efafe, 0x081e222a, 0x823a8317, 0x5e722b03, 0x1e1f5e1e, + 0x071e5706, 0x2d83a4fe, 0x83c31821, 0x7c5c8205, 0x11370ee9, 0x00002c00, 0x23153701, 0x22262637, 0x23170706, 0x36361735, 0x18131632, 0x200be44a, + 0xeb421833, 0x322a0808, 0x01161717, 0x2c6a28ad, 0x52685211, 0x286a2c11, 0x5d705d18, 0x11021010, 0x0a0c910c, 0x0a07116a, 0x1a134905, 0x08031113, + 0x26841361, 0x1e1e1623, 0x36258216, 0xfe22221c, 0x0c7004dc, 0x11690a10, 0x0de51007, 0x800d1313, 0x18093002, 0x280aa553, 0x000f0007, 0x0028001f, + 0xa5761800, 0x4d07201f, 0x012b0776, 0x585058ab, 0x2626349a, 0x4d402634, 0x5620095e, 0x2805764d, 0x241c20ab, 0x01201c24, 0x221d8200, 0x4d503426, + 0x55200b64, 0x098e7418, 0x55005528, 0xab01ab01, 0x424f0300, 0x23372107, 0x49074353, 0x23230688, 0x74353335, 0x3328058f, 0xd6562b01, 0x2a565656, + 0x06860182, 0x0782d520, 0x0c820d89, 0x2608244e, 0x000900ab, 0x822d0021, 0x06dd48cd, 0x05153327, 0x26272627, 0x855f1837, 0x32332e0a, 0x14151516, + 0x35370707, 0x07232334, 0x2a0e8215, 0x09ab0107, 0x2a090d0d, 0x180900ff, 0x38078d99, 0x180d3903, 0x0d1d15ad, 0xad075876, 0x1b137637, 0x090cc005, + 0xeb0d09c0, 0x95991895, 0x83072f09, 0xa7151d15, 0x57390d12, 0x177e07a8, 0xad52141f, 0x87d52008, 0x84132084, 0x23062a69, 0x17253523, 0x07161716, + 0x4a7a8707, 0x372d0702, 0x14150737, 0x35373333, 0x37262223, 0x20838455, 0x21839a01, 0x848f4001, 0x8f080921, 0x00022c84, 0x0195002b, 0x006b01d5, + 0x18130007, 0x22094d41, 0x56163225, 0x342f050a, 0x347b3336, 0x26342626, 0x3e2c1601, 0x83d62c3e, 0x82c02004, 0x3426250e, 0x3f583f85, 0x00200282, + 0x2428418e, 0x26343632, 0x37140622, 0x0121418a, 0x20428451, 0x20419640, 0x20838203, 0x22838680, 0x823b0033, 0x096a7c85, 0x2206142c, 0x37343526, + 0x27230727, 0xf6820606, 0x3e34352b, 0x23273702, 0x37173335, 0x24068533, 0x3e172315, 0x07c54902, 0x22863008, 0x1a221919, 0x2b2b1feb, 0x09192c3e, + 0x0516403b, 0x2b1f1b2a, 0x0b140d08, 0x2d4e2014, 0x2a1a4148, 0x2d3e1a3d, 0x0909051c, 0x1a1a2216, 0x82f51922, 0x221a222d, 0x3d2d8239, 0x16211f2c, + 0x1b14620b, 0x0c1f2c24, 0x040e1217, 0x1c1c1211, 0x18211620, 0x0301252d, 0x26842001, 0x260a485a, 0x000e0008, 0x5400001c, 0x23230a5f, 0x18112335, + 0x540d0c44, 0xb723065d, 0x18ab956b, 0x2109ff43, 0x225555c0, 0xeb4d2605, 0x01aafe6b, 0x5c7c1880, 0x5408200b, 0x0828085b, 0x1a001100, 0x27002300, + 0x2f281182, 0x00004200, 0x35333525, 0x20057458, 0x05244b23, 0x33133326, 0x15151632, 0x27227482, 0x06822315, 0x3336342f, 0x07353713, 0x07273727, + 0x27351707, 0x251b8237, 0x06070714, 0xc54f2727, 0x32363005, 0x406b0117, 0xfe0d132a, 0x130d4ae0, 0x85d6402a, 0x2d118305, 0x155656ca, 0x16555555, + 0x10f05656, 0x02857510, 0x08100825, 0x82402a2b, 0x0d132523, 0x8001404a, 0x2a200583, 0xfe290f84, 0x316231bb, 0x32323125, 0x27078287, 0x87120a3b, + 0x0a440a12, 0x08840282, 0x00040423, 0x08725805, 0x200aaf4e, 0x06bf5013, 0x07823720, 0x03820720, 0x11330125, 0x83409523, 0x40562600, 0x4040eb40, + 0x2e0a8201, 0xc0562b01, 0x80406b55, 0xfe560196, 0x820400aa, 0x015534f7, 0x00ab01d5, 0x000a0003, 0x0011000d, 0x23353700, 0x83173715, 0x232208ea, + 0x27173505, 0xc0272317, 0x2b80162b, 0x00012aab, 0x35aa4040, 0x5656d575, 0xd6d680d6, 0xab4040d6, 0x878276ab, 0x8305ba46, 0x00072240, 0x05484a0b, + 0x17371323, 0x29838407, 0x25211521, 0x32363623, 0x11822716, 0x2d1e4c38, 0x2a2a721e, 0xfeaa01c0, 0xfc530156, 0x475e4708, 0x2d1e2d0c, 0x17825701, + 0xc0408128, 0x3d2e8056, 0x1082443d, 0x00020022, 0x07d67018, 0x1a00112b, 0x21130000, 0x33352311, 0x27038535, 0x26233527, 0x15170727, 0x2405cf68, + 0x801601d5, 0x3b00822a, 0x2e221b2b, 0x556b9227, 0xfec0016b, 0x2b2b5580, 0x121d272a, 0x611a1f16, 0xe0ababe5, 0x2b26d982, 0xeb011500, 0xe182c001, + 0x1e00182e, 0x32240000, 0x23263436, 0x15150622, 0x20063b43, 0x08528222, 0x27373542, 0x17150535, 0x01352707, 0x3f3f5829, 0x6a3f2b2c, 0x3d59583e, + 0x9b0d4f33, 0x3501c0c0, 0x40401030, 0x3e3f583f, 0xc22c022c, 0x3d597a58, 0x2b954230, 0x45cb952b, 0x552b1b20, 0x90000100, 0x6e014000, 0x0e3b6182, + 0x23370000, 0x37222337, 0x37360736, 0x32330733, 0x1616eb07, 0x0308104b, 0x82493302, 0x050e2a08, 0x050e9540, 0x95815902, 0x20968a0e, 0x2d988206, + 0x2500001d, 0x33353327, 0x35173315, 0x58181523, 0x22240808, 0x07353526, 0x01289a84, 0x402b4b60, 0xc0c0152b, 0x21050052, 0x9582aa1a, 0x56555529, + 0xc06b4040, 0x521aebc0, 0x4b210517, 0x2094834b, 0x225a8495, 0x82d50140, 0x0007248f, 0x8317000f, 0x141625f1, 0x34262206, 0x2107474a, 0x0f853206, + 0x465d0127, 0x32463232, 0x21058a4e, 0x0c8333eb, 0x32080127, 0x46333346, 0x430c84a3, 0x1b280a8d, 0x2f002100, 0x15010000, 0x35334e83, 0x33363435, + 0x15161633, 0x34352315, 0x14151522, 0x82363216, 0x112127ae, 0x37233523, 0x53181117, 0x01210a00, 0x34658255, 0x1506161f, 0x1a162a1a, 0x01ab1a22, + 0xc0ab5500, 0xff111a6b, 0x31cd8300, 0x236b2b01, 0x8b233232, 0x21021f16, 0x0a8b8815, 0x15838b0a, 0x01d66b26, 0x6a2a5600, 0x25050a53, 0x19115601, + 0x5b180600, 0x17230c32, 0x7f001f00, 0xcb440d98, 0x18e48706, 0x87071c78, 0x860f87ec, 0x226622f4, 0x208a821a, 0x91fa84ce, 0x0506410b, 0x221a082e, + 0x01221919, 0x3346321a, 0x19074633, 0x91213183, 0x85318333, 0x0cfd4218, 0x15000c24, 0x91821e00, 0x15010026, 0x15173521, 0x32063e44, 0x14153325, + 0x35232306, 0x35232533, 0x33333634, 0x44252315, 0x0131074f, 0x1500ff80, 0x2a191140, 0x192a5601, 0xfe404011, 0x210684aa, 0x13831601, 0x55014029, + 0x2bd5aaaa, 0x822b111a, 0x1a112400, 0x822bd52b, 0x210e8404, 0x5b180300, 0x09300813, 0x24001100, 0x37370000, 0x17373327, 0x27170733, 0x1a115b18, + 0x2e129c2a, 0x38121238, 0x272e122e, 0x13ad5a18, 0x2035f528, 0x35203636, 0x5a184121, 0x063415b2, 0x40002500, 0xc001db01, 0x19001000, 0x2c002300, + 0x4e003600, 0x21257982, 0x27222335, 0x2b038806, 0x17062723, 0x37323316, 0x14172337, 0x36260782, 0x07233535, 0x0a841537, 0x37272725, 0x82161707, + 0x36372414, 0x7e163727, 0x45080580, 0x35262221, 0x37262735, 0x33363637, 0x17163221, 0x052b016b, 0x1c14121e, 0x1b14161b, 0x1d12141e, 0x09031505, + 0x04150d07, 0x0f492a0d, 0x2a100c0b, 0x0a10600c, 0x0c02110d, 0x010d2954, 0x080c0a0e, 0x08290309, 0x3c540615, 0x15062e05, 0x18031608, 0x0e28010e, + 0x806b0417, 0x08008414, 0x0b0e4d2d, 0x6367190a, 0x0b11120b, 0x64606064, 0x0d13110b, 0x67010160, 0x0b0a0f0a, 0x1a230a0e, 0x1a119406, 0x0694111a, + 0x0e5e231a, 0x180e1212, 0x44086741, 0x002507cb, 0x23153301, 0x39038225, 0x23113313, 0x2b2b9501, 0x2b2babfe, 0x01d6d655, 0xebebeb80, 0xc0fe1601, + 0x91420400, 0x00082a08, 0x001c000c, 0x13000025, 0x05a15615, 0x43253521, 0x34230fc7, 0x87073336, 0xc0552d1c, 0x011911c0, 0x11abab80, 0xab111919, + 0x11838683, 0x00011a2e, 0x111a2b95, 0x56561595, 0x80111aab, 0x80231b83, 0x846b1a11, 0x06686313, 0xc001c025, 0x18002800, 0x270afe4c, 0x34263337, + 0x33372337, 0x0cfe4c18, 0x06230727, 0x07331714, 0xfe4c1823, 0x1560260b, 0x56010141, 0x004d1815, 0x1590260c, 0x9e020289, 0x024d1815, 0x0001261d, + 0x014000ab, 0x20788255, 0x0bf87f09, 0x40150125, 0x82405555, 0x6b012403, 0x825555d6, 0x02002102, 0x2308654d, 0x00250007, 0x08808e18, 0x14153733, + 0x35362707, 0x22022e34, 0x1e14020e, 0x37323302, 0x05095017, 0xdf483720, 0xda260805, 0x12123e29, 0x2c242d1a, 0x1a13131a, 0x1b20122c, 0x52493442, + 0x34e6c06e, 0x26342626, 0x424c80d5, 0x12201b3e, 0x23871a2d, 0x3d431228, 0x59931412, 0x70825680, 0x22077c46, 0x820d0006, 0x27373a9b, 0x21152115, + 0x35170705, 0x01213521, 0xfe555580, 0xff4001c0, 0x01555500, 0x25098240, 0x40565500, 0x0483402b, 0x05002208, 0x35001500, 0xa001eb01, 0x13000900, + 0x27001d00, 0x00004400, 0x15173225, 0x07222326, 0x36273635, 0x200b8633, 0x840e8337, 0x3517210c, 0x15201b83, 0x03281982, 0x14111732, 0x27222306, + 0x03831083, 0x0c822220, 0x11352622, 0x172d1a82, 0x1a750136, 0x3c22141c, 0x2a262624, 0x2f098536, 0x28243c60, 0x181c1a38, 0x412a212d, 0x27413434, + 0x18249819, 0x2005ce28, 0x11241505, 0x07831128, 0x154e2008, 0x21051223, 0x0af6ab06, 0x0120f520, 0xc9fe2020, 0x16010704, 0x01172020, 0x39010406, + 0x82202020, 0x00552afc, 0x01ab0140, 0x000700d5, 0x29bd821b, 0x23272335, 0x35173315, 0x08831533, 0x18112321, 0x08071b77, 0x33150723, 0x156b8001, + 0x8016806b, 0x2a6b1596, 0x1a221a16, 0x80958016, 0xab2b802b, 0x01552ad5, 0x11190c46, 0x21028219, 0xeb181b0c, 0x29260e42, 0x21370000, 0x58182115, + 0x42180c53, 0x332e0835, 0x15060715, 0x33331415, 0x34353532, 0x6f182727, 0x2b22072f, 0xeb18122b, 0x562f0852, 0x550b0427, 0x6b27040b, 0x4015012b, + 0x18196b40, 0x33095aeb, 0x05031f33, 0x5b0b0b5b, 0x331f0305, 0x26000600, 0xdb012b00, 0x0f2ac682, 0x1d001600, 0x4f004700, 0xce826e00, 0x2726363c, + 0x07222326, 0x041f3217, 0x27360715, 0x16170627, 0x27371627, 0x37060726, 0xe3821716, 0x07071624, 0x8f821617, 0x7d440720, 0x37262b07, 0x36372626, + 0x17323336, 0x05823717, 0x35331624, 0x214b3633, 0x832c8407, 0x83272028, 0x3726212e, 0x23824782, 0x36373322, 0x71082c82, 0x04013233, 0x0d0c020b, + 0x220c0f10, 0x01060201, 0x140d0101, 0x0b1a1907, 0x321f7308, 0x08071344, 0x220d26b1, 0x0c1b031d, 0x1218030c, 0x12220b0b, 0x19220f09, 0x110f0d23, + 0x13240608, 0x091e090c, 0x06012319, 0x12771501, 0x0c120c0c, 0x12130769, 0x0f110608, 0x1111070c, 0x110f0c07, 0x13130906, 0x17140707, 0x052e0506, + 0xc9121806, 0x0d0c1f0d, 0x2f820d0a, 0x01020136, 0x43140794, 0x80151f32, 0x07191a0b, 0x0d5d1314, 0x1b281627, 0x0c354e82, 0x03062413, 0x2319031b, + 0x152b0a30, 0x0c031911, 0x1d01190c, 0x085b8216, 0x21120c25, 0x1a0b0c14, 0x0f061b0d, 0x0d1b060f, 0x140c0b1a, 0x16161413, 0x00020014, 0x012b0055, + 0x00d501b2, 0x191b0013, 0x2d085baa, 0x11231523, 0x33352626, 0x33331614, 0x5c4f2632, 0x012d0806, 0x541e5f53, 0x2f2b2a2b, 0x2c3e2b3c, 0x19661a37, + 0x24191924, 0x1e605301, 0x8080ff55, 0x4f0e1b01, 0x2e3e2c32, 0x24181824, 0x00090019, 0x2055823f, 0x2c5582cd, 0x00140009, 0x003a002c, 0x004a0042, + 0x05507a4e, 0x16143739, 0x37373233, 0x37060727, 0x14150622, 0x36371717, 0x17172627, 0x82071707, 0x27222312, 0x1b823426, 0x07247385, 0x22361707, + 0x33290a82, 0x33351732, 0x14152315, 0x0ee74f14, 0x82370721, 0x23352134, 0x27201c84, 0x6b332182, 0x04040307, 0x03161017, 0x03070319, 0x08080807, + 0x831e4703, 0x0f173900, 0x10100f2e, 0x1f100717, 0x0710202c, 0x202caf0f, 0x0e121620, 0x1c124055, 0x085a7718, 0x1ea61f37, 0xab40a7a6, 0xabab6b40, + 0x04070460, 0x03160f16, 0x0504066f, 0x23448203, 0x1f280307, 0x0f224585, 0x45832c10, 0x1f1f2c30, 0x1007102c, 0x1f2c2088, 0x602a600b, 0x4683e316, + 0x1a7e1227, 0x131a1313, 0x2847825a, 0x2a2a56e2, 0x002ac056, 0x08e14509, 0x2207674b, 0x8223001b, 0x002f2513, 0x37000048, 0x3520af82, 0x13200382, + 0x28066f4b, 0x15233537, 0x11231123, 0x20148233, 0x067b4216, 0x1df24918, 0x37273528, 0x32333336, 0x00822a6b, 0x2b2b6a2c, 0xc02a2a6a, 0x6a156b80, + 0x491862ab, 0x0e3a19e2, 0x10051f01, 0x2b6b1099, 0x00012b80, 0x552a562a, 0x00ff6b6b, 0x806b1501, 0x34840dab, 0x733b0584, 0x58084040, 0x0a090676, + 0x061b1b06, 0x58760f0a, 0x0005000e, 0x01400040, 0x51d501d5, 0x172206e9, 0xc1892a00, 0xc1823520, 0x200b2d63, 0x0d836911, 0x11221d82, 0x0084ab95, + 0x40000124, 0x02822a40, 0x24074050, 0x2bc09595, 0x2001826b, 0x3c1584c0, 0x9a91fe40, 0x1a1a1195, 0x11000111, 0xfbfe2a19, 0x15000400, 0xeb015500, + 0x0900ab01, 0x25961800, 0x16163508, 0x35211515, 0x22373634, 0x34353627, 0x33362726, 0x06141632, 0x22053042, 0x4a172206, 0x2c080651, 0x3f4c40a0, + 0xec3faafe, 0x101c0f0d, 0x230d0f0c, 0x32f83232, 0x46323246, 0x565235c7, 0x1a2a12eb, 0x2a1a4040, 0x2f210527, 0x050e3013, 0x20188333, 0x26058233, + 0x202b0818, 0x51314040, 0x0d200c47, 0x1d238382, 0x41000000, 0x37210991, 0x0ce01823, 0x0614320b, 0x01342622, 0x13131a3e, 0x484f131a, 0x0dd60d3a, + 0x270b8420, 0x7d7db02d, 0x15017db0, 0x13261682, 0x262fa81a, 0x0984a626, 0x74189320, 0x2f5d098c, 0x82042005, 0x002928db, 0x23350100, 0x82053615, + 0x25142204, 0x30e08232, 0x06070614, 0x33150706, 0x33352315, 0x27262635, 0x05d55926, 0x35334108, 0x95011533, 0x00ff2a2a, 0x112a012a, 0x0928361a, + 0xd656172d, 0x092d1756, 0x111a3628, 0x5501d62a, 0x0f0f5216, 0x6d2d1652, 0x28161119, 0x2416053c, 0x2b2b4205, 0x16240542, 0x16283c05, 0x2b2b1911, + 0x5e2edb82, 0x95012b00, 0x0800c001, 0x10000c00, 0x7b822f00, 0x07273725, 0x4c170727, 0x1720053d, 0xe1508382, 0x06072c06, 0x06141515, 0x22062323, + 0x83222327, 0x27630880, 0x36363726, 0x0b013637, 0x23230f27, 0x2016270f, 0x2b565656, 0x151d573e, 0x0611190e, 0x060c320c, 0x3f0e1911, 0x2c41080f, + 0x260d010f, 0x10232310, 0x16403826, 0x15152a16, 0x3e575501, 0x12411c01, 0x1131130c, 0x1a15151a, 0x0c133111, 0x422c5438, 0x08000308, 0x2c002c00, + 0xd401d401, 0x0d000700, 0x43001300, 0x31270521, 0x00003700, 0x82153337, 0x337182fa, 0x26070633, 0x27260526, 0x37060633, 0x06171616, 0x27350706, + 0x15231985, 0x85352333, 0x36232211, 0x82088237, 0x17163d2c, 0x4d1f2cbf, 0xb3331f17, 0x191c0567, 0x1ddbfe28, 0x28056704, 0x1f3305db, 0x56204d16, + 0x218b0686, 0x2805df3f, 0xeb051c19, 0x172503bf, 0x32234c11, 0x43370c2c, 0x371b312d, 0x114c2352, 0xbf032517, 0x8a07862a, 0x1b1b251f, 0x322c0c37, + 0x20089e52, 0x20ba82d5, 0x21b8820b, 0x9e440000, 0x37072506, 0x16270717, 0x0e66f918, 0x3e2c4034, 0x3a3e2b2b, 0x4b1f5b1e, 0x063c0606, 0x06b60612, + 0x06823d06, 0x836c0121, 0xbb2c2517, 0xc41e5a1e, 0x3d230e82, 0x85b50606, 0x04002906, 0x6b003300, 0x9501d001, 0x0f205f82, 0x33215f82, 0x057d4e00, + 0x14062223, 0x068e4226, 0x23350722, 0x08318d18, 0x0616052f, 0x27272223, 0x22060723, 0x36343526, 0x09c11835, 0x44012007, 0x2208050f, 0x0c0c121e, + 0x2b400c12, 0x152b2b15, 0x21040c01, 0x30101619, 0x2e103080, 0x0417011f, 0x1fc22030, 0x82eb0530, 0x120c221f, 0x23058434, 0x2a2a1622, 0x6c300282, + 0x30102519, 0x171f1030, 0xa3010601, 0x1e2b2a1f, 0x3f389482, 0xc1013f00, 0x0500c101, 0x11000900, 0x00001700, 0x1e362701, 0x27370702, 0x9955f682, + 0x17073405, 0x01022e06, 0x3b2373c0, 0x78ee0a0c, 0xa362781e, 0x82596810, 0x847e2003, 0x4d012711, 0x0c0a0173, 0x1882bc3a, 0x59a3e724, 0x03821068, + 0x1184f720, 0x00060022, 0x07856118, 0x28057543, 0x002d0025, 0x37000035, 0x06977b35, 0x34352324, 0xeb552326, 0x46162007, 0xa14d0e0b, 0x84fd8207, + 0xd6952819, 0x2a1a112b, 0x842b111a, 0x0d1e21cf, 0x6233fe83, 0x0d0d120c, 0x3f586012, 0x2d3f583f, 0x7c57577c, 0x822a6b57, 0x15152422, 0x84011a11, + 0x1f0c2126, 0x0c202083, 0x0c212684, 0x2225826b, 0x82c1583f, 0x7c572125, 0x3c0aec50, 0x00190012, 0x00280021, 0x33172500, 0x27222715, 0x27262627, + 0x36173327, 0x33373736, 0x06ee5113, 0x0717372a, 0x35072306, 0x33363407, 0x4108bb82, 0x551e2201, 0x1e060d64, 0x57031807, 0x09023148, 0x47482501, + 0xeb2a0c09, 0x06122212, 0x0c40640d, 0xee2a1509, 0x0b015643, 0x07360e42, 0x13056fbd, 0x00ff5502, 0x5640090d, 0x0b294a29, 0x09165601, 0x5218560d, + 0x032b0a99, 0x27001d00, 0x35010000, 0x83361523, 0x0714216d, 0x23206a82, 0x524f8683, 0x21138305, 0x82450334, 0x233b0805, 0x40012622, 0x0c12e2ab, + 0x10041101, 0x110311de, 0xab111901, 0xd6d61a11, 0x09aa090d, 0x402b010d, 0x090d4040, 0x5503063b, 0x03551111, 0x1a117b06, 0x0940111a, 0x4040f7fe, + 0x4b0c0c09, 0xdb260620, 0x1500af01, 0x70821e00, 0xdf541620, 0x32332c08, 0x27343536, 0x36373627, 0x82140716, 0x36360815, 0x01161737, 0x4b6507d4, + 0x041911d6, 0x2e2e1fae, 0x48493666, 0x0e14cd70, 0x772913a6, 0x4c110115, 0x11111a70, 0x1f2e1c13, 0x272b1433, 0x49590504, 0x2e46140e, 0xd4820832, + 0x36003236, 0xca01ce01, 0x0f000600, 0x00002100, 0x06373625, 0x27360706, 0x5c820382, 0x37063728, 0x07061616, 0xdd820606, 0x82262621, 0x33363d10, + 0x415a0132, 0x4d802304, 0x04417269, 0x401a3a0f, 0x11cd694d, 0x2a2e2708, 0x15443873, 0xa6370887, 0x804d6a41, 0x41f60323, 0x1a53206a, 0x19032340, + 0x2e896611, 0x8515272a, 0x07002106, 0x2408bf53, 0x000e0009, 0x09655816, 0xd4822520, 0x27352632, 0x27170707, 0x17072737, 0x23273717, 0x32161707, + 0x27200c82, 0x1524e582, 0x13171614, 0x17829c82, 0x15333527, 0x26373717, 0xe4781826, 0x81600809, 0x1e15012a, 0x1d39111f, 0x651d4d4d, 0x0e6d0d0f, + 0x8538190f, 0x151e1f11, 0x4f111901, 0x090e3719, 0x552a551d, 0x370e091d, 0x7db08a19, 0x917db07d, 0x04023f30, 0x5d0a1001, 0x36562d1d, 0x20625636, + 0x09201717, 0x0a5d1d3e, 0x02040110, 0x0114411a, 0x162a0712, 0x1e3b091d, 0x1d093b1e, 0x32072a16, 0x20053546, 0x06815504, 0xc4828020, 0x15000f24, + 0x274d3500, 0x07294809, 0x3532262e, 0x37152234, 0x22231533, 0x07161706, 0x604cb082, 0x34352205, 0xa1a71937, 0x17320808, 0x2419c036, 0x08241818, + 0x34262634, 0x16165626, 0x0a56e59b, 0x0403010d, 0x02293e08, 0x4b35020a, 0x16050802, 0x12161f1f, 0xee27051c, 0x24191924, 0x27821519, 0x5a34263d, + 0x350a0a0b, 0x170a0e56, 0x05382815, 0x06354b01, 0x20020a07, 0x10151f2c, 0x82060025, 0x012b3a99, 0x00d401d4, 0x000a0004, 0x0014000f, 0x001f0019, + 0x35270100, 0x37011616, 0x087a8217, 0x06171352, 0x17072707, 0x37272607, 0x37363507, 0x26071507, 0xd4013435, 0xfe6c4abf, 0x4042bfe1, 0xbf412c6d, + 0x15ad0e04, 0x1519bf40, 0x211f4098, 0x0113426b, 0x084d6e19, 0x6ed9fe69, 0x2b015827, 0x631e216e, 0x126d2525, 0xdc25881d, 0xdb2a030e, 0x6a2d2b27, + 0x27286b82, 0xd5011500, 0x0800f101, 0x1c227182, 0xac523a00, 0x34353508, 0x06072236, 0x32331614, 0x27343637, 0x023e1626, 0x36060626, 0x2b054c42, + 0x030e022a, 0x37270707, 0x3434043e, 0x37212782, 0x06d35136, 0x24677008, 0x111a0d0c, 0x0d0d0c12, 0x445532db, 0x4454320d, 0x2f0c4aaa, 0x031b4119, + 0x0e170b18, 0x5a071013, 0x0b075b1f, 0x1d010406, 0x32c02f19, 0x24323346, 0x0d0c0723, 0x0d0c1a22, 0x32970d23, 0x3255440d, 0x4c7d440e, 0x1d192f77, + 0x0b060401, 0x5a1e5a07, 0x0f131007, 0x03180b17, 0x2f19411a, 0x76000300, 0x91010200, 0x0a00ea01, 0x29002100, 0x5b010000, 0x072b0696, 0x16170606, + 0x36270716, 0x82273435, 0x08038396, 0x37262658, 0x17160617, 0x1616023e, 0x01260606, 0x0e121010, 0x07091213, 0x112e371a, 0x150e251b, 0x25402586, + 0x216d2420, 0x1625190c, 0x120d2616, 0x12091e23, 0xaf011e22, 0x120e1209, 0x080b0f20, 0x2b712686, 0x201c1916, 0x6f15e81f, 0xbe153715, 0x162c6224, + 0x2f165526, 0x2a840a1e, 0x00040039, 0x022b0001, 0x00f80100, 0x0039001d, 0x005c0054, 0x33161300, 0x55272217, 0x2721051c, 0x2c868315, 0x35262634, + 0x36373726, 0x16173233, 0x20908237, 0x240a8336, 0x32333237, 0x3f028216, 0x07060716, 0x06230622, 0x05262223, 0x1e273523, 0x27231702, 0x35231507, + 0x06273736, 0x36272607, 0x17213782, 0x07934917, 0x21f02208, 0x2e3e032c, 0x2b2d320f, 0x4e1e5b1b, 0x02010217, 0x110d470f, 0x2606090f, 0x03041610, + 0x02030617, 0x08138202, 0x0a010528, 0x060d0118, 0x02050108, 0x06010503, 0x262b1401, 0x07181409, 0x2b2c272d, 0x120d1b12, 0x32171e1b, 0x24141616, + 0x774ccb6c, 0x211f3305, 0x330f2c2c, 0x196e802d, 0x4d1e5a2f, 0x0405013f, 0x56821202, 0x06074008, 0x111e0304, 0x01020917, 0x0e221801, 0x01030306, + 0x0f484a01, 0x227a642d, 0xa0802bab, 0x14401a11, 0x0917030f, 0x0f202328, 0x1924542d, 0x00182419, 0x00550001, 0x01ab0150, 0x001400ab, 0x82361300, + 0x020e25ba, 0x27060607, 0xca820982, 0x2b08c382, 0x3a952181, 0x2c09013a, 0x295e2221, 0x6d264409, 0x1a1a1230, 0x2b215401, 0x4f190506, 0x0f2221a1, + 0x20753214, 0x3f127238, 0x02003e32, 0x31085b44, 0x0018000b, 0x23352500, 0x15232707, 0x37173533, 0x07823715, 0x3521152e, 0x35233533, 0x55011737, + 0x2a2b2b2a, 0xaa380382, 0x56fe2a2a, 0xd5d52a2a, 0x40409580, 0x40405595, 0x2ac09555, 0x952bc02a, 0x5d058755, 0x1122050f, 0x57822300, 0x25002408, + 0x35231533, 0x26222306, 0x16163327, 0x37363233, 0x35232723, 0x33361533, 0x23171632, 0x22232626, 0x47330706, 0x01310714, 0x402a8055, 0x0f754d6b, + 0x3b5c0e2c, 0x3e164f2e, 0x430f8eaa, 0xd52a05d1, 0x61552b80, 0x2f493749, 0x09888027, 0x26346f25, 0x56263426, 0x0e240a06, 0x31001d00, 0x3722cc82, + 0x64823423, 0x83170721, 0x23152570, 0x27373207, 0x35268c83, 0x33072733, 0x337b1614, 0x3733320f, 0x60011733, 0x2c3f2a35, 0x0e0f181a, 0x2a322315, + 0x2108822b, 0x08821310, 0x15823520, 0x766ed720, 0x27443809, 0x36b52780, 0x0f0d3e2c, 0x6b233207, 0x3308100d, 0x2c353523, 0x4c15013f, 0x93180724, + 0x152c0880, 0x00020000, 0x0b00c001, 0x23001300, 0x17219082, 0x429d1807, 0x07fe4408, 0x16323723, 0x2c958314, 0x37270727, 0x36053727, 0x260f8601, + 0x36028726, 0x44446231, 0x42754462, 0x3c425e5e, 0x01ac085a, 0x0101c0c0, 0x8ad51230, 0x82842021, 0x6244331f, 0x5e845ed1, 0x954a3b4f, 0x82952b2b, + 0x000c0002, 0xaa4b0040, 0x092c5905, 0x0b356618, 0x8d183720, 0x032409a5, 0x17152335, 0x27200386, 0x25210b96, 0x057e5833, 0x35331129, 0x2a950133, + 0x842b2a2a, 0x82068700, 0x012a2910, 0x2aab5500, 0xc0d655ab, 0x0e5ac118, 0x2a2aab23, 0x88128256, 0x2a2a2802, 0x5555d5aa, 0x42552b01, 0x30220a77, + 0x8f823800, 0x14153324, 0x42572306, 0x26222d06, 0x35333535, 0x32333634, 0x17161717, 0x26290982, 0x07072223, 0x07141516, 0x26138327, 0x16323637, + 0x82340415, 0x14540805, 0xab012206, 0x0d11192a, 0x09d6fe09, 0x4019110d, 0x1014131d, 0x920c061d, 0x0507080a, 0x3b07021b, 0x06050b0c, 0x2432111b, + 0x2418c0fe, 0xeb241919, 0x091a1180, 0x1a090c0c, 0x13108011, 0x0721101d, 0x0b07ae08, 0x03081b05, 0x073b0c0b, 0x23111b02, 0x18244019, 0x274b2982, + 0x000a240a, 0x821c0015, 0x1737229f, 0x05054107, 0x17273522, 0x24060f41, 0x23252735, 0x2b018211, 0x11970137, 0x2a2b1129, 0x5711e82b, 0x112e0582, + 0x2ac0a601, 0x55abd5c0, 0x55705d08, 0x02848055, 0x485d7026, 0x1501ebfe, 0x240b2243, 0x002c001d, 0x31588230, 0x33112111, 0x27263335, 0x3e343427, + 0x06063706, 0xe8831716, 0x15334208, 0x37361627, 0x06272636, 0x07021e17, 0x21030606, 0xab012111, 0x302baafe, 0x03010219, 0x140d0804, 0x02152319, + 0x281c1602, 0x14832b16, 0x28020331, 0x01030504, 0x02010104, 0xaa01de13, 0x015556fe, 0x082c8256, 0x06202027, 0x0f110805, 0x16171315, 0x15060b18, + 0x2c1c1335, 0x412b1d23, 0x131b1311, 0x0d0e0828, 0x08070f04, 0x3b01150a, 0x095a54fe, 0x0500c02d, 0x00001400, 0x26343313, 0x5b170622, 0xf7830516, + 0x17372008, 0x56d53335, 0xc01a221a, 0x566a4040, 0x55d5406a, 0x112b0140, 0x3a021919, 0xab8080ab, 0x18384dc0, 0x6108e967, 0x21250559, 0x35010000, + 0x2a398323, 0x16322115, 0x07231515, 0x82212723, 0x35232403, 0x83333634, 0x24158303, 0x2a6b8001, 0x2546836b, 0x0e160e1c, 0x0482f2fe, 0x11191c2b, + 0x0001111a, 0x2b011a11, 0x23008240, 0x2a6b111a, 0x6b230082, 0x82401a11, 0x0011306b, 0x00150002, 0x01b2012a, 0x000d00d5, 0x43000028, 0x2322053a, + 0x53822622, 0x37173228, 0x06371616, 0x634f2306, 0x23262506, 0x26340722, 0x13826982, 0x95162308, 0x111a1a11, 0x26261a40, 0x5c0f2d1a, 0x1d2f7521, + 0x2122375e, 0x211a242e, 0x01131737, 0x140f5678, 0xda82ab01, 0x34262208, 0x40532a26, 0x342d0538, 0x1b311a0b, 0x092e082f, 0x56020601, 0x3617037c, + 0x0005005e, 0x012b006b, 0x207982ab, 0x2083820a, 0x207d8220, 0x2ae1824e, 0x37262736, 0x16170633, 0x94230716, 0x22162d0a, 0x32161406, 0x22073436, + 0x07232726, 0x91829b83, 0x26373730, 0x14213526, 0x06170706, 0x22062707, 0xcb560727, 0x06142f05, 0x10073301, 0x05150619, 0x0406110f, 0x0a88064b, + 0x0a894a20, 0x12962408, 0x0c120d0d, 0x07201515, 0x0d051588, 0x03090408, 0x01302855, 0x0c24332a, 0x05150e14, 0x6c2a051c, 0x82152007, 0x6b012ae6, + 0x251a101b, 0x1b131219, 0x21089111, 0x45830ceb, 0x13184925, 0x83030922, 0x12813244, 0x50282d49, 0x12081310, 0x41010121, 0x34261813, 0x2f7b1826, + 0x00253310, 0x21151300, 0x33152735, 0x23351735, 0x23151715, 0xd1822307, 0xcf410382, 0x32333c07, 0x32151516, 0x00018016, 0x406a40d5, 0x150e1d96, + 0x150fb90e, 0x111a1d0e, 0x82aa111a, 0x011a2603, 0x6b404000, 0x20008340, 0x0cd4412b, 0x001a402b, 0x00550002, 0x01ab0155, 0x300982ab, 0x3700001c, + 0x17172733, 0x35262221, 0x17071711, 0x30038e37, 0xe47b7b95, 0x11d5fe32, 0x0f16321a, 0x0f172a16, 0x22038317, 0x83101729, 0x7b95280b, 0x111a3289, + 0x83322b01, 0x10162316, 0x22822a17, 0x0b842920, 0x63840f20, 0xb5016b28, 0x05009501, 0xcd820b00, 0x23071725, 0x84332737, 0x6bb52d05, 0x6b6b606b, + 0x606a6af6, 0x95016a6a, 0x03440087, 0x1032080a, 0x20001800, 0x14010000, 0x22061716, 0x34363627, 0x32362726, 0x37060617, 0x26071416, 0x25363426, + 0x06141616, 0x01342607, 0x3e2a3c2b, 0x382e3ea6, 0x06842e38, 0x26268427, 0xfe333327, 0x2d0482c9, 0x00012627, 0x39135b2e, 0x68541439, 0x06831454, + 0x86374628, 0x54440c37, 0x04840c44, 0x82863721, 0x003f2c6f, 0x01c1012b, 0x003a00d5, 0x82740067, 0x262626a3, 0x36173636, 0x06376d36, 0x33361727, + 0x06161732, 0x28748207, 0x06061616, 0x17070627, 0x27048223, 0x26220606, 0x27022e27, 0x2622cf82, 0x32820627, 0x34263723, 0xb7711837, 0x17162207, + 0x08175737, 0x37361723, 0x264b8226, 0x26273435, 0x82372627, 0x8222202b, 0x0716233d, 0xcb821706, 0x37362108, 0x22230627, 0x52160727, 0x1f10060d, + 0x16350f0e, 0x18201802, 0x06263302, 0x080c190b, 0x07070d06, 0x20281782, 0x1c0d0f0e, 0x100d1527, 0x032b1b84, 0x15040a0d, 0x0f0c1d28, 0x82101f0f, + 0x23490820, 0x0a170705, 0x0a09080a, 0x3e2b1020, 0x0720112b, 0x1318080c, 0x0a180608, 0x2c1e0c0c, 0x2a0c320c, 0x0a0c0c20, 0x0d280d58, 0x0c1e1008, + 0x1e0c100f, 0x0a340110, 0x060a1c1f, 0x10051e10, 0x0c101515, 0x0e150327, 0x3c160a1f, 0x25158416, 0x2e40090f, 0x18830306, 0x0303012a, 0x09402e02, + 0x1c0a060f, 0x56081e83, 0x1916120d, 0x12130215, 0x48080814, 0x2a1e1b13, 0x16191e2a, 0x140c0547, 0x16180125, 0x13021612, 0x0b211614, 0x210b1616, + 0xbd131416, 0x06021010, 0x44050544, 0x00050006, 0x01a0003d, 0x006b01c3, 0x00120009, 0x0028001b, 0x25000036, 0x36262723, 0x16323333, 0x82170707, + 0x3737280a, 0x36171636, 0x82171736, 0x05ac430f, 0x82262721, 0x17322713, 0x36270517, 0x07823637, 0x31081882, 0x01222306, 0x01104c26, 0x0846080c, + 0x0e7e010c, 0x120a2d26, 0x91120822, 0x22091002, 0x262c0b12, 0x0c0705d5, 0x06050506, 0x05180512, 0x270f0115, 0x08820e07, 0x05071138, 0x070d0505, + 0x0e0a93c0, 0x781b0a0e, 0x130b1357, 0x0b0b0a05, 0x0882050a, 0x031d5736, 0x090c0a0c, 0x2609091b, 0x190d1d1d, 0x0a1b0909, 0x000c0a0b, 0x22090772, + 0x82170003, 0x233528aa, 0x16321315, 0x7c071415, 0x262b08d6, 0x33363435, 0xab562b01, 0x5e2a3223, 0x2a350559, 0x55c02332, 0x32000155, 0xb6193123, + 0x111a1a11, 0x233119b6, 0x08a25032, 0x0700eb2d, 0x1c001800, 0x2c002400, 0x18004200, 0x270802b4, 0x23153337, 0x23352315, 0x23086b4d, 0x23273307, + 0x8210cd55, 0x141525fd, 0x35222323, 0x07858882, 0x36372008, 0x0c12a233, 0x520d120c, 0x6e2b15ae, 0x261a2d0f, 0x23131a26, 0xbb1cf45b, 0x0f0f16ac, + 0x84a50f16, 0x0ed22705, 0x160a2306, 0x0382d60a, 0x0f052323, 0x05d46c01, 0x2a2b1e2b, 0x34262a2a, 0x56fd1926, 0x872982ab, 0x0fb13602, 0x0a0a926a, + 0x0b0a2020, 0x000f6a91, 0x00550005, 0x01ab012b, 0x2ab682c0, 0x002b0027, 0x003b0033, 0x85213700, 0x160122ac, 0x218e8e17, 0x3f523736, 0x33372605, + 0x32171633, 0x45c48207, 0x2621057a, 0x2dcb8722, 0x96560155, 0x1b01962a, 0x0a102203, 0x0382d610, 0x04041d30, 0x030a0401, 0x080cb603, 0xf41cce01, + 0x8884d11d, 0xb784b420, 0x402a953e, 0x06480140, 0x11118b66, 0x11111919, 0x010e568b, 0x05010205, 0x0b010106, 0x86565609, 0x34202384, 0x9e822f84, + 0x40002b24, 0xa882d501, 0x2c00272c, 0x34003000, 0x3c003800, 0xac824000, 0xc3613520, 0x83332005, 0x16162c07, 0x23153317, 0x23270606, 0x6d363215, + 0x15290773, 0x21150614, 0x23353736, 0x28048415, 0x33152337, 0x35331527, 0x25038207, 0x21072103, 0x00831555, 0x1910803c, 0x02d5d502, 0x022b1019, + 0x17120207, 0x3120400d, 0x99fe0144, 0x0f153904, 0x00822b46, 0x27082583, 0x2aaa0155, 0xb5a0aafe, 0x16151516, 0x11190115, 0x011b1115, 0x1e090196, + 0x0231442b, 0x2b100108, 0xb208a49a, 0x16401515, 0x2b270082, 0xebfe1515, 0x8202002b, 0x012b3aa1, 0x00d901c0, 0x0036000e, 0x35322500, 0x07272734, + 0x33141506, 0x15333533, 0x24488237, 0x23230614, 0x053f6b15, 0x37343535, 0x26263537, 0x37363637, 0x23151636, 0x06222634, 0x82321614, 0x8c013c23, + 0x90900509, 0xd6210905, 0x161e1f36, 0x1621d621, 0x168c1f1e, 0x1c040418, 0x522e1e13, 0x2b0805c6, 0x0709d50c, 0x02404002, 0x16160a06, 0x01220d39, + 0x80801d16, 0x2101161d, 0x080d3f0d, 0x1b131829, 0x1e260504, 0x120d0d09, 0x1f090c0c, 0x552d9582, 0xab014000, 0x0900c001, 0x00001700, 0x6d781837, + 0x33132408, 0x83272315, 0x3634258d, 0xc0153333, 0x2b05f46a, 0x402b2bc0, 0x2c3f6b80, 0x0996eb80, 0x012b3e82, 0x4040ab6b, 0x403f2c40, 0x70000600, + 0xd52c0515, 0x10000300, 0x30001400, 0x44003400, 0x2d054543, 0x35331535, 0x35262627, 0x14152335, 0x0c823707, 0xea861720, 0x13822220, 0x3620e682, + 0x22099252, 0x82251714, 0x3507211f, 0xd8568483, 0x01460809, 0x159696ab, 0x2b161912, 0x1d4d162b, 0x11961119, 0x0f141d19, 0x0940090c, 0xc7fe0f0c, + 0x1880552a, 0x2b802b13, 0x2b551813, 0x2121cc2b, 0x13240607, 0x0f2e0606, 0x61161683, 0x11cc1f0a, 0xcc111919, 0x05060a1f, 0xb0835b10, 0x060e5b31, + 0x80404004, 0x2015abab, 0x2a2a4407, 0x82200744, 0x002630af, 0x01da0155, 0x000900ab, 0x0040003a, 0x43213700, 0x372607f1, 0x23060722, 0xde4e3235, + 0x8d332005, 0x15172107, 0x20059e5d, 0x06a65d06, 0x253b0784, 0x32362621, 0xaa012b16, 0xaafe1119, 0x0b471911, 0x0b19160d, 0x1718170d, 0x8d0c0d17, + 0x18192207, 0x20128316, 0x35078b16, 0x56fe5701, 0x7eb87e05, 0x1a112bab, 0x0860111a, 0x0e082a0d, 0x0387080e, 0x080d2a24, 0x03850d08, 0x4c344b23, + 0x20b7824c, 0x2eb78215, 0x009501d5, 0x0011000d, 0x0100001b, 0x82231533, 0x069b49b9, 0x23372725, 0x41212717, 0x013b0744, 0x26406a6b, 0x1a262634, + 0x1e94090d, 0x01691e95, 0x802b802b, 0x4095012a, 0x82261ac0, 0x6e032617, 0xc0552b2b, 0x2b048255, 0x42000100, 0xc0012b00, 0x0a00d501, 0x173e5282, + 0x35231523, 0x37233723, 0x556b0117, 0x53945496, 0x01959429, 0x55558000, 0x00d5d580, 0x8c6b0005, 0x00132107, 0x2407ec4c, 0x15050100, 0x18018321, + 0x22096190, 0x43052535, 0x172a0661, 0x37152335, 0x01150735, 0x6782ffd5, 0x472d0383, 0x4739aa39, 0xfe6a0140, 0x151515ab, 0x3403822b, 0x221ec001, + 0x5f3a6b15, 0x17252517, 0x2aab3a5f, 0x2f1a183d, 0x2300836b, 0x1d021f80, 0xf62c7186, 0x0c00e101, 0x27001a00, 0x37003400, 0x3636a482, 0x37272734, + 0x14151617, 0x17270707, 0x17323336, 0x26270717, 0x0d822223, 0x1a8c2720, 0x87372721, 0x222a081c, 0x17130107, 0x07074101, 0x11221722, 0x77164d11, + 0x13171613, 0x08231622, 0x22080a0b, 0x07077317, 0x110c170d, 0x6c170c11, 0x19837817, 0x0d160c2d, 0xfe081608, 0x01c06a7e, 0x82160783, 0x13222d21, + 0x4d131617, 0x11113317, 0x08221623, 0x8c261082, 0x0c071807, 0x16830c17, 0x6c170d30, 0x11117816, 0x080d170d, 0x01bffe08, 0x4c54c02a, 0x2a098308, + 0x0020000f, 0x00300028, 0x5a3e0036, 0x342e0c2f, 0x14062226, 0x14153327, 0x27222306, 0x0e833335, 0x23351523, 0x23148206, 0x34363216, 0x2408b656, + 0x23353632, 0x821f8214, 0x26223a27, 0x0d128c01, 0x5e0c120d, 0x120c0c12, 0x44ea2a0d, 0x6a1a1b31, 0x401f2c1f, 0x2b168a77, 0x6a1f2c61, 0x6244ea40, + 0x0c540144, 0x2a822783, 0x602b0282, 0x0d44318b, 0x13130d3e, 0x5b55350d, 0x69250ad3, 0x180d0d13, 0x201b828b, 0x06ab5344, 0x2409cb5b, 0x001b0013, + 0x05cf4335, 0x23351724, 0x03822715, 0x84351721, 0x871520a5, 0x0f7a789c, 0x44183320, 0x013108da, 0x55555580, 0x2c152a16, 0x1c4e2c28, 0x121c1212, + 0x09d94fcb, 0x111a6b36, 0xe01a112a, 0x20402020, 0x6b6ba020, 0x120e10c0, 0x80100e12, 0x12252482, 0x111a7d1c, 0x202983eb, 0x068d4ceb, 0x01004022, + 0x2b067242, 0x000f00eb, 0x15170100, 0x07273523, 0x373d0482, 0x17073335, 0xc0150123, 0x95413f95, 0x15156ac0, 0x86860140, 0x2b2b6ad5, 0x6586d56a, + 0x05e44421, 0xab01152d, 0x1200d501, 0x00001e00, 0x82262637, 0x06e4499b, 0x14151627, 0x27070706, 0x08148217, 0x22062745, 0x92020e27, 0x171f2419, + 0x435c4304, 0x231f1704, 0x45456e19, 0x01050144, 0x011d421d, 0x02eb0202, 0x24171925, 0x3e3e2d04, 0x1724042d, 0xd6022519, 0x018484e2, 0x12120104, + 0x00020301, 0x00150003, 0x82d6012b, 0x00112f65, 0x00270023, 0x16322500, 0x35270715, 0x63831733, 0x27232325, 0x18131707, 0x210841b2, 0x8282022e, + 0x32334708, 0x23153305, 0x1912ab01, 0x9b2a96ab, 0x3c0b0f11, 0x402c0725, 0x291d2317, 0x2c2c2a2a, 0x1d2a2a2a, 0x56d7fe22, 0x11199556, 0x39c02a40, + 0x0f0a1107, 0x0110140e, 0x1d291a26, 0x28293d16, 0x163d2928, 0xeac0291d, 0x88430400, 0x82082008, 0x001c22e0, 0x217a8224, 0x73183536, 0x088407f1, + 0x07141522, 0x82053b54, 0x4f07208a, 0x380805c7, 0x39013426, 0x191d1c1c, 0x15152619, 0x2611111c, 0x091d0c0c, 0x7db01109, 0x8e7db07d, 0x383a3939, + 0x3264310f, 0x2f2e250e, 0x25240e28, 0x1a121f24, 0x0d1b181b, 0x13151412, 0x232082fc, 0x0500b07d, 0x6b317482, 0x9501d501, 0x0f000700, 0x19001300, + 0x00003100, 0x06725a24, 0x20073474, 0x2fde8227, 0x35363216, 0x15251423, 0x06142307, 0x23352622, 0x3323f783, 0x82373315, 0x32332209, 0x06c44216, + 0x26340530, 0xea263426, 0x12216a6a, 0x15012b0d, 0x0d826060, 0x23322a29, 0x404b4b55, 0x48191140, 0x492005c4, 0x26361382, 0xc02bbb34, 0xc909090d, + 0x261a7848, 0x23401a26, 0x395d6b32, 0x0241192a, 0x000f2a0a, 0x0026001e, 0x3700002a, 0x2f658235, 0x14151532, 0x35222123, 0x25333435, 0x35262627, + 0x14231382, 0x82150707, 0x3a158496, 0x13141521, 0x95233533, 0x0a0a6056, 0x0a0aeafe, 0x0e094b01, 0x0a208014, 0x8235552a, 0x2a012a0e, 0xab2b2b2b, + 0x150b2a2a, 0x3102820b, 0x320f0902, 0x31cbca14, 0x2a560b23, 0x0a20200a, 0xc44f2a01, 0xab300809, 0x0d000900, 0x33130000, 0x07173717, 0x17372721, + 0x21072117, 0x22567fc0, 0xccfe3b1e, 0x05221e3b, 0xfe0f2001, 0x48ab01fe, 0x3b3b1e21, 0xc04e211e, 0x2c08c942, 0x002b00d5, 0x23150100, 0x23270717, + 0x27048215, 0x07352315, 0x23353727, 0x23220482, 0x49823335, 0x82353321, 0x82b68204, 0x33152158, 0x01320482, 0x1e4559d5, 0x1f642b63, 0x1f452a45, + 0x1e632b64, 0x108f5945, 0x98150121, 0x352b881a, 0x15000600, 0xeb016b00, 0x03009501, 0x0f000b00, 0x1b001700, 0x8a822f00, 0x200a8b4a, 0xe9da1827, + 0x3327230a, 0x05192335, 0x012c1374, 0x15566b40, 0x13131a28, 0x5540131a, 0x2a05dd43, 0x01555520, 0x2636802b, 0x82752634, 0x192b2603, 0x56150112, + 0x251f82e0, 0x56771a13, 0x08868a56, 0x6a802a26, 0x1a26261a, 0xc02e0383, 0x01001812, 0x8d000000, 0x73010002, 0x09822d00, 0x14163228, 0x22232306, + 0xfa822726, 0x30054c4a, 0x07070607, 0x34262206, 0x32333336, 0x07171716, 0x05104927, 0x3736373a, 0x605d0137, 0x01304343, 0x1b0f2f13, 0x3c161920, + 0x153c2a2a, 0x213c1347, 0x14251484, 0x211b0e2f, 0x32148818, 0x5e447301, 0x180e1444, 0x2a16151c, 0x3e152a3c, 0x8f213512, 0x02002210, 0x05ca5300, + 0x1700c732, 0x00001b00, 0x07262601, 0x07171636, 0x06372626, 0x34250683, 0x36333437, 0x08098217, 0x07173724, 0x83327401, 0x3173303e, 0x0631317a, + 0x3d322015, 0x46013f3f, 0x99385162, 0x011f891f, 0x15203244, 0x1a823106, 0x3e307323, 0x201a8283, 0x271b82b3, 0xb8380608, 0x001e8a1f, 0x09998518, + 0x1d000324, 0x64822b00, 0x15233524, 0x16493233, 0x5f0b8206, 0xeb820549, 0x33373525, 0x6e071517, 0x2e080730, 0x35352622, 0x562b0133, 0x191911d6, + 0x80568011, 0x11191812, 0x2b552b55, 0x19955680, 0x12d6fe12, 0x6b019519, 0x111a2a2a, 0x2b1a1140, 0x8212192b, 0x2b2a2d06, 0x15c02a2b, 0x19191255, + 0x06005512, 0x8746d986, 0x052b6105, 0x85463720, 0x05684109, 0x2009365e, 0x06cb4326, 0x50181787, 0x52231076, 0x8712121c, 0x05f94102, 0x14850585, + 0x0bd36618, 0x44630120, 0x84d22005, 0x8a4e2019, 0x21118505, 0x9e7d2e01, 0x0005350c, 0x01400015, 0x00c001eb, 0x00250005, 0x004d0045, 0x37000055, + 0x07c8cb18, 0x16323723, 0x065e6d33, 0x2626232b, 0x22070622, 0x06222326, 0x23148314, 0x06251633, 0x29070a5c, 0x27262627, 0x36373426, 0x01823736, + 0x16173224, 0x02821617, 0x34241422, 0x2005fb44, 0x30078636, 0x340cc0a0, 0x66213440, 0x04010d4f, 0x1a1a1101, 0x21068211, 0x0e8d4f0d, 0x046b0138, + 0x5f161522, 0x1f384739, 0x0423150f, 0x23040202, 0x361d1115, 0x0e853692, 0x10c5fe3a, 0x160f0f16, 0x10160f5b, 0x1dd51610, 0x3c4d2323, 0x221a012f, + 0x3c2f011a, 0x4b2e0887, 0x2f062816, 0x221b313f, 0x08162806, 0x0d82080c, 0x30182625, 0x84211d30, 0x831b200e, 0x833a8237, 0x06c64402, 0xd501c02a, + 0x0f000700, 0x2e002900, 0x56095245, 0x252207bd, 0xbd561516, 0x06232305, 0x50712306, 0x35233305, 0x14211733, 0x16320306, 0x5e012315, 0x1a13131a, + 0x0584ad13, 0x1911013a, 0x2a1c1f2b, 0x29042d04, 0x272c1f1c, 0x144a2f2d, 0x96153701, 0x55ab6447, 0x02872382, 0x21174535, 0x1b252b1f, 0x1f2b251b, + 0x2b5e162c, 0x013d182b, 0x44466415, 0x1b200aa1, 0x5a094757, 0x2724067b, 0x17372737, 0x07200183, 0x012f0582, 0x1e2d1eb7, 0x1f2d1f1e, 0xb74c1f1e, + 0x8c1e1e4c, 0x83c3200d, 0x20118317, 0x821b821e, 0x88258221, 0x0e0f680d, 0x68001921, 0x13191a0f, 0xa9662552, 0x01c02b05, 0x000f00d5, 0x01000017, + 0xd0181507, 0x33210a67, 0x07166011, 0x6b012108, 0x4b3c2e80, 0x2b404b6a, 0x121c12c0, 0x82011c12, 0x1802c142, 0x19191110, 0x250c1911, 0x7dfe8001, + 0x12231583, 0x4a000800, 0xc02205e1, 0x4e180e00, 0x2e24083d, 0x4a004200, 0x162c5a82, 0x37230707, 0x37262736, 0x06073337, 0x8205c250, 0x200f870e, + 0x068a5513, 0x07862320, 0x50333721, 0x67570846, 0x08336708, 0x06213928, 0x05032901, 0x06822215, 0x13050227, 0x02062257, 0x20078228, 0x23078602, + 0x2b2b2a09, 0x83210283, 0x05564ce7, 0x131d403d, 0x041d1014, 0x19241875, 0x83012419, 0x0c092f20, 0x2e22151b, 0x141b0d09, 0x822e2101, 0x0114210c, + 0xfe220d85, 0x008680d1, 0x2606066c, 0x101c1410, 0x83640521, 0x4f192037, 0xd52008ee, 0x2906ae65, 0x001f000f, 0x15331300, 0x03821123, 0x21351723, + 0xe6931815, 0x2aab2113, 0xbe4b0082, 0x19122108, 0x3b050751, 0x00011219, 0x4000016b, 0xeb6b6b15, 0x8001c1c1, 0xaafe1218, 0x11191911, 0x18125601, + 0x200ac26c, 0x24618207, 0x00810051, 0x08036300, 0x26272230, 0x26273727, 0x16323523, 0x07061717, 0x10822306, 0x06072223, 0x125b4d05, 0x8c4d2320, + 0x3316211a, 0x870f8d4d, 0x0bbd4d40, 0x16173222, 0x0808c44d, 0x1f2b0127, 0x2c1f1f2c, 0x040d0c91, 0x2015450c, 0x18342935, 0x0d030689, 0x160d0b0c, + 0x010d1632, 0x0b171711, 0x170b0d0e, 0x93078f18, 0x8e238313, 0x17302727, 0x0b0e0d0b, 0x2e8a1717, 0x18201287, 0x01211a82, 0x377c8375, 0x03085520, + 0x20164505, 0x88181335, 0x08080104, 0x60080d0d, 0x0e07070e, 0x2b200387, 0x0e220a89, 0x19988b07, 0x0a178218, 0x13000f2b, 0x16010000, 0x36211716, + 0x08865436, 0x21053208, 0x27012115, 0xfe04563f, 0x3f560480, 0x19241904, 0xaa0100ff, 0x5a0156fe, 0x4141610d, 0x09080d61, 0x12181812, 0x002acd09, + 0x002b0006, 0x01d50115, 0x245282d5, 0x00290019, 0x0559792d, 0x3327252b, 0x34262227, 0x22153336, 0x05167e06, 0x15151629, 0x26343523, 0x87163723, + 0x32352a09, 0x14333536, 0x23153307, 0x08038237, 0x0137255a, 0x35232707, 0x3f6b0133, 0x2a1d363f, 0x16111d2a, 0x1e211017, 0x1119202c, 0x20251e3c, + 0x17102431, 0x20202720, 0xfe202035, 0x6b011a76, 0x95d5951b, 0x2b5b3fac, 0x15202a3a, 0x271a1110, 0x141b221c, 0x3a0e5217, 0x242c2c24, 0x11172033, + 0x4040c21e, 0xfe1bd540, 0x40961b95, 0x2208774a, 0x511600d5, 0x002208fc, 0x88873201, 0x86059b58, 0x829f8da9, 0x823520b0, 0x26a58927, 0x01211521, + 0x822b1f56, 0x87212095, 0x865d20a4, 0x1017239e, 0xa1872a1d, 0xfe40012b, 0x262601c0, 0x141c231d, 0x27a38717, 0x233a0e35, 0x32243030, 0xcb829d82, + 0x1e1d2a23, 0x21a282c5, 0x874a4040, 0x0000260a, 0x000a0001, 0x3306821a, 0x07063707, 0x36362726, 0x32051637, 0x36361716, 0x07061433, 0x45081183, + 0x95012626, 0x202a94df, 0x2c032a20, 0xe7fe431c, 0x21217044, 0x4c5f4470, 0x15151911, 0x22015f4c, 0x22173322, 0x5f271722, 0x4267431c, 0x54423333, + 0x05061b86, 0x861b0803, 0x15000200, 0xd0011500, 0x0800d001, 0x60821700, 0x1533272c, 0x35271133, 0x15230723, 0x434a3533, 0x33270805, 0x01372735, + 0x6ab5b52b, 0x1640402a, 0x891cd02b, 0x1b562beb, 0x15b50b01, 0xb52bf5fe, 0xd0152a6b, 0x2b5f8a1b, 0x481c55f4, 0xc02708ee, 0x11000300, 0x82130000, + 0x11372541, 0x11333523, 0x33375383, 0xd5112315, 0x2beb2b2b, 0x552b6ac0, 0x2a2a1501, 0x2bc0fe6b, 0x83155501, 0x82402005, 0x00003cdf, 0x0100022b, + 0x004e00d5, 0x14160100, 0x23060707, 0x22060727, 0x1707022f, 0x83232314, 0x25068307, 0x07233735, 0x0f821617, 0x85272721, 0x089a8207, 0x352635b2, + 0x26371621, 0x16171637, 0x27262736, 0x37262722, 0x16163334, 0x021e1717, 0x01171407, 0x190101ff, 0x070f0202, 0x0e020902, 0x04112f17, 0x14020214, + 0x1504190a, 0x23871704, 0x14060208, 0x221c0103, 0x16060206, 0x17150d04, 0x2f301201, 0x081c0e08, 0x09020907, 0x0c020124, 0x291d0402, 0x07030407, + 0x01020105, 0x0103013e, 0x16030220, 0x051e0404, 0x03048870, 0x03621151, 0x44428704, 0x27660205, 0x3802053c, 0x15099052, 0x0e162201, 0x0b040514, + 0x010e1c07, 0x04030503, 0x04031125, 0x05080f08, 0x00020002, 0x01950040, 0x006b01c0, 0x00280016, 0x20055a5f, 0x0b627e33, 0x35363229, 0x33052335, + 0x18152315, 0x2d08c146, 0x23353335, 0x6a2a6b01, 0x6a121995, 0x04841912, 0xd5fe552f, 0x116b6b6b, 0x40111919, 0x2beb956a, 0x84168380, 0x2a553d04, + 0x12192b2b, 0x2b19112b, 0x0003002b, 0x0115006b, 0x00eb0195, 0x0013000f, 0x01000017, 0x0aa19318, 0x34113528, 0x11230326, 0x6a820733, 0xd66b0122, + 0x04854a83, 0xaac0d628, 0x19eb01aa, 0x4f84fe12, 0x05820120, 0x0180fe33, 0x002b152a, 0x00150004, 0x01eb0115, 0x000d00ab, 0x200b8211, 0x82be8321, + 0x0511529b, 0x3335332b, 0x33352307, 0x21152127, 0x08196801, 0x35332908, 0x152b4001, 0x16c0fe15, 0x8055c016, 0x01956b6b, 0x01c0fe40, 0x40402b80, + 0x4095402b, 0x2b6b6b2b, 0x55558080, 0x00ff2bd6, 0x40201183, 0x5520b283, 0xeb226384, 0xb0820b00, 0xb2822820, 0xd8561520, 0x25688206, 0x35363203, + 0xc3832634, 0x37161422, 0x332d1782, 0x07141516, 0x3e343526, 0x01323302, 0x844184ab, 0x19122fb3, 0x3e403d19, 0x1cabab02, 0x16223d30, 0x6c82eb01, + 0xff230282, 0x82111900, 0x11123219, 0x4050d019, 0x926a0c0e, 0x40286a92, 0x0600192e, 0x20728500, 0x748218ab, 0x2500210c, 0x0320c48a, 0x25248382, + 0x13231133, 0x8f840782, 0x01210782, 0x28c584ab, 0xfe2b2b6b, 0x962b2bd5, 0x2000842a, 0x27848480, 0xc02b012b, 0x01aafec0, 0x2105647c, 0xb6710300, + 0x82cb2006, 0x00232360, 0x5a82002f, 0x3d693320, 0x23072d08, 0x26272722, 0x33363737, 0x17173233, 0x0732dc82, 0x17072327, 0x06271633, 0x37272315, + 0x07061733, 0xdb860727, 0xc83f2208, 0x0c330c19, 0x190c870d, 0x600c1964, 0x09091111, 0x32876451, 0x080f0ba8, 0x2662107a, 0x2a0d1236, 0x3a7e853b, + 0x57160b40, 0x15e91615, 0x0104a515, 0x1957e98c, 0x1b161579, 0x130d5fab, 0x6d00674b, 0x0b20094e, 0x21087c48, 0x8d570100, 0x33352705, 0x11153335, + 0x9c821121, 0x15062223, 0x9f981811, 0x23232507, 0x07353315, 0x20081482, 0x15233507, 0x2a40d501, 0xfe2a4040, 0x128080d6, 0x01121919, 0x2b19122a, + 0x2a802b55, 0x012b2b2a, 0x26198395, 0xd6fe4040, 0x4c2b2a01, 0x192a053a, 0x56568012, 0x80abab56, 0x49180080, 0x2f0809a7, 0x00250015, 0x003f0031, + 0x16320100, 0x07273517, 0x021e1415, 0x37363617, 0x34352626, 0x22173636, 0x14150606, 0x32331616, 0x34353636, 0x32072626, 0x82069a4a, 0x2217231c, + 0x22822726, 0x32332008, 0x06151616, 0x056b0106, 0xa0a0050b, 0x223b2b18, 0x0b081109, 0x243a220c, 0x17172718, 0x83171827, 0x172a0805, 0x090f0e0a, + 0x0a0e0e0a, 0x1208190f, 0x17070816, 0x01180811, 0x67010115, 0x24694646, 0x08283944, 0x0f040602, 0x3a241426, 0x32882a22, 0x1e243e82, 0x0f090a0e, + 0x722d3883, 0x0b070c0d, 0x070b0505, 0x06000d0c, 0x050d6e00, 0x1e00c42c, 0x3a002e00, 0x79004500, 0xbf868900, 0x2326342f, 0x27372723, 0x17371707, + 0x23061415, 0x259a8223, 0x33070614, 0xc890023e, 0xdf832220, 0x2682bb82, 0xf1432520, 0x16142707, 0x26372717, 0x04820727, 0x06222326, 0x27071707, + 0x15200485, 0x37231882, 0x82160717, 0x16072855, 0x37363233, 0x85173727, 0x34352104, 0x2c082e82, 0x27262606, 0x37363626, 0x17161636, 0x01060616, + 0x0b1b0fa0, 0x16871119, 0x104c0f1e, 0x1119161e, 0x01120f0c, 0x1a034301, 0x21151929, 0x23028815, 0x0d13130d, 0x21080382, 0x196ba8fe, 0x0d084012, + 0x1404850d, 0x0a08230f, 0x08141309, 0x0a070711, 0x13122208, 0x03081304, 0x17961303, 0x21114c28, 0x0507071b, 0x07861014, 0x0900012a, 0x19126507, + 0x4b0f1e17, 0x312b7582, 0x2b111912, 0x050b0519, 0x89172618, 0x207c8273, 0x8275846b, 0x12c02779, 0x08090d19, 0x69a1670d, 0x5b20818c, 0x7a83728a, + 0x00030023, 0x064d5640, 0x11000739, 0x00003800, 0x26260713, 0x16163727, 0x33072737, 0x26371716, 0x82213526, 0x020e2409, 0x83060607, 0x1e072a19, + 0x30301502, 0x33153131, 0x08068235, 0x36363451, 0x37033e37, 0x0b1fd133, 0x052a0714, 0x5556220e, 0x2a030140, 0x15010201, 0x01405655, 0x080d1810, + 0x0d050710, 0x0f0a1e06, 0x110a2a08, 0x14170b0c, 0x0140010d, 0x1e0b1e12, 0x150e0b15, 0x1b555566, 0x12080a13, 0x2755550a, 0x070c1c2e, 0x82080b10, + 0x12092e2b, 0x6a6a141a, 0x0b131a16, 0x3323180a, 0x974b1825, 0x000f2c0a, 0x00170013, 0x001f001b, 0x43210100, 0x11270a56, 0x23032634, 0x5a173335, + 0x0783065b, 0x0cf69b18, 0x2b2be724, 0x00822a55, 0x2b2b5624, 0x4d43c001, 0x2a012c07, 0xd5fe1912, 0x2b406b6b, 0x59d6962b, 0xd52808fb, 0x3b002f00, + 0x17250000, 0x3524f182, 0x35233533, 0x20053943, 0x05494323, 0x23151735, 0x2e153315, 0x27372702, 0x021e1415, 0x023e3233, 0x43273535, 0x27080a55, + 0x0b216b01, 0x40182f25, 0x11181340, 0x1d12121d, 0x40131811, 0x252f1840, 0x2355210b, 0x21214339, 0xc0233943, 0x090c0c09, 0xc02b0382, 0x141e1221, + 0x192bbe04, 0x82142107, 0x3e2e8228, 0x19072114, 0x1404be2b, 0x4021121e, 0x29361f40, 0x36291717, 0x0dab401f, 0x0d0d0809, 0x570d0908, 0x192e0ace, + 0x37002800, 0x56004700, 0x22010000, 0x01820706, 0x8f850620, 0x82373621, 0x35362c01, 0x03022e34, 0x35262622, 0x83373634, 0x060622a6, 0x210d8d37, + 0x0f842306, 0x33363728, 0x15161632, 0x2f823714, 0x86362321, 0x0106290c, 0x13472b40, 0x2c24162a, 0x0a897e83, 0x311d9f25, 0x830a0c1d, 0x210d2213, + 0x200b8a2e, 0x22e68252, 0x84071d31, 0x852a2005, 0x8312201e, 0xd501281e, 0x2917242c, 0x832b4713, 0x210a8ac9, 0x1d8280fe, 0x0d211222, 0x0a221683, + 0x0c8b400c, 0x83074721, 0x8512200d, 0x841f8505, 0x47f9821e, 0xeb2a052d, 0x09000300, 0x15000f00, 0xf9821b00, 0x37270729, 0x27371735, 0x83071707, + 0x37372204, 0x200c8307, 0x230f8207, 0x2b012737, 0x2d2b0082, 0x36636336, 0x63352d53, 0x84d33563, 0x84532005, 0x00012111, 0x55201b82, 0x2d20108a, + 0xad201684, 0x00291184, 0x006b0004, 0x01d50115, 0x246682eb, 0x00210018, 0x45688239, 0x34370f46, 0x17323336, 0x17352607, 0x16372722, 0x23061415, + 0x33112307, 0x18353315, 0x2a0db69b, 0x01233535, 0x17261880, 0x84182617, 0x1f4d2705, 0x480c0d16, 0x04833506, 0x15161f27, 0x192ad6d6, 0x05254811, + 0x2a191124, 0x26875501, 0x55272c83, 0x48061f16, 0x83350d0c, 0x1f162404, 0x5200014b, 0x45480521, 0x00552605, 0x00550008, 0x028d1855, 0x0014220c, + 0x05d1561e, 0x23078774, 0x23153335, 0x172f0383, 0x33152335, 0x22262737, 0x37170707, 0x83073436, 0x8227200c, 0x56d5241b, 0x84568056, 0x56d63800, + 0x0219b434, 0x26130307, 0x25d50312, 0x5624258e, 0x56ab0156, 0x82d656aa, 0x345e3101, 0x03193a56, 0x13251303, 0x26920802, 0x56a2258f, 0x33060749, + 0x00eb01d7, 0x004c0040, 0x25000064, 0x36373527, 0x23262727, 0x26206282, 0x08830783, 0x15221422, 0x2406e259, 0x15171706, 0x31048207, 0x33323316, + 0x17171637, 0x32333316, 0x36323737, 0x0a823731, 0x36220982, 0xcc450727, 0x5c07200a, 0x112208dd, 0x29823634, 0x82151621, 0x232108c6, 0xd1013311, + 0x04061111, 0x01060212, 0x01031402, 0x24080103, 0x02030108, 0x01021402, 0x04120305, 0x261c8906, 0x01040202, 0x82072507, 0x02012622, 0x05020115, + 0x211d8202, 0xac450d51, 0x41222005, 0xd6330b70, 0x040ef0d6, 0x1f07040e, 0x01080105, 0x07071601, 0x82010115, 0x20042a09, 0x050d0506, 0x2006040e, + 0x20168504, 0x24158316, 0x04071f05, 0x077a4510, 0x12554b27, 0x01121919, 0x08058380, 0xff15552a, 0x00040000, 0x01400088, 0x00c00179, 0x000b0005, + 0x0028001c, 0x37173700, 0x33272637, 0x17170706, 0x26342737, 0x15233527, 0x8b098a47, 0x05882ff0, 0x10163b23, 0x3b161076, 0x18390623, 0x37442a13, + 0x44402007, 0x23080625, 0xa2212f6f, 0x05101005, 0xe62f21a2, 0x2f062115, 0x1521062f, 0x12121d11, 0x080d041d, 0x090d0d09, 0x03000d08, 0x20085c58, + 0x357a8213, 0x0100002f, 0x15021e32, 0x23020e14, 0x35022e22, 0x37023e34, 0x0f820e22, 0x2406ae44, 0x23022e34, 0x2c8e8217, 0x01371723, 0x2f3e2300, + 0x3e2f1b1b, 0x27078723, 0x213b4d2c, 0x2c4d3b21, 0x15260787, 0x5555402a, 0x228bab01, 0x2a202a83, 0x2b83238b, 0x8255d521, 0x20889100, 0x20808625, + 0x22908633, 0x823e3207, 0x87808290, 0x15272690, 0x27333533, 0x2088a607, 0x4987a655, 0x3046091e, 0x142e4607, 0x35233724, 0x03823533, 0x240c2a46, + 0x4096967c, 0x460082d6, 0x2b240f27, 0x2b2b2a2b, 0x0a18a418, 0x00122308, 0x003a0018, 0x34350100, 0x22212326, 0x14031506, 0x35333316, 0x33363634, + 0x17352707, 0x15171537, 0x4f180614, 0x162108c5, 0x051c4415, 0x8e492782, 0x84352008, 0xab2d0861, 0x19011812, 0x1d11eb12, 0xabab8012, 0x12192baa, + 0x04061911, 0x202b0605, 0x171f1616, 0x27181727, 0x802b0117, 0x11191911, 0x191200ff, 0x3e26826b, 0x6b2b6b16, 0x55ab2b6b, 0x12191912, 0x07070460, + 0x16606004, 0x60161f1f, 0x17172618, 0x84551826, 0x011526a1, 0x00eb01eb, 0x06615307, 0x27373727, 0x17070727, 0x23048307, 0x17373717, 0x06820b82, + 0x9501272e, 0x1b3b3b1b, 0x863b3b1a, 0x76763535, 0x2a200382, 0x1a200b82, 0x01221382, 0x06833b40, 0x461a1b22, 0x76211684, 0x820f8735, 0x0578575b, + 0x0900c02a, 0x17001000, 0x11130000, 0x1125f583, 0x25062223, 0x33e18423, 0x36323303, 0x40233535, 0x80801219, 0x55011912, 0x9219ab80, 0xab200882, + 0x24056241, 0x19198001, 0x210e82ab, 0x1f8280fe, 0x250a2d42, 0x00110008, 0x504d0021, 0x21468205, 0x50821733, 0x08891520, 0x56836383, 0x26342408, + 0x11d62b01, 0x55d62a19, 0x2b1912d5, 0x12ab2bd5, 0xab121919, 0x01191911, 0xd61119d5, 0x12192bd6, 0x852ad5d5, 0x82112011, 0x08624d1b, 0x0700eb28, + 0x2d001d00, 0x62833300, 0x0723272a, 0x17211523, 0x21350722, 0x1622bc84, 0x94423316, 0x06304706, 0x08070547, 0x23270640, 0x27371715, 0x154b4001, + 0x014b156b, 0x1416152b, 0x111900ff, 0x2c49117a, 0x1829361f, 0x1f362918, 0x1c1c311d, 0x301e1d31, 0x13301d1d, 0x3e114d20, 0x1616d501, 0x5b066b2a, + 0x191100ff, 0x21833026, 0x17252982, 0x301d00ff, 0x242a881e, 0x192c6bc0, 0x06cf4624, 0x4556d520, 0x00172206, 0x299e8228, 0x27171300, 0x17270737, + 0x03820507, 0x0b823720, 0x85071121, 0x26073a08, 0x06070722, 0x16171714, 0x36373732, 0x07272734, 0x07173727, 0x1e1e35a0, 0x20038235, 0x8a048301, + 0x07842703, 0x07f80711, 0x06863107, 0x342e1626, 0x8901342e, 0x35222a84, 0x0786b435, 0x85000121, 0x3c35223c, 0x202c8207, 0x832d8211, 0x32062206, + 0x422d8375, 0x9d850643, 0x1d001825, 0x9c010000, 0xd5012189, 0x7a947e86, 0x699dd520, 0x2b002b22, 0x2206ad42, 0x8a270016, 0x07172269, 0x46eb8417, + 0x072005b8, 0x1720f482, 0x25080341, 0x01273717, 0xfb8236eb, 0x1e363536, 0x11342d94, 0x32060637, 0x37061107, 0x50113511, 0x8c921b92, 0x06230e82, + 0x828c0612, 0xeb01230a, 0x28841e1e, 0x342d4f24, 0x14823712, 0x82063221, 0x8e342126, 0x12212685, 0x830e8206, 0x08554e26, 0x0982eb20, 0x31001722, + 0x15238783, 0x58112537, 0x362c05b3, 0x16323336, 0x26261117, 0x01062223, 0x27200682, 0x06240a85, 0x023e1507, 0x5e081983, 0x36323316, 0x6a950135, + 0x0780fe6a, 0x01020204, 0x1f183816, 0x3f17173f, 0x013e201f, 0x0c150abe, 0x12142512, 0x0e0e2a2b, 0x1b122b2a, 0x03021734, 0xeb010704, 0x8b60eb6b, + 0x0604c7fe, 0x0e0d0a01, 0x124b0112, 0xcefe0e0e, 0x0a072001, 0x06e0fe04, 0x090f0805, 0x080f092b, 0x07010c0a, 0x4b050004, 0xeb2a06a0, 0x18000c00, + 0x28001c00, 0x9e823b00, 0xa8711520, 0x36372805, 0x27171736, 0x84150622, 0x343527a9, 0x35211326, 0x8e823721, 0xd94f3420, 0x82272006, 0x15232208, + 0x05145433, 0x3535363e, 0x01231523, 0x1c3a402b, 0x22062255, 0x12495812, 0x11121919, 0x01041919, 0xe000ff00, 0x3a062547, 0x40090c7e, 0x2b11192b, + 0x2b2b1912, 0x192a5501, 0x63d5c554, 0x27080f12, 0x83121996, 0x1912272e, 0x162a80fe, 0x2d830e12, 0x55120e26, 0x162a0c09, 0x11234182, 0x57002a40, + 0xab2205da, 0x9e49d501, 0x14112f06, 0x22212306, 0x34113526, 0x33353736, 0x03823315, 0x05161622, 0x33338c82, 0x19ab0135, 0x1200ff12, 0x401b2519, + 0x251b4056, 0x82d5d5fe, 0x00ff216a, 0x01274883, 0x082d1e00, 0x822a2a2d, 0x2b732304, 0xf44a552a, 0x8408200a, 0x002022ff, 0x23ff8224, 0x21152111, + 0x1121e682, 0x17064c27, 0x2135212a, 0xd5feab01, 0x19112b01, 0x07f64918, 0x192b6f82, 0x956b6ba7, 0x00ff6a6a, 0x18010001, 0x2007725a, 0x055c4555, + 0x01121922, 0xfe267f82, 0x6a6a6ad6, 0x75826b2b, 0x2b006b24, 0xcb829501, 0x13000f28, 0x30002600, 0x75823a00, 0x18222321, 0x22077653, 0x4c353536, + 0x35270573, 0x022e3423, 0x44363435, 0x0e250636, 0x31213702, 0x05b94834, 0x87232721, 0x0a125209, 0x2a2a6729, 0x1016102a, 0x82152115, 0x2f088202, + 0x1300ff6b, 0x130dc00d, 0x0d13d615, 0x01130d96, 0x134a8d82, 0xf6fe2b07, 0x180c1520, 0x14101d1a, 0x02821422, 0x1a1d1029, 0x120ee918, 0x83400e12, + 0x06fc5904, 0xd701b922, 0x00229f82, 0xe1472601, 0x36300807, 0x032e3736, 0x2e070136, 0x21223c50, 0x282c4d3b, 0x30133846, 0x081b384f, 0x2102d501, + 0x2c2d4e3b, 0x1b213b4d, 0x28012030, 0x00585242, 0x002b0004, 0x26052160, 0x000d0006, 0x82230017, 0x333527e3, 0x15151632, 0xe1823207, 0x03152323, + 0x07c34611, 0x51421720, 0x32332c07, 0x56550136, 0x112a1911, 0x842a8019, 0x137622aa, 0x8291830d, 0x801525bc, 0xaa561119, 0x80260382, 0xd6fe2a01, + 0x1e821119, 0x55429520, 0x00250806, 0x00000005, 0x01000240, 0x001600c0, 0x00490034, 0x00650059, 0x27333700, 0x23232626, 0x30173315, 0x06063130, + 0x21098207, 0xc2823435, 0x16872320, 0x33172322, 0x17251683, 0x17021e33, 0x058a4d16, 0x4c220721, 0x172305d8, 0x45302737, 0xa24b09ac, 0x0a534a0f, + 0x10d53b08, 0x0e180329, 0x231e5353, 0x80570631, 0x11d72717, 0x0e16041d, 0x79185454, 0x0a07580a, 0x320a3c02, 0x19291d04, 0x1c1f331e, 0x1d121e31, + 0x140b0c11, 0x01011428, 0x12121d11, 0x0584d21d, 0x15821120, 0x854d0882, 0x0d250805, 0x130fb4d5, 0x360b852b, 0x18152a25, 0x4f801726, 0x402b0f0d, + 0x0c150a2a, 0x1726172b, 0x321c0101, 0x1c301e1e, 0x252e82aa, 0x3808190f, 0x4785390e, 0xb3491120, 0x85112005, 0x0c55224e, 0x05dd4909, 0x0003003f, + 0x0140006b, 0x00d50195, 0x00350022, 0x37000041, 0x21150622, 0x23232634, 0x36323335, 0x05a54d35, 0x20052858, 0x063f4a37, 0x2205f36a, 0x18170706, + 0x25083490, 0x34070717, 0x844e3336, 0x11952b07, 0x192a0119, 0x12405611, 0x6e83ab19, 0x01090d35, 0x1c251d01, 0x160c1d31, 0x0d09091e, 0x07280714, + 0x83153a14, 0x4a152005, 0x6b2707d0, 0x19121219, 0x8212192a, 0x1122082e, 0x110d091d, 0x0c040604, 0x311d2136, 0x1f012a1d, 0x140c161f, 0x14072208, + 0xa107140f, 0x140e1408, 0xeb415608, 0x49132005, 0x1d260ced, 0x00002700, 0xd9493401, 0x3e32250a, 0x06172502, 0x2305814a, 0x27071405, 0x1e23a082, + 0x4ad50102, 0xfe2b0f38, 0x3e2befa5, 0x1b2f3e23, 0x87255601, 0x4a002009, 0x95240e85, 0x2f1b25ef, 0x3e222482, 0x09842b3e, 0x2a2c7982, 0xc0012900, + 0x0a00b901, 0x18001400, 0x43087982, 0x35361715, 0x23263411, 0x07271721, 0x16141117, 0x37172133, 0x17352327, 0x012a9501, 0xf6fe1219, 0x161b702a, + 0x07011219, 0xd5791b2c, 0xe08001dd, 0x0104062a, 0x2b191200, 0xfe161b39, 0x2c1912f8, 0xdddd3c1b, 0x220a7e73, 0x822b0013, 0x0e354b54, 0x06071325, + 0x18272722, 0x230e64dc, 0x01141617, 0x3d36af8f, 0x0308041e, 0x0f2a1449, 0x320b0612, 0x3115321e, 0x07090f12, 0xfc920349, 0x041ee12a, 0x08064804, + 0x15311110, 0x0b282882, 0x2a0f1206, 0x08034914, 0x240a0760, 0x001b000f, 0x228d821f, 0x5033002f, 0x072311f3, 0x75371737, 0x332d083d, 0x23172315, + 0x23352315, 0x33353335, 0x080b5115, 0x240cdc4a, 0x1e1e1791, 0x2d028416, 0x6baf1e17, 0x202a706b, 0x2a202b2b, 0x00826b8b, 0x200def4a, 0x82288257, + 0x1d162702, 0x101e171e, 0x25839020, 0x203b2a24, 0x4a182015, 0x9b830ced, 0x32002b22, 0x15239782, 0x7f073533, 0x262505b6, 0x06062726, 0x85058437, + 0x45052011, 0x23820732, 0x1117333a, 0x26341707, 0x36361527, 0x80558001, 0x06102510, 0x2510060d, 0x570d060f, 0x21080884, 0x060d0710, 0xb2fe250f, + 0x11191911, 0x6a162a16, 0x0e12a06a, 0x1501120e, 0x0b8d2a2a, 0x11090c1c, 0x05830c08, 0x1108f823, 0x84088209, 0x3d260805, 0x122a1219, 0x40555519, + 0x40400001, 0x8e0d2515, 0x0200250d, 0x2d004200, 0xe001b101, 0x11000d00, 0x01250000, 0x3c491707, 0x27073a09, 0xa5011737, 0xae53f0fe, 0x0c1e0d0d, + 0x0c5b0c24, 0x1e5b1e85, 0x531001d0, 0x2b0d82f9, 0x5a0d0d1e, 0x1e6c230d, 0x06001e5a, 0x2a08e260, 0x00180012, 0x002f0023, 0x41390035, 0xca820682, + 0x58112121, 0x11260552, 0x15012634, 0xf0823433, 0x16321523, 0x26098216, 0x1527022e, 0x84021e32, 0x173d0809, 0x35371715, 0x17073507, 0xfec00137, + 0x2b191280, 0x95958001, 0xfe191912, 0x1d114043, 0x1d301e12, 0x3629182b, 0x3446281f, 0x41242b1e, 0x4b4aa555, 0x7675754b, 0x1219c001, 0xd6fe4040, + 0x0510562b, 0xc0fe2208, 0x111d1240, 0x311d2a55, 0x29361f1d, 0x1e2b5617, 0x31284535, 0x18254055, 0x2a29292a, 0x40409528, 0x0a9a5840, 0xb5820520, + 0xa5821920, 0x23350729, 0x33271537, 0x18151632, 0x2c07f190, 0x17363411, 0x01113311, 0x402a4035, 0x0aa05876, 0x80150126, 0xd6568056, 0x080ba158, + 0x00ff6b20, 0x02000001, 0x55002a00, 0xae01d601, 0x28002500, 0x27250000, 0x27023e35, 0x26272626, 0xdc820606, 0x08086f44, 0x15150640, 0x16060607, + 0x3632023b, 0x17372526, 0x12b8cd01, 0x04040c1a, 0x2a18151f, 0x0d132b1a, 0x0e13130d, 0x08b80c08, 0xc00a0c01, 0x010c0ac0, 0x8080abfe, 0x0514897c, + 0x1514231a, 0x11050520, 0x1f461726, 0x090c2b05, 0x13068926, 0x0a130e0e, 0xd7606060, 0x4313200a, 0x01291186, 0x3a4e2c00, 0x4e3a2121, 0x2107862c, + 0x0c8ad501, 0xbb821484, 0x1500402a, 0xeb01c001, 0x3c001500, 0x23204282, 0x22079951, 0x82222315, 0x211521be, 0x26210f82, 0x20158417, 0x94c08222, + 0x36310808, 0x32333336, 0x01151616, 0x12191555, 0x1519122a, 0x011d301e, 0x22301d80, 0x08090d2a, 0x090c2b0d, 0x0d2b0c09, 0x2a0d0908, 0xaa121d11, + 0x01111d12, 0x058f4c15, 0x1d311c2e, 0x311d9696, 0x0940d51c, 0x40090c0c, 0x6b20058b, 0x4405fe45, 0x06220a68, 0x9e820d00, 0x8a820720, 0x01371738, + 0x23351737, 0xd5010717, 0x46ab4771, 0x7192fe71, 0x7147ab46, 0x0684b701, 0x8456fe21, 0x00220814, 0x001e0003, 0x01c4011e, 0x001c00c4, 0x003b0029, + 0x32211300, 0x14111516, 0x35362715, 0x23152335, 0x86523527, 0x1315220a, 0x057e4927, 0x27353426, 0x27270137, 0x35221f82, 0xc1482733, 0x92210809, + 0x19120301, 0x04200949, 0x0d202b27, 0x0d094008, 0xfdfe3891, 0x1e221912, 0x12d98801, 0x1b042b0e, 0x08158409, 0x19ab012b, 0x0100ff12, 0x0a064802, + 0x19270b16, 0x0d08160b, 0xfe04080d, 0x121937f7, 0x01010001, 0xfe1e2301, 0x0b129d78, 0x0a061b40, 0x8a1a8356, 0x000d22de, 0x06324312, 0x37112408, + 0x35363221, 0x07263411, 0x33350727, 0xaafeab01, 0x01551911, 0x1919112b, 0x6a353527, 0x1119d501, 0x495580fe, 0xea230582, 0x82aa2020, 0x002d2643, + 0x01d3013c, 0x2cf282ca, 0x2500002e, 0x27071737, 0x35363632, 0x05df5734, 0x22232626, 0x14150606, 0x372e1482, 0x26263727, 0x17070706, 0x37170723, + 0x27821735, 0x37173208, 0x2d260116, 0x15312d80, 0x04051422, 0x07392039, 0x22140a11, 0x26270414, 0x0c2d1e0f, 0x4c0c2121, 0x4b0f3c1e, 0x260f1f0f, + 0x0cf32d9e, 0x2e802ebc, 0x221e82ef, 0x8207110a, 0x0504272a, 0x0c152214, 0x2a82280c, 0x080c2e23, 0x242a8208, 0x3d0f4c0f, 0x242a831e, 0x080004f2, + 0x07d57000, 0x09000523, 0x05b75b00, 0x1d001924, 0xe4822100, 0x11233525, 0x70011121, 0x35200adc, 0x13200b82, 0x07210382, 0x05e45a23, 0xd5000127, + 0x00ffaa01, 0x24008680, 0x2bababd6, 0x2b008255, 0xfe556b01, 0xff2b0180, 0x2b2b2a00, 0xfe220283, 0x0783d5d6, 0x18020021, 0x22089553, 0x83270023, + 0x2634215f, 0x3320f485, 0x2105eb47, 0xa1492315, 0x16142205, 0x07927c33, 0x6d820720, 0x42800121, 0x2b350563, 0x0c09090c, 0x801911aa, 0x2a551219, + 0xc02a5601, 0x2b012a2a, 0x2b1b8540, 0x080d0d08, 0x56111940, 0x2b191156, 0xab208582, 0x28094f5a, 0x001900c1, 0x002c0024, 0x23708236, 0x27072737, + 0x3907784e, 0x37331507, 0x36161617, 0x34363737, 0x3037022f, 0x07173130, 0x17173717, 0x07843727, 0x3805a84d, 0x17070706, 0x50225a01, 0x240c5822, + 0x0c0c290c, 0x66506558, 0x15170a58, 0x2b0b8206, 0x1b2858ef, 0x1f191e19, 0x1f285880, 0x1b2b0782, 0x32060626, 0x27041208, 0x820a0150, 0x0c592130, + 0x24292f82, 0x5066580c, 0x030a5966, 0x22308207, 0x86620c24, 0x86d02031, 0x06d62631, 0x07320612, 0x2f328203, 0x1e000400, 0xd5011e00, 0x0e00d501, + 0x28001c00, 0x0022af82, 0x91843713, 0x27343622, 0x2721b384, 0x0c2c4e07, 0x2322a682, 0xaa843315, 0x07290a82, 0x37ab37c9, 0x0c0c371e, 0x23a782ab, + 0x501e6f37, 0x51320a87, 0x37abc41e, 0x20441922, 0x20171e17, 0x176b174e, 0x29857401, 0x2a822420, 0x32370c25, 0x8237511e, 0x0cab2631, 0x1e50370c, + 0x2a298219, 0x1e18202a, 0x18c62018, 0x6800176b, 0x5e37092f, 0x7e007200, 0x33250000, 0x33112111, 0x26273636, 0x2627030e, 0x82023e26, 0x26062204, + 0x08088227, 0x26363522, 0x36373426, 0x031e1736, 0x022e3637, 0x1e363736, 0x3e161702, 0x16173203, 0x1617040e, 0x16363632, 0x03280982, 0x021e1417, + 0x2e060607, 0x16210482, 0x13967d17, 0xe14a1320, 0x0157080a, 0xaafe9714, 0x0a04029b, 0x0b090a05, 0x0109090f, 0x04060a08, 0x0f121001, 0x0d0a0101, + 0x0606010a, 0x030c0406, 0x0e0d0c07, 0x0a040708, 0x0d0c0308, 0x0a0b090d, 0x0e0e110b, 0x090a0f0e, 0x15171002, 0x0b02030b, 0x040d0f0e, 0x16150b04, + 0x120f0110, 0x11080608, 0x820f1113, 0x97032138, 0x2809096e, 0x27802744, 0x0a0a081c, 0x08038208, 0x00016b20, 0x1e0f00ff, 0x0d060307, 0x0705060c, + 0x110d0a0a, 0x0101070c, 0x08080d07, 0x06060604, 0x81820909, 0x0301023a, 0x05050b0c, 0x0e0f0d04, 0x0d04030c, 0x03031315, 0x0d15130c, 0x0d110d0c, + 0x0a2d2f82, 0x05040706, 0x030b0c0b, 0x07050301, 0x2a9d8207, 0x0a08030c, 0x1b090803, 0x4d2a010d, 0x2b230b92, 0x84ebfe2b, 0x3f768272, 0x15000300, + 0xeb011e00, 0x2a00d501, 0x32002e00, 0x17130000, 0x23060716, 0x06272722, 0x14161707, 0x50080a91, 0x06060706, 0x37331515, 0x01013717, 0x27173727, + 0x1e372707, 0x030707a8, 0x24030504, 0x031e0604, 0x04050303, 0x09081b03, 0x0403031c, 0x1e020504, 0x0c09160b, 0x7f47cb10, 0x0178fe1e, 0x1f5f1e4f, + 0x60985f2e, 0x07a9a601, 0x24040407, 0x031e0b0d, 0x23318209, 0x1b08091b, 0x1d380884, 0x05030b07, 0x47380e16, 0x88011e7e, 0x5f1fedfe, 0x975f2d1e, + 0x0007005f, 0x3305a545, 0x000800eb, 0x0024001c, 0x0041002d, 0x00640049, 0x35270100, 0x2205bd43, 0x4d353517, 0xa563054f, 0x82222005, 0x031721a2, + 0x17211185, 0x3024a317, 0x17070113, 0x022e1523, 0x22232631, 0x020e1407, 0x05575731, 0x01172329, 0x0b103515, 0x82960f0b, 0x15102104, 0x0f220482, + 0x0583e080, 0x954a3521, 0xfef93716, 0x01781e78, 0x0612190c, 0x07070806, 0x1391070a, 0x1013811b, 0xa9821901, 0x100b7427, 0x25e00b10, 0x3006837b, + 0x0f0ba67b, 0x80a90b0f, 0x100b1301, 0x4b350a0f, 0x341c9a35, 0x8801cafe, 0x065b781e, 0x05030a0f, 0x07090701, 0x180b1499, 0x796e1800, 0x07a24809, + 0x27072725, 0x4f131707, 0x212d0fbe, 0x62012135, 0x1e2d5b1e, 0xd6feac4b, 0x06145f12, 0xfe12192c, 0x012a01d6, 0x2d5a1e18, 0xac834c1e, 0x8400ff21, + 0x2205821a, 0x45d5d5fe, 0x11280a2a, 0x00001800, 0x23272301, 0x2c0a1b5c, 0x03263435, 0x33352335, 0xab011735, 0x054b55ab, 0x1156012d, 0x56911919, + 0x80016a56, 0x8512192b, 0x12d5284c, 0x4000ff19, 0x526a4055, 0x10240afd, 0x5c002100, 0x27255082, 0x23373726, 0x05426807, 0x36373324, 0x108f3726, + 0x06072728, 0x16141515, 0x54613b16, 0x05bd4d06, 0x8c08c64d, 0x023e3408, 0x34353631, 0x022e3027, 0x024e0131, 0x28020513, 0x85220602, 0x0f032407, + 0x82140145, 0x07012110, 0x29381084, 0xf10e0301, 0x1d12149a, 0x7b258611, 0x0b0f0f0b, 0x100ba57b, 0xbba50b10, 0xbb210b83, 0x390b8390, 0x0a0f07d3, + 0x09070603, 0x02980107, 0x090c1a15, 0x1501222d, 0x16090d1a, 0x0e8d1029, 0x12910d27, 0x1d11811c, 0x08154212, 0x0b0f1625, 0x8315100b, 0x09fb410e, + 0x2c0adc4b, 0x00100006, 0x001e0014, 0x25000022, 0x30cd8235, 0x15073307, 0x35262223, 0x33363435, 0x33152317, 0x300d8c13, 0x952b6b01, 0xeb952a2a, + 0x11191911, 0x90202030, 0x2e0886c0, 0x6b96c055, 0x12199655, 0x3b191240, 0x871b0120, 0x01002109, 0x3b087650, 0x01000008, 0x15211707, 0x37170721, + 0x621e4001, 0x5901a7fe, 0x01951e62, 0x2a621e95, 0x00270782, 0x00550007, 0x18eb0155, 0x220ceba7, 0x8223001e, 0x15232235, 0x0f446237, 0x26272531, + 0x15070722, 0x34363733, 0x37352307, 0x62800117, 0x0682054e, 0x00822b20, 0x180c0132, 0x71091a0a, 0x890a7145, 0x01164916, 0x7e2ba9ab, 0x08085662, + 0x09199e23, 0x71467109, 0x16741a0a, 0x0500164a, 0x15000000, 0xeb010002, 0x3f002e00, 0x5a004500, 0x00006000, 0x09935001, 0x3533272b, 0x17331523, + 0x27022e23, 0x06954f26, 0x36363223, 0x0aa35037, 0x5d060521, 0x36250661, 0x16323336, 0x25ac8217, 0x06332723, 0xba501706, 0x31323f0a, 0x15161632, + 0x07060614, 0x33351723, 0x11950127, 0x0e160524, 0x67203737, 0x266b1808, 0x93500e26, 0x2c1a2409, 0x885a051d, 0xf4fe240e, 0x50152007, 0x152a0590, + 0xc23c0720, 0x0741101e, 0xb750660a, 0x3d198408, 0x568056bc, 0x646b0180, 0x552b100c, 0x6b2b2b15, 0x01162618, 0x1e311d02, 0x161d301e, 0x0d8a1927, + 0xa65e8020, 0x2a2a2e09, 0x6116092b, 0x0f121d11, 0x0f390919, 0x052a4839, 0x2b406b26, 0x00050040, 0x33074d4b, 0x0027001b, 0x00370033, 0x0100003d, + 0x23232626, 0x07070622, 0x20085a54, 0x20098821, 0x0a9a4605, 0x0b8a3320, 0x3337253a, 0x35330117, 0x01152317, 0x0b100494, 0x04100bea, 0x16080d2c, + 0x00010d08, 0xfe210684, 0x065b50cb, 0x5c54dd20, 0xfe122705, 0x20ea20e8, 0xcd8200ff, 0x0ad5012d, 0x800a0c0c, 0x0d0d09aa, 0x83151509, 0x55aa2305, + 0x3b4c0d13, 0x08c65005, 0xfe606026, 0x2b402bea, 0x2c082569, 0x001b00c0, 0x00260022, 0x00420036, 0x55b28248, 0x0729060b, 0x22233523, 0x15150606, + 0x071a6333, 0x83373321, 0x143327b2, 0x15332706, 0x4a520523, 0x8505201a, 0x19952ebd, 0x4b404011, 0x2618554b, 0x1d122a17, 0x2c028211, 0x00ff6060, + 0x0d2b0d08, 0x016a6a33, 0x1234522a, 0x83f7fe21, 0x129529c4, 0x5d382b19, 0x1827176b, 0x28068a49, 0x080d8e79, 0x2beb0d08, 0x8832826b, 0x0d552135, + 0x2006d95b, 0x21cc836b, 0xfa5e0007, 0x00c02205, 0x26cc841f, 0x003a0032, 0x824c0046, 0x343527ce, 0x23262727, 0xc9822221, 0x33161429, 0x33161633, + 0x85373632, 0x35362706, 0x23272634, 0xce822535, 0x80411720, 0x3537270a, 0x35233533, 0x138b1533, 0xc035d286, 0x140d540a, 0x1912fffe, 0x07041219, + 0x20151520, 0x2106b307, 0x27d98215, 0xfe344a18, 0x405555eb, 0x2e05b152, 0x4040370c, 0x0d09806b, 0x0d08090d, 0x83e2fe0d, 0x201130d4, 0x0f650c0f, + 0x12aa1219, 0x18181319, 0x82181313, 0x21152634, 0x55183d35, 0x25c88780, 0x552b2a2b, 0xd68c2baa, 0x28000522, 0x2b06665f, 0x002e0022, 0x004a003e, + 0x37000050, 0x5405415b, 0x26260f14, 0x06060726, 0xe0840607, 0xce8a2720, 0xa9412520, 0x0555431a, 0x1799a729, 0x28101727, 0x530f1704, 0x702d05fe, + 0x13192808, 0x1004031c, 0x2114141f, 0x21c68635, 0xb0412201, 0x82b32012, 0xab8025da, 0x17261815, 0x2c07ee53, 0x04051916, 0x2314131c, 0x0c131815, + 0x050d4109, 0x38855520, 0x380ed553, 0x402b4056, 0x40000400, 0xc0015500, 0x0800ab01, 0x1d001100, 0x00004600, 0x057f4225, 0x07363226, 0x32331523, + 0x2d05a241, 0x16143315, 0x23353333, 0x34270622, 0x15823336, 0x26211683, 0x05966723, 0x16230f82, 0x83061415, 0x05c6650d, 0x26292883, 0x080dc001, + 0x0d082b2b, 0x34048315, 0x2b2bb30d, 0x40401219, 0x19951912, 0x22152011, 0x15221414, 0x25d7834a, 0x12120e4a, 0xfd82200e, 0x2b2a0282, 0xd519112b, + 0x0d2b0d09, 0xb9832a38, 0x12554028, 0x0419ab19, 0x84561911, 0x090d2705, 0x0d130d08, 0x2882130d, 0x17271824, 0x6f63192b, 0x001b260c, 0x002c0029, + 0x127b522f, 0x520af462, 0xc0840677, 0x17151627, 0x37273327, 0x0c775217, 0x100bf235, 0x0f0b0b10, 0x4016410f, 0x15121915, 0x36601912, 0x5d366b6b, + 0xe5470501, 0x84402008, 0x0b390822, 0x55ab100b, 0x19113655, 0x56761119, 0x0056562a, 0x00150007, 0x01ea0140, 0x000e00c0, 0x00550049, 0x009d0091, + 0x00d100ca, 0x0e223700, 0x21151503, 0x032e3435, 0x35343625, 0x1ad31834, 0x17172a17, 0x17141506, 0x17170607, 0x0a806016, 0x17373625, 0x60373716, + 0x27240e7c, 0x26070726, 0x2405c260, 0x06060715, 0x820f8307, 0x15142237, 0x820e8214, 0x37372b3f, 0x14171716, 0x35323333, 0x40873637, 0x7a822720, + 0xd35f0e82, 0x33252c0b, 0x35353632, 0x23232634, 0x5e272634, 0x26250707, 0x06222326, 0x220d8707, 0x82150606, 0x1533080e, 0x17161415, 0x23373632, + 0x11c01616, 0x18272e2d, 0x27185601, 0x06012d2e, 0x03100101, 0x04010f02, 0x03070512, 0x031e0301, 0x06070201, 0x0f010412, 0x89100201, 0x0208211a, + 0x47241a8d, 0x0b10100b, 0x02320382, 0x0d02010b, 0x01020504, 0x02031502, 0x0d020502, 0x11820102, 0x840b0b21, 0x21188306, 0x54821503, 0x0e020422, + 0x17821084, 0x0a07353b, 0x0a08070a, 0xb6e8fe0a, 0x04070704, 0x07131706, 0x05070404, 0x0a06060a, 0x08098305, 0x0617132a, 0x5f060604, 0xa4072d1e, + 0x07c02d07, 0x111b140e, 0x1b112b2b, 0xae070e14, 0x04020302, 0x03020c04, 0x07010319, 0x03140304, 0x04220282, 0x0e820107, 0x040c0224, 0x19830304, + 0x08021a22, 0x02291885, 0x03010805, 0x0702031a, 0x27a4830f, 0x540f0b0b, 0x06010312, 0x0223d482, 0x82010e03, 0x02012ea7, 0x09020212, 0x03020203, + 0x13020109, 0x821a8202, 0x0e0225a1, 0x06020301, 0x09220f84, 0x1a820104, 0x84210221, 0x070823aa, 0x3b825c0a, 0x1806042f, 0x05140b27, 0x1d050606, + 0x01020201, 0x2309831d, 0x18270b14, 0x55271a84, 0x241c1c24, 0x5e000200, 0x0f2207b4, 0xc7422100, 0x07232212, 0x05524423, 0x33373327, 0x14151632, + 0x0cb94206, 0x6a253c27, 0x13130d47, 0x5506850d, 0x80250d24, 0x0d0d13c0, 0x21048413, 0x65820300, 0xab012b2d, 0x0b00d501, 0x34001700, 0x43130000, + 0x14210b1f, 0x05ef4316, 0x06222323, 0x22038217, 0x47270707, 0x1528053d, 0x33153315, 0x37331735, 0x332e0582, 0x8b263435, 0x11191911, 0xd2191912, + 0x01470e12, 0x3d403605, 0x13051109, 0x0b13064d, 0x20191240, 0x102f366b, 0x01131655, 0x232484d5, 0xa0191112, 0x12362585, 0x1d080a43, 0x190c0a84, + 0xdd958012, 0x6a97175d, 0x00130d4b, 0x5a5d0004, 0x000c2907, 0x004f0043, 0x37000057, 0x230a2658, 0x16072535, 0x0e20ed82, 0x25062462, 0x36363534, + 0xa6831637, 0x032f3724, 0x9e823737, 0x210cfd56, 0x63582726, 0x0737290c, 0x37372727, 0x10a51717, 0x2705ca41, 0x14160110, 0x2f1b0202, 0x31054862, + 0x1d11402a, 0x0e083256, 0x29130d07, 0x140f3c3c, 0xd057182c, 0x090a230b, 0x36879607, 0x17179224, 0x03823434, 0x0f0beb22, 0x24051442, 0x0f072b5e, + 0x078c6208, 0x01010131, 0x24293d10, 0x1c01012a, 0x1b1b1329, 0x580a0907, 0x18240b3d, 0x5e0f142c, 0xa9203786, 0x34234584, 0x51050017, 0x0f2108a1, + 0x052a6800, 0x2012f241, 0x0aa55103, 0x37271725, 0x52173717, 0x1928058f, 0x11560111, 0x6ae71919, 0x67250084, 0x441e1e3c, 0x0df1411e, 0x2bd5fe2e, + 0x2b2b2a2b, 0x1f1e3dab, 0x06001e44, 0x2b276c82, 0xd501e001, 0x49000b00, 0x41250519, 0x00004f00, 0x0a654101, 0x46351321, 0x222805cb, 0x16070706, + 0x27151516, 0x8a0b9a5d, 0x5427820b, 0x332008a2, 0x2a060c42, 0x06222323, 0x15331515, 0x5d195501, 0x562d0678, 0x16053635, 0x160e020e, 0x16111205, + 0x06fb4160, 0xc35d8820, 0x203c3106, 0x11401219, 0x15e02019, 0x0d2b0d13, 0xab011613, 0x2d064c42, 0xa28092fe, 0x0e10100e, 0x15230937, 0x5942e0aa, + 0x19752207, 0x231f8512, 0x8095abfe, 0x80234283, 0x83555595, 0x55552352, 0xbb460a00, 0x00183208, 0x0025001e, 0x002d0029, 0x00370033, 0x003f003b, + 0x24e08243, 0x27352335, 0x20018307, 0x06db5215, 0x35211523, 0x26148333, 0x35231517, 0x84172737, 0x35072806, 0x23021d33, 0x83372735, 0x0502530e, + 0x33231522, 0x29067a41, 0x402bc001, 0x2a2b2b2a, 0x00822b40, 0x09820120, 0x2b16402f, 0x080d4909, 0x2a08082a, 0x0c16562a, 0x22168209, 0x84d62b2b, + 0x2b00221d, 0x83268440, 0x562a2c05, 0x6e2b2a56, 0x092e2e15, 0x82090c0c, 0x828d2005, 0x2b2b2343, 0x0c8215ae, 0x2a230984, 0x1801002b, 0x26083849, + 0x1300001d, 0x4a31041e, 0x4f080896, 0x37033e30, 0x23262636, 0x06062221, 0x21200d5b, 0x090d111b, 0x110d092a, 0x0d20211b, 0x090c0206, 0x0c09d8fe, + 0x10880102, 0x15242a2a, 0x0d0d0980, 0x24158009, 0x07102a2a, 0x100c0c10, 0x6b000400, 0x6b012b00, 0x0900c001, 0x24000d00, 0x00003000, 0x09894318, + 0x3737fd83, 0x31302715, 0x23171616, 0x26373636, 0x37352727, 0x32333636, 0x5d071716, 0x953c0a37, 0x801219d6, 0xd6d61912, 0x231944d6, 0x2306d206, + 0x5d060b19, 0x121e085d, 0x1208140b, 0x3b075348, 0x1911166b, 0x6b2b1119, 0x0a0e80d5, 0x291b1b29, 0x130c080a, 0x130f1316, 0x09320608, 0x0382f482, + 0x778e8b40, 0xd5220580, 0x04430700, 0x25002906, 0x17372731, 0x03071737, 0x220c4244, 0x8307022e, 0x07172b14, 0x37270727, 0x26221327, 0x80443727, + 0x2c012705, 0x351d1734, 0x74664b16, 0x062d4408, 0xab5a8f20, 0x7a1e2c09, 0xf4183f23, 0x2f1b1b16, 0x8233893e, 0x4b17232c, 0x495c4c01, 0x1e5b220f, + 0x08dd5a1e, 0xf2fe3008, 0x18f4161b, 0x3e23233f, 0x03001b2f, 0x40005500, 0xc001ab01, 0x18000400, 0x00002000, 0x21110701, 0x06140711, 0x35231523, + 0x35352622, 0x85331533, 0x23173403, 0x34352335, 0x00013336, 0xa05601ab, 0x0d160d13, 0x820a1613, 0x15353301, 0x01121916, 0x00ff80c0, 0x0d4b0001, + 0x13555513, 0x0083400d, 0x404bb524, 0x5f821911, 0x71002b21, 0x132405c9, 0x1d001600, 0x200a6246, 0x214e8233, 0x5d823717, 0x07263427, 0x17072127, + 0x560f8207, 0x192806fb, 0xabc0c011, 0xbc192aab, 0x16246982, 0x55555656, 0x30056557, 0xd52b1912, 0x956a6a6a, 0x6b961912, 0x405655c0, 0x225d842b, + 0x82d50155, 0x001624bd, 0x821e001a, 0x2733265d, 0x23153307, 0x82b58815, 0x2168825f, 0x68833521, 0x0115172b, 0xd5d54095, 0x2a2b2b40, 0x23018256, + 0x00ff2b2b, 0x01250782, 0x40c0c000, 0x29b2842b, 0x4c672b40, 0x674cb3b3, 0x15410600, 0x00032f08, 0x000b0007, 0x0015000f, 0x13000019, 0x01821521, + 0x82213521, 0x83232054, 0x6b372003, 0x1522054d, 0xc8183521, 0x9620080b, 0xf43e0082, 0x623c1e1e, 0x01c9fe1f, 0x2b6b0156, 0x2b802a55, 0x1f112b80, + 0x1e623d1e, 0x2b2b0001, 0xbb560400, 0x000e3708, 0x002d0020, 0x2500003c, 0x31333523, 0x36272626, 0x1e323336, 0x0c493702, 0x16162505, 0x33151617, + 0x3621bc82, 0x28188236, 0x15030e37, 0x36313030, 0x25268227, 0x14151616, 0x1f821506, 0x01363630, 0x0b7ad500, 0x150a2d42, 0x2e3e240b, 0x0782d51b, + 0x4e2f3408, 0x02070516, 0x7b802b04, 0x0c5a420c, 0x3c221e2d, 0x2b1f1a2d, 0x1723340e, 0x0d07011a, 0x550d0406, 0x0b422d2b, 0x2e1b0303, 0x0303813e, + 0x160a262e, 0x8216150c, 0x21263812, 0x1b021337, 0x29233d2e, 0x0f362345, 0x0428491e, 0x09040306, 0x58231305, 0xeb2408b1, 0x30000b00, 0x2724ac82, + 0x17150723, 0x30066d65, 0x36361737, 0x07272726, 0x17072735, 0x07170733, 0x22088427, 0x64230717, 0x2608088e, 0xce013735, 0x71361571, 0x2d061206, + 0x2d1e6307, 0x0d08080d, 0x4c0f1e4b, 0x161e3d0f, 0x3c40593d, 0x12581e40, 0x8206712d, 0x0611271c, 0x717c6e71, 0x0c831536, 0xb1120627, 0x210d2e1e, + 0x202a8220, 0x292b823d, 0x583d171e, 0x413c401e, 0x47841258, 0x06062308, 0x006e2d71, 0x00000009, 0x0100022b, 0x000f00d5, 0x002b001f, 0x00460037, + 0x0056004a, 0x00640060, 0x3f500100, 0x06246006, 0x5e11ec71, 0x195e080b, 0x1423350d, 0x23170706, 0x23152327, 0x16323335, 0x23350715, 0x33352715, + 0x11840d82, 0x44181520, 0x23220724, 0x19821735, 0x23000124, 0x0288233a, 0x6c261821, 0x032008cc, 0x0805af58, 0x202beb26, 0x2b202a2a, 0x13080b80, + 0x20181320, 0x20130d4b, 0x2020ea2b, 0xb520202b, 0x0d13130d, 0x012a4a4a, 0x243a22d5, 0x1f724185, 0x2b96260f, 0x2b2a2a2b, 0x3e4083eb, 0x0510092b, + 0x802a2a2c, 0x16160c14, 0x802b0b16, 0x2b803535, 0x400c142b, 0x6080130d, 0x57004040, 0xc42d05f2, 0x1700e601, 0x2d002500, 0x00005500, 0x054a4213, + 0x07141522, 0x2720cf82, 0x2005364d, 0x20d98222, 0x06255a17, 0x15161628, 0x22270614, 0x1a831707, 0x0701132a, 0x15060617, 0x37363433, 0x07310782, + 0x06070606, 0x35262223, 0x16161423, 0x36373233, 0x08028336, 0x33343247, 0x2a128117, 0x29362018, 0x01011717, 0x311c0d1f, 0x0c1b0e1e, 0x1b171fcf, + 0x1a1e2025, 0x06ac141e, 0x20024006, 0x1e78fed9, 0x2b06052d, 0x0e8d0101, 0x1108081a, 0x110a060c, 0x27172b19, 0x16101317, 0x12050a1b, 0x3b18820d, + 0x0d0cbc01, 0x1f372817, 0x0101292a, 0x1a1c2001, 0x081d301e, 0x1e1ecf07, 0x5531294a, 0x2e084a82, 0x3b202846, 0x07410190, 0xfe1f1606, 0x1e8801c7, + 0x0f1d0d2d, 0x8d050b06, 0x18171c0a, 0x19040615, 0x17261812, 0x1d240b07, 0x010a1210, 0x4a03008d, 0x1b220ac0, 0xc24a3900, 0x4a032011, 0x322005bf, + 0x3720f083, 0x0623da83, 0x7f342315, 0x67430558, 0x46272005, 0x1621058a, 0x0cda4a16, 0x0ba72208, 0x0c0b1010, 0x0c340f0f, 0x02030615, 0x1a070727, + 0x11020708, 0x03121111, 0x1d250723, 0x07082117, 0x0efd4804, 0xb749c020, 0x129e3a07, 0x0b050b11, 0x0b18080f, 0x080d130e, 0x0b151218, 0x1320150f, + 0x00260c0d, 0x2eac880e, 0x000c0003, 0x00140010, 0x001c0018, 0x57250020, 0x362406af, 0x3f003a00, 0x232cc282, 0x33033335, 0x27371735, 0x37233533, + 0x15200382, 0x07200382, 0x14820382, 0x03832320, 0x23351729, 0x15011614, 0x83263433, 0x20038315, 0x831d8213, 0x3335272d, 0x01062235, 0x00822b6b, + 0x371e3725, 0x82558037, 0xaa2b2108, 0x07535518, 0x192b2b2c, 0x192b3c01, 0xab2a2abc, 0x1a822b2b, 0x2b280282, 0x95011912, 0x3780fe2b, 0x2b2b2e82, + 0x2a802b80, 0x2a012bd5, 0x82d5fe2b, 0x2019820b, 0x201e8280, 0x830a822b, 0x802a280f, 0x0300192b, 0x4f001f00, 0x182005b8, 0x3831b582, 0x15130000, + 0x06222326, 0x15331707, 0x15171616, 0x064e4823, 0x11353630, 0x27233505, 0x17323336, 0x23060717, 0xee6b1722, 0x23450806, 0x37373635, 0x27353317, + 0x1bc03335, 0x16371c1d, 0x230e1747, 0x12194012, 0x111d12d5, 0x1730e8fe, 0x202c1413, 0x1811041e, 0x090cdf0f, 0x13800c09, 0x1e3d040e, 0xab01aa80, + 0x16160b1e, 0x0f0d1847, 0x12403001, 0x262b8219, 0x2e891601, 0x821f0716, 0x8653082a, 0x080d0d08, 0x0e08372b, 0x801e3c04, 0x000d000d, 0x012c002c, + 0x00d401d4, 0x000b0005, 0x00170011, 0x0023001d, 0x002f0029, 0x003c0036, 0x00480042, 0x2500004e, 0x35070617, 0x16232736, 0x37263717, 0x15272637, + 0x26331716, 0x07160727, 0x35171607, 0x82351326, 0x823620cf, 0x2611821a, 0x07062705, 0x83053633, 0x23372810, 0x37361707, 0x82030627, 0x36172112, + 0x3c822a83, 0x17152331, 0x42012737, 0x18231f15, 0x0f032bd6, 0x83e80925, 0x897c200a, 0x2318350a, 0xb515151f, 0x151c1525, 0x25e9fe13, 0x032b030f, + 0x09034f01, 0x42280883, 0x25141c16, 0x1d15e10e, 0x0e200582, 0x12262083, 0x1e5b2a8e, 0x2484634f, 0x36839120, 0x0a8fca20, 0x844f0121, 0x843f2058, + 0x83382039, 0x18422269, 0x20068215, 0x215f8473, 0x45840201, 0x6b82e020, 0xe50e2523, 0x474b8274, 0xab26081f, 0x27000b00, 0xf9822b00, 0xd07f2320, + 0x35212306, 0xf85f3723, 0x4715200c, 0x078207e7, 0x23263439, 0x01333523, 0x2baa2b80, 0x55aa0155, 0x1219402b, 0x40191280, 0x83551911, 0x7c193411, + 0x15ab8080, 0x6b6b1515, 0x19122b95, 0x192b1219, 0x822b5611, 0x11562200, 0x05604a19, 0xab01eb24, 0x7b821501, 0x21130024, 0x19472115, 0x2a152f05, + 0x80000200, 0x80012b00, 0x0900d501, 0x89820e00, 0x37273534, 0x17152135, 0x35131507, 0x01071533, 0xff555580, 0x60825500, 0x802b5525, 0x827f5655, + 0x0180250e, 0x554b4b35, 0x0f244782, 0xd3010f00, 0x0b273782, 0x1b001600, 0x82130000, 0x3717232e, 0x3d833131, 0x82072721, 0x31340840, 0x17352115, + 0x35232737, 0xaaab1737, 0xff4d1a3c, 0x1e7e2b00, 0x00014dbe, 0xaa7e1e35, 0xab016e3c, 0x4c1a3d4b, 0x412a1980, 0x014cbe1e, 0x1e35197f, 0x6f3d4b28, + 0x13208f8f, 0x21208a83, 0x03219483, 0x82498215, 0x8501207f, 0xd501218e, 0xfe228f87, 0x8f824bcb, 0x2807bf47, 0x000a00c0, 0x00130010, 0x07754817, + 0xc7823320, 0x33273323, 0x223e8317, 0x82073723, 0x056e480d, 0x2ad62a3b, 0xd605ccfb, 0x6b376ea2, 0xc00001d6, 0x2b2babc0, 0x272704d6, 0x2adc322e, + 0x0acc642a, 0x0c000622, 0x19274d82, 0x39002900, 0x50250000, 0x272d05f7, 0x23373633, 0x06223716, 0x26263307, 0x21058307, 0x145a3727, 0x0535570f, + 0x2e08eb67, 0x1d100001, 0x1d0b700b, 0x02089339, 0x855202a8, 0x0959210c, 0x09210b82, 0x0a345a4c, 0xb646a720, 0x3a232b08, 0x0a0a0bab, 0x110f2a0b, + 0x08877111, 0x19950f23, 0x212c8912, 0x2c8ac0fe, 0x90412320, 0x00d32608, 0x0012000d, 0x21ac8218, 0x01823127, 0x08075a66, 0x17372524, 0x01171737, + 0x15163221, 0xd1b5d301, 0x19311e20, 0x31190112, 0x364ab6fe, 0xfe7c4019, 0x121901bc, 0x17842d19, 0x12e7fe2e, 0x60713119, 0x04402040, 0x12194401, + 0xfc785882, 0x00c03505, 0x0037002f, 0x0100003f, 0x17060622, 0x27072607, 0x23262636, 0x06200b85, 0x2506cd6b, 0x16372736, 0xf5541737, 0x250b8305, + 0x34353636, 0xcd6f0726, 0x37078607, 0x150fc001, 0x0b4c0409, 0x0803360b, 0x150f1015, 0x0c610308, 0x12191218, 0x61241583, 0x04370b0b, 0x21821584, + 0x92241583, 0x142c2c14, 0xe13b0382, 0x0a2b2b0a, 0x012b2b0b, 0x0b191155, 0x3603034c, 0x1111190c, 0x04610c19, 0x820f1509, 0x0c18223b, 0x20138861, + 0x2256834b, 0x84151911, 0x14142437, 0x840b2b57, 0x08817a3b, 0x2000eb28, 0x32002600, 0xca823800, 0xc2842320, 0x22230724, 0x01830607, 0x14111524, + 0x01831617, 0xfa613320, 0x27072507, 0x37071737, 0x220aad46, 0x82372717, 0x95012212, 0x05715659, 0x0405593e, 0x0406090c, 0x07030303, 0x05040c09, + 0x19122a01, 0x4d1ebc19, 0x442f1e4d, 0x07090907, 0x2c360382, 0x1e2f2f1e, 0x13c0014d, 0x01131818, 0x07060a02, 0xd6fe0908, 0x1a820809, 0x19010223, + 0x26308312, 0x4d4d1fee, 0x82a52e1f, 0x2a31821a, 0x1ff20a06, 0x4d1f2e2e, 0x18000200, 0x20074f84, 0x05014c08, 0x23152723, 0x188e8335, 0x3708f343, + 0x33333634, 0x21152315, 0x33352335, 0x55011632, 0x222a221e, 0x19ab551e, 0x32061e5c, 0x00014040, 0x19124040, 0x221e9501, 0x1e22eeee, 0x82ebc056, + 0xeb122a9c, 0xeb2a1911, 0x00192aeb, 0x21608203, 0xdc18016b, 0x0f27074f, 0x21250000, 0x82152135, 0x37272101, 0x07226782, 0xcf183715, 0x6b20097d, + 0x802c0082, 0x562bc07f, 0x344caa2a, 0x324e4b4b, 0x542a9e83, 0xac012700, 0x1e00e101, 0x3b825700, 0x07060629, 0x26272606, 0x82363736, 0x2b088402, + 0x1e173234, 0x15161703, 0x26370616, 0x26241082, 0x07263637, 0x0e292582, 0x16141702, 0x06071415, 0x82148927, 0x16172311, 0x02821617, 0x3e373622, + 0x0805b265, 0x2626275d, 0x0f053a01, 0x0c231206, 0x13020102, 0x08030416, 0x04010202, 0x13060104, 0x01021115, 0x0c310c01, 0x0f180c1a, 0x0507020a, + 0x1f0a150c, 0x010f0524, 0x02080808, 0x040b1001, 0x14040b01, 0x03030212, 0x40130c07, 0x1e4f2725, 0x0c021916, 0x09010101, 0x8809040b, 0x06020805, + 0x82020a0b, 0x1a4d0846, 0x0e1a0e0f, 0x020a150b, 0x12140d01, 0x05060e15, 0x0ba21e0f, 0x40180c12, 0x02070521, 0x1a070e05, 0x02275147, 0x04090204, + 0x02030704, 0x06193314, 0x3f1a0506, 0x09130920, 0x2b201418, 0x1b120505, 0x1c3c3715, 0x11020302, 0x000a060e, 0x086f5a02, 0x000d4708, 0x01000017, + 0x1e141507, 0x033e1702, 0x17073535, 0x27370727, 0x17173737, 0x1dc00001, 0x29294634, 0x8b1d3446, 0x14494914, 0x21215440, 0x56eb0154, 0x46532c80, + 0x310a0a31, 0x802c5346, 0x2b2b52a2, 0x4e083752, 0x5282074e, 0x2207ce6d, 0x82310025, 0x22312552, 0x1415020e, 0x27052541, 0x021e1716, 0x36323133, + 0x83056d41, 0x34352305, 0xcf55022e, 0x0001330b, 0x1729361f, 0x250f0f0f, 0x060b080f, 0x080a0603, 0x06820a08, 0x82080b21, 0x0f0f2910, 0x1f362917, + 0x161f1f16, 0x01210382, 0x370c83d5, 0x1917341c, 0x170c192c, 0x0b0f060d, 0x0d060f0b, 0x2d180c17, 0x1c341719, 0xd0214483, 0x24278320, 0x00201616, + 0x08b57504, 0x25000536, 0x3e002e00, 0x17250000, 0x33352707, 0x020e1417, 0x27262223, 0x35240382, 0x37363435, 0x2f075c6e, 0x32333617, 0x3325021e, + 0x23262635, 0x05150622, 0x23071064, 0x33161614, 0x2f08bd82, 0x113e3501, 0x1aa0204d, 0x21233e2f, 0x12651739, 0x1a111918, 0x2a191a2c, 0x0b0c021a, + 0x1a2f3e23, 0x026babfe, 0x1f16151f, 0x3a232b01, 0x223a2423, 0x2505954b, 0x2f1c24d1, 0x1f83566b, 0x19141639, 0x1812c012, 0x2b1b0a01, 0x1927171a, + 0x3d2f1b02, 0x1c150f72, 0x88a01620, 0x3a23212c, 0x0a835718, 0x1600082d, 0x07130000, 0x33152317, 0x83371707, 0x36322606, 0x26341135, 0x39108223, + 0xd9371eeb, 0x6a1e37d9, 0x11abab56, 0xab111919, 0x1e6b01ab, 0x1e382a38, 0xd568956b, 0x822b2006, 0x00152648, 0x01d50115, 0x234682d5, 0x01000022, + 0x21069041, 0x90733707, 0x0bce6a09, 0x2605646b, 0x8f2a090b, 0x50192e15, 0x29230620, 0x82402a40, 0xd5012c02, 0x2c4d3b21, 0x8f152e19, 0x830b092a, + 0x201e830a, 0x201983ea, 0x22ae8440, 0x82eb012b, 0x00052565, 0x2500001d, 0x20059850, 0x05b77134, 0xac823520, 0x22213108, 0x37111506, 0x37343133, + 0x4c720126, 0x1f5a2e1e, 0x362917eb, 0x0e20121f, 0xaafe1119, 0x80551911, 0x4c550101, 0x1e5a2d1e, 0x29361f39, 0x8f070818, 0xfe25d083, 0x06055580, + 0x265d8605, 0x000002d5, 0x82240014, 0x14152ac3, 0x07212306, 0x33363411, 0x08165e33, 0x9e412720, 0x266c8206, 0x06222326, 0x82d50106, 0x55d52c58, + 0x01d81119, 0x1d311c01, 0x5c732112, 0x005c0540, 0x6b013105, 0x551912c0, 0x19118001, 0x1d050b05, 0x5f0c1d31, 0x1a821d82, 0x00240584, 0x002b0003, + 0xab26cd83, 0x1c001600, 0xcf822200, 0x142bc98f, 0x26333316, 0x15371703, 0x84012707, 0x000121eb, 0x1924ce8c, 0xab02ad11, 0x01210083, 0x20ec841d, + 0x20d4826b, 0x18d48217, 0x2a072bd6, 0x6b1f010c, 0x6a6a2b6b, 0x834bd6fe, 0x085a61f3, 0x1d00d524, 0xe1872d00, 0x35262222, 0x172ae389, 0x17152707, + 0x33161637, 0xea943632, 0x1911aa22, 0x1328eb84, 0xabab4e10, 0x09120971, 0x4020f18f, 0x1924f182, 0x12000112, 0x0624f282, 0x310f2917, 0x46247f82, + 0x5f0b0303, 0x2b0a945b, 0x2b000100, 0xd5011500, 0x4100eb01, 0x07288582, 0x06233727, 0x020e0706, 0x2507fa4e, 0x17163233, 0x14833636, 0x3323118b, + 0x5f272626, 0x16330c87, 0x17161615, 0x01372733, 0x221e55d5, 0x2b390570, 0x6f1d1101, 0x0f2706db, 0x291f081a, 0x7d074205, 0x42290a8a, 0x081f2905, + 0x1d120f1a, 0x82898211, 0x392b2728, 0x1e216f06, 0x3b820001, 0x164f3222, 0x1c823985, 0x100b0d24, 0x465f243a, 0x39242409, 0x840d0b11, 0x82122030, + 0x4f162422, 0x6f1e2232, 0x19240a29, 0x29001d00, 0x180f906a, 0x23081d42, 0x27263411, 0x270ec66d, 0x1956ab01, 0x19115611, 0x9e560282, 0x56562207, + 0x06f84280, 0x112b8028, 0x2b111919, 0x39731219, 0x19122707, 0x40c02b2b, 0x314f2b40, 0x00d5300a, 0x001b0011, 0x0039002f, 0x07012500, 0x5e172317, + 0x352308f4, 0x4c273717, 0x332505b4, 0x15371737, 0x07674427, 0x0a831520, 0x22232623, 0x081d8206, 0x36270721, 0x16163233, 0x78fec401, 0x1619501e, + 0x17271715, 0x7b172718, 0x1219c41e, 0x0c151911, 0x852b2b34, 0x82838211, 0x062108a3, 0x13105805, 0x3c111d12, 0x511e8801, 0x172618d5, 0x19182617, + 0x12441e7b, 0x78121919, 0x2a6ebc34, 0x22138544, 0x82c42aee, 0x0a032812, 0x0b580811, 0x74001d11, 0x0e280937, 0x00003400, 0x26262313, 0x14228b88, + 0x7f823706, 0x23111523, 0x05475511, 0x41141121, 0x233206d1, 0x23073327, 0x32331614, 0x34113536, 0x5fc53636, 0x48430908, 0x89092105, 0x8f84a182, + 0x18271722, 0x152f9d82, 0x15158016, 0x19121119, 0x6b012717, 0x410c1608, 0x0c2205cf, 0x9c826216, 0x01abfe23, 0x05fa4255, 0xd5219885, 0x055764d5, + 0x00210d82, 0x08c45207, 0x3100182c, 0x45004100, 0x5d005100, 0x9f826100, 0x82074e4f, 0x1737217b, 0x272a8e84, 0x22232626, 0x16321706, 0x91831617, + 0x83273721, 0x24148515, 0x36361707, 0x0a097525, 0x32213328, 0x11230716, 0xcf853733, 0x0b8bc185, 0x33152332, 0x1b051e91, 0x07130d12, 0x0c06050a, + 0x1a061e02, 0x05340b83, 0x0c060307, 0x05070312, 0x120d1307, 0x021e061a, 0x0a05050d, 0x1b260b83, 0x0c021e05, 0xae443601, 0x05234205, 0xd6d6aa23, + 0x074e566a, 0x22080787, 0x1e012a2a, 0x0913061e, 0x030a0705, 0x0a13071e, 0x0a040404, 0x05030461, 0x1e061309, 0x05070a03, 0x8207130a, 0x65c02007, + 0x19240959, 0x2b00ff12, 0x2006f272, 0x0679565e, 0x2b745d08, 0x95000200, 0x6b012b00, 0x1200d501, 0x00001700, 0x15233501, 0x07171714, 0x37071707, + 0x27372717, 0x07363727, 0x33352707, 0x0bd66b01, 0x37491559, 0x113f3f11, 0x59154937, 0x1515560b, 0xb421012a, 0x35060cb4, 0x472f0732, 0x2f472525, + 0x06353207, 0xc50d0d1a, 0x28000400, 0xd7012c00, 0x392e5382, 0x82004500, 0x00008e00, 0x27363725, 0xd45d3627, 0x37372424, 0x7e171716, 0x36230555, + 0x60161737, 0x05220b20, 0x43943427, 0x5e08d95d, 0x44880819, 0x4809d95d, 0x2e330c01, 0x1f05031e, 0x051f0101, 0x06031e03, 0x060d0c25, 0x823c0601, + 0x0b0e2d03, 0x1e030625, 0x01200504, 0x04052001, 0x6f241a90, 0x12191912, 0x013e0382, 0x01011506, 0x13030414, 0x08170501, 0x04010309, 0x03010426, + 0x18030805, 0x02130204, 0x1b821403, 0x08820320, 0x07180422, 0x052e1b84, 0x04080404, 0x14020318, 0x110c5f02, 0x03820c11, 0x0633dc3a, 0x07081804, + 0x05180807, 0x02053405, 0x2706090f, 0x05280606, 0x06020f09, 0x3f201998, 0x7d827984, 0x030fa33f, 0x04050304, 0x21030310, 0x06090204, 0x04051903, + 0x0305011a, 0x2203010a, 0x04100303, 0x2b1a8b05, 0x02190404, 0x02090304, 0x01032104, 0x7d827984, 0x51040021, 0xeb2606d3, 0x17001300, 0x0d822500, + 0x14250026, 0x2315020e, 0x2b07f976, 0x16163231, 0x33152307, 0x07061437, 0x24097e53, 0x30152727, 0x07684930, 0x26263727, 0x023e3435, 0x25118233, + 0x104b0115, 0x04771016, 0x364e0809, 0x12802a2a, 0x19151e0f, 0x191f1e25, 0x2855401e, 0x191e3545, 0x120f1e15, 0x1f362917, 0x1a1c10e0, 0x190c0c19, + 0x15101c1a, 0x21151521, 0x1bab2095, 0x191e1430, 0x4b2c2440, 0x3c141f1b, 0x1e405687, 0x24274635, 0x141e1940, 0x361f1b30, 0xf4471729, 0x01402405, + 0x56c001d5, 0x012005d2, 0x24082163, 0x35211507, 0x069b5f27, 0x35210323, 0x07f65b21, 0x01154038, 0x11401500, 0xfe111919, 0x015601aa, 0xea1219c0, + 0x2b151912, 0x0884152b, 0xeaebfe24, 0xb1660500, 0x09516408, 0x64010021, 0x0120414f, 0x2b314964, 0x19116b01, 0x6b5d392a, 0x40172717, 0x2805cb44, + 0x090d8e78, 0x2beb0d09, 0x0b49486a, 0x180d5621, 0x48073544, 0xd5200735, 0x2d2bc582, 0x00003900, 0x37171513, 0x5d173527, 0x3e270afd, 0x17323302, + 0x59232635, 0x27230cb0, 0x58233537, 0x352e0767, 0x561165d5, 0x29170289, 0x36201f36, 0x07821729, 0x16202108, 0x28151514, 0x1d1d3546, 0x28284635, + 0x021e3545, 0x40402b02, 0x5501402b, 0x331a3e80, 0x0a0b5571, 0x1f2a2887, 0x06172936, 0x351e052c, 0x2f872845, 0x950b0a25, 0x822a4040, 0x04003c02, + 0x28002800, 0xd501d501, 0x26000f00, 0x49003e00, 0x01250000, 0x06061707, 0x821e1415, 0x37362794, 0x2e222717, 0xb7553502, 0x49152005, 0x3720054b, + 0x03201e82, 0x2e07fd55, 0x36270706, 0x2e343536, 0x06222302, 0x84141707, 0x3341080e, 0x01161632, 0x1b86febd, 0x21141229, 0x222c4d3b, 0xa1281a3d, + 0x1b2f3e23, 0x07200c0e, 0x233a2308, 0x1f0d1e10, 0x1a922e13, 0x4d2c223d, 0x1114213b, 0x1b0e0c1f, 0x19233e2f, 0x08da132e, 0x1e0dac07, 0x24238210, + 0x1c7a0143, 0x21218828, 0x20862d28, 0x1d851f20, 0x20070827, 0x5b010e0c, 0x825f8711, 0x8519204e, 0x82912061, 0x83ac205c, 0x0af64765, 0x39002928, + 0x00004500, 0xd6861713, 0xd1823e20, 0xbb83b183, 0x41183320, 0x36210cac, 0x084a7a17, 0x23060626, 0x37262622, 0x2105a247, 0xd4823634, 0x09213d22, + 0x8307635f, 0x1c1d2507, 0x182d1420, 0x210b5b5f, 0xc6504c09, 0x12152d0b, 0x13130d0e, 0x01120e0d, 0x1c1b2158, 0x3d879d83, 0x5f210a21, 0x44200f4b, + 0xae20388a, 0x7b068567, 0x29220a7a, 0xc0823500, 0x4d004925, 0x18010000, 0x21085842, 0xcf973736, 0x917c2520, 0x4717200a, 0xd88607b1, 0x15232724, + 0x03823733, 0x8305b64b, 0x060623bd, 0xd78b0b29, 0x0f1b1e25, 0x83132411, 0x60fe2019, 0xfd2007e0, 0x23279e8a, 0x552b2b95, 0x77012b2b, 0x13250876, + 0x1c0e1124, 0x27df8b1e, 0x0606290b, 0x7f4d3b21, 0x2007987a, 0x253e8aab, 0x8080801d, 0xe15e0600, 0x00062a08, 0x001e0012, 0x00310025, 0x5bdb823d, + 0x7d6505a2, 0x0a9f5f06, 0x2605be61, 0x23353317, 0x7d170735, 0x18850b5f, 0x01263085, 0x5655556b, 0x33479656, 0x560c240e, 0x8f555556, 0xab012514, + 0x2b405556, 0x8707a243, 0x2bd62507, 0x40565540, 0x0024158f, 0x00150003, 0x2705c44c, 0x001c0010, 0x37000038, 0x26218782, 0x66748226, 0x32210515, + 0x0bf34636, 0x15272527, 0x23032e23, 0x07564215, 0x3e32152c, 0x15333702, 0x065a5a91, 0x534b1521, 0x21152205, 0x37a48636, 0x56568d01, 0x4a392404, + 0x2f3e2329, 0x3e2f1a1a, 0x394a2923, 0xeb560424, 0x08864418, 0x2709eb66, 0x292b4015, 0x2a1d3446, 0x2e08e561, 0x2946341d, 0x0002002b, 0x013c003c, + 0x82e201e2, 0x0d2e0809, 0x37010000, 0x07011707, 0x17150717, 0x17373317, 0x47c00001, 0x1e78fe69, 0x3c97686c, 0x016c271e, 0xa6c04779, 0x6c1e8801, + 0x973c1e27, 0x765b6c68, 0x00d52408, 0x82260013, 0x0c7e443b, 0x17022e24, 0xe5853723, 0x4d270721, 0x372005b0, 0x32106a79, 0x0f316b54, 0x2b19182a, + 0x0715051e, 0x1d1e3324, 0x422b1231, 0x0b4e0957, 0x30ff2d07, 0x26151411, 0x2c1c0617, 0x2c14181a, 0x220c0f5e, 0x821f0010, 0x11072377, 0x4d181121, + 0x42560c1a, 0x15333105, 0x32333533, 0x00011516, 0xdb5601ab, 0x0b10100b, 0xa6290382, 0x1616aa16, 0x19124b4a, 0x060f5e01, 0x3305b862, 0x20750f0b, + 0x4b609520, 0x01001219, 0x2b006700, 0xd6018001, 0x34325b84, 0x36373636, 0x26272636, 0x030e0726, 0x021e0607, 0x0f843233, 0x022e4008, 0x1d000135, + 0x050a2133, 0x25110a09, 0x313f2414, 0x1d05041f, 0x172f513c, 0x05080b16, 0x1c332309, 0x43260001, 0x11040d32, 0x02040211, 0x33210403, 0x55302440, + 0x02052542, 0x0e041210, 0x82254233, 0x001e34c7, 0x01c40115, 0x000b00eb, 0x001b0018, 0x36271300, 0x82173336, 0x27113db0, 0x06271335, 0x22232306, + 0x27113526, 0x27270137, 0x054fbc15, 0x11d60d16, 0x133b2a19, 0x21080885, 0x88011e4d, 0x8001af80, 0x01100c4f, 0xe7fe1218, 0x9efeae2b, 0x19100c13, + 0x4d190112, 0x4478fe1e, 0x6084aeae, 0x24056c76, 0x00130007, 0x31608216, 0x27071521, 0x13233733, 0x35211527, 0x27273533, 0x5b831737, 0x017c2b08, + 0x8f6a8444, 0x26ffe026, 0x1e6b00ff, 0x01041eaf, 0x01446b84, 0x6a942bc0, 0x2689fe2a, 0x216a2b04, 0xfe041eb0, 0x43432f7c, 0x46820400, 0xd5011634, + 0x1300d501, 0x36002e00, 0x00003d00, 0x17072725, 0xc46a2307, 0x32212606, 0x37173736, 0x06e27d27, 0x26200b82, 0x2d055a43, 0x35363233, 0x0e172734, + 0x33273702, 0xe2823317, 0x33373208, 0x35233507, 0xf5290133, 0x3604711e, 0x0e14140e, 0x120c1101, 0x4c1f2e03, 0x172717ab, 0x22132012, 0x1f160909, + 0x2016161f, 0x18042204, 0x25999623, 0x3d25821c, 0x15402233, 0x1ff5d755, 0x0e140571, 0x0e140ec8, 0x4c1e2f0c, 0x1827172b, 0x03182414, 0x2d830321, + 0x16202f08, 0x14210908, 0x9967131f, 0x740e141e, 0x006a5674, 0x000f0003, 0x01eb010f, 0x000700eb, 0x00200011, 0x33271300, 0x33153335, 0x14150503, + 0xb0823316, 0x17353524, 0x9a820701, 0x33154108, 0x21152117, 0x07f21735, 0x1e6b2b6a, 0x090d48fe, 0x0c091501, 0x1e5afe7e, 0x1e342179, 0xe7fe2aef, + 0x01604001, 0x56564b4a, 0x152fdafe, 0x090d0d09, 0xa6011315, 0x2108791e, 0x2a2b2033, 0x05005f03, 0xd3286984, 0x0900d501, 0x1c001900, 0x272f6b82, + 0x35250000, 0x33023e34, 0x17352711, 0x60060627, 0x262e05b1, 0x37273535, 0x15270101, 0x17152337, 0x04823517, 0x0136362d, 0x271d1155, 0xdf202b16, + 0x82060a06, 0x173408d1, 0xa6011e31, 0x5519b1fe, 0x2a552b2b, 0xd5010227, 0x1a1e0eab, 0x2ba7fe0f, 0x02dfc62e, 0x17c0c001, 0x31441826, 0x015afe1e, + 0x95191913, 0x953c2b2e, 0x0a062883, 0xd524ea86, 0x1300d301, 0x35207c82, 0x3720ea83, 0x78056e41, 0x34240561, 0x22232626, 0x21075478, 0x84823736, + 0x604f2720, 0x27372109, 0x36078d44, 0x802049e9, 0x19114427, 0x311d036d, 0x31c00b1d, 0x1911d1fe, 0x822a0608, 0x209e2b91, 0x12060a05, 0x0202111d, + 0x1b820f20, 0x011a0f3d, 0x2b234a53, 0x00ff1119, 0x0b6d0301, 0x1c311d0c, 0x1931bafe, 0x09000112, 0x822b0511, 0x2062319e, 0x1d110202, 0x050b0512, + 0x1e1c1920, 0x00081d30, 0x2d05085e, 0x00c401d5, 0x001f000b, 0x003e0036, 0x69673700, 0x22012a0a, 0x07070606, 0x36363517, 0x22158233, 0x82353315, + 0x27072bb2, 0x06071707, 0x33331616, 0x5a570617, 0x17372c06, 0x36272737, 0x26263736, 0x4b801707, 0x240807a3, 0x12191220, 0x096c4b07, 0x110c0b0f, + 0xbe20132a, 0x39aa1ea8, 0x090b0206, 0x0f0c198e, 0x160e1119, 0x661e2904, 0x25bf823f, 0x5a275827, 0x3d651980, 0x40013106, 0x5808140f, 0x100ba86b, + 0x0b0b0d12, 0xa4142214, 0x43363682, 0x190c1007, 0x110e1604, 0x280c0f19, 0x05f3661e, 0x0113060c, 0xbc865b11, 0xd501c433, 0x26001a00, 0x3a002900, + 0x01250000, 0x14151707, 0x26038316, 0x36323333, 0x82333535, 0x2309820d, 0x25173732, 0x210a2857, 0xb1823527, 0x3d06f248, 0x07061415, 0x01353327, + 0x1e78fec4, 0x0c0a0c37, 0x0d091509, 0x15090daa, 0x23010101, 0x126ffafe, 0x2d230806, 0x18410e2e, 0x3e232845, 0x01031b2f, 0x013c5980, 0xc3381e88, + 0x2609190e, 0x080d0d08, 0x0d081616, 0x47772301, 0x8032071d, 0x416b2f2f, 0x1106070d, 0x06d51c22, 0x6b7f050a, 0x7b180100, 0x082808c1, 0x17130000, + 0x11331137, 0x6b207f82, 0x71059471, 0x28820aa7, 0x55005527, 0x95019501, 0x30288300, 0x17073315, 0x35331537, 0x1ef88dc0, 0x95012af8, 0x2106822a, + 0x4d84d58d, 0xab015522, 0x37212485, 0x23ca8333, 0x6b233533, 0x2b851d85, 0x320a1a41, 0x001c0010, 0x003e0026, 0x36270100, 0x17163637, 0x82171616, + 0x15332303, 0x3c672622, 0x4107200c, 0x96820532, 0x23051d5a, 0x020e3537, 0x36061f4a, 0x06233736, 0x492b0106, 0x0c080f0b, 0x04060306, 0x182f0f1c, + 0x413f3a1c, 0x2b0806e7, 0x19b71eb2, 0x1e782e12, 0x121d11ef, 0x27181318, 0x1d311c16, 0x051e2c1a, 0x0121072c, 0x010c4914, 0x02030301, 0x111f0404, + 0x7d182a16, 0x3807e541, 0x2eb81e44, 0x1e771912, 0x111d1219, 0x2c072115, 0x1a2c1e05, 0x161c311d, 0x18408227, 0x220c0741, 0x461a0017, 0x032611c7, + 0x17333523, 0xbc461735, 0x2b412410, 0x466b152b, 0xfe3b11ae, 0xaaaaaad6, 0x00060055, 0x0169002b, 0x009701d5, 0x00160012, 0x00320024, 0x824e0040, + 0x0c794d5c, 0x2607784d, 0x07272634, 0x4d151616, 0x252e057f, 0x27373634, 0x14150606, 0x26371716, 0x944d2526, 0x8207200c, 0x88352011, 0x11894d1f, + 0x1d21c02c, 0x1c1c1917, 0x211d1719, 0x068476fe, 0x01261084, 0x1710122a, 0x02821714, 0xdf121025, 0x85121017, 0x0b01260d, 0x181a1d10, 0xa344180c, + 0x20943009, 0x1d4e2c95, 0x25431817, 0x17184325, 0x862c4e1d, 0x2d148606, 0x17102b18, 0x1f1f3615, 0x10171536, 0x0382822b, 0x11881820, 0x4e010021, + 0xc0220664, 0xe4820900, 0x1723352e, 0x33152707, 0xc0013727, 0x46d647ab, 0x01250382, 0xd646ab15, 0x61038247, 0x1c220c0f, 0x0f612300, 0x52232012, + 0x35360824, 0x15330721, 0x27333533, 0xd5fe9501, 0x11191911, 0x19122b01, 0xb76f1219, 0x01562706, 0x562aea2b, 0xe660552a, 0x00ff210d, 0x2405564d, + 0x404080d5, 0x2c6d8256, 0x0140002b, 0x009501eb, 0x001d0015, 0x216d8226, 0x38563332, 0x14153307, 0x26333316, 0x36343526, 0x35270736, 0x33371733, + 0x10571715, 0x01210807, 0x1705058b, 0x11e6fe11, 0xcf111717, 0x35200706, 0x8405898c, 0x1e2a0687, 0x22595922, 0x1501561e, 0x36198358, 0x0c1711da, + 0x36200e1b, 0x2f512a1f, 0x522e4f4f, 0x222b221e, 0x5800551e, 0x1326091b, 0x2a002100, 0x54423800, 0x75072011, 0x3227068d, 0x14151516, 0x78231706, + 0x2e4c0658, 0x420d8606, 0x6c201072, 0x2606c851, 0x12195662, 0x522a1912, 0x8442071c, 0x0dd52a11, 0x0d094008, 0x0840090d, 0x0565540d, 0x0d086a22, + 0x00211286, 0x08195301, 0x97831c20, 0xec520720, 0x23200805, 0x14111522, 0x36373233, 0x17323336, 0x35323316, 0x01233411, 0x2f0303c9, 0x5f643163, + 0x0c0c0303, 0x012a0a8a, 0x121102ab, 0xfe0e0223, 0x08850ec6, 0x0e3a0122, 0x55215682, 0x05426d00, 0x253e5682, 0x34352626, 0x34353637, 0x15222123, + 0x16161714, 0x06071415, 0x21331415, 0x27343532, 0x3d87a901, 0x83120121, 0x213d8246, 0x67933d02, 0x8a030321, 0x831b20ac, 0x0f0622ac, 0x22468202, + 0x8216021f, 0x3f3622a1, 0x2e608202, 0x2626022f, 0x522c0001, 0x1206132c, 0x82130612, 0x2c0b8a08, 0x0808ab01, 0x42431303, 0x03134342, 0x89008208, + 0x08ca5d0b, 0x0f00ab29, 0x28001f00, 0x42250000, 0x21230b16, 0x5e273632, 0x252d0eb6, 0x23061415, 0x35213521, 0x11199501, 0x056954fe, 0x19112b23, + 0x0ae756c0, 0x19040132, 0x0195fe12, 0x12abd56b, 0xab121919, 0x27191911, 0x20881d82, 0x12eb803a, 0x00eb2b19, 0x00000004, 0x01000254, 0x002f00ab, + 0x00460040, 0x0100005b, 0x082f4718, 0x9b762720, 0x23232220, 0x0c155707, 0x20159d76, 0x065d6633, 0x76840121, 0x1e232596, 0x7607dd11, 0x01201b97, + 0x0121c584, 0x4193762b, 0x240c1d43, 0x002b001f, 0x151d4337, 0x82363421, 0x141522c3, 0x0b817606, 0x1c430b8b, 0x4f972010, 0x1221052d, 0x0643475d, + 0x074f5e20, 0x111d4306, 0x7a76f520, 0x820f870f, 0x00552e9b, 0x01d5012b, 0x000f00eb, 0x00350015, 0x189b8341, 0x260d8459, 0x33352717, 0x5f031715, + 0x062d082d, 0x16141115, 0x27263333, 0x15331123, 0x241b8233, 0x34351716, 0x0c7d5426, 0x301e6b23, 0x444e181d, 0x2e063b07, 0x441d2815, 0x15152007, + 0x12440720, 0x82121919, 0x2b640b13, 0x15162baa, 0xdd439219, 0x18012006, 0x3c0c714e, 0x3b442e9d, 0x134e0128, 0x19131818, 0x11c0fe12, 0x01181219, + 0x6c404040, 0x12790a03, 0x08834e19, 0x82050021, 0x015524af, 0x82ab01eb, 0x001b22b9, 0x5cbb862a, 0x30580e64, 0x36343906, 0x07163233, 0x34352115, + 0x2223032e, 0x3e17030e, 0x1e323303, 0x35371702, 0x098b5b18, 0x18150121, 0x210bd054, 0xc36e192a, 0x72d62006, 0x113a05e2, 0x272e2d11, 0x17022b18, + 0x16162b26, 0x0218252b, 0x2b40406b, 0x55014040, 0x5a182718, 0xa06e0975, 0xe7193505, 0x1b112b2b, 0x07070d15, 0x111b150d, 0x090e0e06, 0x060e0e09, + 0x2b212e84, 0x0c864340, 0x0021b683, 0x22b28e01, 0x6b331517, 0x35230521, 0x89051523, 0x209e8db2, 0x227c832b, 0x8b95fe2b, 0x208b8c9c, 0x829c8213, + 0x8aab2002, 0x217a828a, 0x3141002b, 0x00132307, 0x7a930022, 0x728b3520, 0x91582b20, 0x05325905, 0xfe804022, 0x2e27ee84, 0x2c11112d, 0x8e18272e, + 0xf72b206e, 0x077b466a, 0x0f00ab2b, 0x30001c00, 0x00003c00, 0x0e935213, 0x0e26172b, 0x33151503, 0x36362626, 0x07786917, 0x2207fc4b, 0x50371737, + 0x80200b8d, 0xf885ec85, 0x2e125d2c, 0xcb192930, 0x06010d14, 0x0b410cc3, 0x160c2508, 0x801e3709, 0x4106eb41, 0x692e0c05, 0x150e0601, 0x162b111c, + 0x5417252d, 0x4a821714, 0x07244d85, 0x371e3605, 0x21079b49, 0x39480200, 0x00c53006, 0x003d0039, 0x23352500, 0x27372726, 0x57262607, 0x0a8306fc, + 0x27070624, 0xa2831707, 0x09851520, 0x15230726, 0x07171633, 0x8306b85c, 0x362708b3, 0x23073337, 0xc0013335, 0x37030241, 0x0a053315, 0x240e0106, + 0x1f12251e, 0x1e250718, 0x0c010e24, 0x37153309, 0x85410203, 0x3711251e, 0x11372121, 0xab3d1185, 0x2bc02a2a, 0x25200b0d, 0x060e071d, 0x1a040704, + 0x251e2315, 0x0407010a, 0x15231e25, 0x2610821a, 0x251d0e0d, 0x850d0b20, 0x231d2a23, 0x251d1d23, 0x2b0d0c1f, 0x2ab98280, 0x0140002b, 0x00c001d7, + 0x8259004d, 0x050464b9, 0x15020e23, 0x2a9b8214, 0x34352626, 0x23263736, 0x82060622, 0x240b82cb, 0x32323336, 0x05935233, 0x210d1e78, 0x0a522222, + 0x82172007, 0x33162139, 0x36202482, 0x080d3f44, 0x0533c72f, 0x0a162513, 0x0c101819, 0x0f0d0f0a, 0x1918161c, 0x061e2c19, 0x1d121a14, 0x0f180f11, + 0x161f1f16, 0x0d0d0920, 0x06042009, 0x15010406, 0x05db4a20, 0x1e311d28, 0x0a150fbd, 0x56445205, 0x2e8d2a06, 0x07182919, 0x10141d12, 0x2b45821b, + 0x2c1b1423, 0x25160c0d, 0x15220618, 0x202e4682, 0x0d1f1616, 0x060d0908, 0x1d060504, 0x5e821e30, 0x1e010528, 0x19101d31, 0x6548181a, 0x18002007, + 0x24092543, 0x00170013, 0x6edd181c, 0x25501808, 0x33332f07, 0x13173337, 0x37112111, 0x21072707, 0x9157ab01, 0x2e058305, 0x27802744, 0xd6aafe44, + 0x01402b40, 0x18950100, 0x280e1e42, 0xff0001d6, 0x3a4f9500, 0x0a796e56, 0x19001326, 0x32002500, 0x37236382, 0x18152715, 0x2a098950, 0x16322133, + 0x21350715, 0x45352111, 0x072e0b62, 0x15021e32, 0x34352315, 0x8001023e, 0x525d5555, 0x00ff230c, 0x9f420001, 0x0b122e07, 0xab131b1d, 0x011d1c12, + 0x55ea5520, 0x052e5c60, 0x4f250583, 0xb100ff4f, 0x07944231, 0x0a06152a, 0x15150b10, 0x060a100b, 0x2a061246, 0x00d501ab, 0x001e000d, 0x822d0021, + 0xa0401893, 0x0711340b, 0x27260627, 0x37362626, 0x17163636, 0x17071616, 0x18173527, 0x220bd14d, 0x87ab2b01, 0x286a3367, 0x0f123016, 0x0e0f0a0a, + 0x120e2726, 0x4a280b06, 0x4f18b676, 0xd520087d, 0x2908035c, 0x0b28f400, 0x270e1206, 0x2b830e26, 0x16301227, 0x7575c128, 0x06de4675, 0x29063043, + 0x00ab01ab, 0x000c0003, 0x6d821300, 0x022f1738, 0x37151707, 0x36eaab17, 0x50936d4c, 0x74716b1b, 0x95049101, 0x0c848223, 0x7348ba22, 0x522c2a82, + 0xb0012f00, 0x0b00d101, 0x2f001500, 0x2737c382, 0x07072226, 0x36173717, 0x16052636, 0x27373732, 0x17140607, 0x83070737, 0x21098217, 0x0f830717, + 0x03821883, 0x34363e08, 0x2d9b0127, 0x3d0c240c, 0x0d4b2d2e, 0xcdfe0808, 0x35091a0a, 0x0909352d, 0x440f0fcc, 0x090a1a0a, 0x870f4409, 0x230c0d0d, + 0x1206c40d, 0x01060606, 0x0d0d2d97, 0x4c2e2e3c, 0xb020210d, 0x202a8209, 0x20248234, 0x222b8380, 0x821b090a, 0x8288202b, 0x820d204b, 0x8206202b, + 0x0d00212d, 0x38084a63, 0x0013000f, 0x0027001d, 0x00430035, 0x005f0051, 0x007b006d, 0x00970089, 0x067341a5, 0x32080b74, 0x23072634, 0x21133335, + 0x35352622, 0x06141521, 0x7e262627, 0x212105ce, 0x070e7825, 0x83163221, 0x200d9a17, 0x201b9a17, 0xa91b8c27, 0x6b012229, 0x3c6418d6, 0xfe40390a, + 0x011911aa, 0x053119aa, 0x0dc80d15, 0x014a0515, 0x16f6feaa, 0x04060604, 0x3c200497, 0x31841897, 0x29081d9d, 0x1119d501, 0x1919122b, 0x19112b12, + 0x80fe2b55, 0x16161119, 0x0bfc1911, 0xa70b0e0e, 0x0504062b, 0x04050606, 0x04072a06, 0x03830704, 0x0d832b20, 0x55201583, 0x00211ab4, 0x08f04d05, + 0x13000f28, 0x2f001f00, 0xca4d3b00, 0x11212312, 0x01590721, 0x22272b0a, 0x1e070606, 0x36323302, 0xa3653736, 0x6995200e, 0x192609cd, 0x01d6fe12, + 0x9449752a, 0x1d202807, 0x0a0a2633, 0x871d3326, 0x1f162307, 0x0382161f, 0x240df64d, 0x0001abfe, 0x06f14980, 0x2616482d, 0x16271919, 0x19192716, + 0x658b1626, 0x032008b2, 0x24089866, 0x0012000e, 0x20ae8216, 0x089a6607, 0x33072725, 0x82152315, 0x0a996603, 0x2a15c022, 0x95660082, 0x8056340e, + 0x00802b2b, 0x00530003, 0x01ab0140, 0x000b00c0, 0x82620025, 0x0a32594a, 0x0e222728, 0x06070702, 0x0c523316, 0x33152205, 0x05e25a35, 0x14141725, + 0x82161715, 0x27272219, 0x28058206, 0x27222323, 0x07272627, 0x2f058206, 0x26343737, 0x35363435, 0x37372627, 0x36171736, 0x33260582, 0x17173233, + 0x0e831716, 0x3a083382, 0x0c150116, 0x0d0c1212, 0x1e0d1212, 0x02182934, 0x07060429, 0x15121920, 0x18302695, 0x12213629, 0x02110102, 0x08061504, + 0x22040103, 0x08030103, 0x02031507, 0x12030211, 0x84120101, 0x82428208, 0x04222716, 0x07070301, 0x1a830415, 0x01011323, 0x08508549, 0x77120c2a, + 0x1e332716, 0x400b0636, 0x64401912, 0x1f2d4812, 0x95172936, 0x0e020502, 0x031e0302, 0x03050901, 0x17040417, 0x01090503, 0x14820e82, 0x02020523, + 0x21068204, 0x1b821d04, 0x16030627, 0x03160404, 0x201b8206, 0x2214821d, 0x18030003, 0x2508de49, 0x00290019, 0xd7560036, 0x1e322305, 0xdd5b1502, + 0x34352205, 0x05557d26, 0x07132326, 0x23060627, 0x26061f5c, 0x22133727, 0x50353526, 0x163805f8, 0x1a61eb17, 0x4d2c213b, 0x1112213b, 0x1c0d0b1f, + 0x12191f30, 0x301ed92a, 0x25081488, 0x12af1e30, 0x03026619, 0x012a4428, 0x12116052, 0x2c4d3b21, 0x201a3b21, 0x24182c12, 0x090d2f3e, 0xd1fe1911, + 0x1788301e, 0xfe1e302e, 0x151219bc, 0x0a130966, 0x0530482c, 0x350a2153, 0x01000024, 0x36323335, 0x26343135, 0x06222323, 0x16143115, 0xab823333, + 0x31230636, 0x17153315, 0x35333537, 0x26262231, 0x08165501, 0xd6080d0d, 0x162d0483, 0x7f111d12, 0x11801615, 0x4001121d, 0x071f476b, 0x15826b20, + 0x15952b27, 0x112b9515, 0x0c48711d, 0x0b000725, 0x7a000f00, 0x1f3505cf, 0x27002300, 0x2f002b00, 0x37003300, 0x33130000, 0x33172335, 0x05337115, + 0x13280782, 0x07353315, 0x11333523, 0x27200b82, 0x89820382, 0x86232321, 0x82372007, 0x86352007, 0xab40260b, 0x55552bab, 0x2005842b, 0x220a84aa, + 0x8a2b802b, 0x832a2000, 0x2b2b2300, 0x1b821501, 0x8200ff21, 0x55012f04, 0x5580abab, 0xab2bd6fe, 0x2b2a2b2b, 0x2d822a55, 0x45120021, 0x03300877, + 0x0c000800, 0x15001100, 0x1e001a00, 0x26002200, 0x260aee71, 0x00460040, 0x8252004c, 0x231524ab, 0x83233735, 0x200887a0, 0x8a118837, 0x8a0720a2, + 0x4337200b, 0x13220654, 0xd4833523, 0x15233525, 0x82211523, 0x233522f2, 0x27478211, 0x40cb3533, 0x20808060, 0x8a200483, 0x80210483, 0x20008620, + 0x85078640, 0x2a603406, 0x402a6a40, 0x406ac0fe, 0x01402a2a, 0x20404075, 0x84ca8080, 0x848a2005, 0x20aa2205, 0x20308420, 0x25068440, 0x2a400001, + 0x2b8556fe, 0x06824020, 0x82020021, 0x011524e6, 0x82d501e0, 0x001323e2, 0x36680100, 0x33352409, 0x82372317, 0x011521d1, 0x27067b47, 0x0b95c055, + 0x2a6a242f, 0x2806bb48, 0x80ab5580, 0x006b8055, 0x2c418204, 0x01d50195, 0x0003006b, 0x000b0007, 0x86458212, 0x21e183d9, 0xd6822727, 0x01153324, + 0x0082c015, 0x80804034, 0x80806a40, 0x802b6b01, 0x152a802b, 0x562a566b, 0x65180600, 0x162a08a4, 0x25002100, 0x2d002900, 0x43823100, 0x8205857b, + 0x23112d05, 0x16161415, 0x36322133, 0x03113536, 0x21088a72, 0x65820733, 0x07876183, 0x41a00121, 0x05820511, 0x1d114036, 0x12000112, 0x0c2b111d, + 0xc00c0909, 0x8080d5ea, 0x952b2b95, 0x01210584, 0x212688b5, 0x6560d6fe, 0x6a012e06, 0x0d0996fe, 0xea40090d, 0x2b2b2b2a, 0x82038215, 0x07b151cc, + 0x90820d20, 0x90823020, 0x06222324, 0x16590315, 0x07112406, 0x52331523, 0x2329059e, 0x35231523, 0x35333523, 0x06b55223, 0x3335332f, 0x35273315, + 0xab2b0117, 0x19011812, 0x2a888212, 0x40556b19, 0x080d0d08, 0x882b2a16, 0x602b2108, 0x25075841, 0x00011119, 0x7d821555, 0x150d0829, 0x0d152b15, + 0x82094008, 0x602a2208, 0x0a0d5060, 0x1a001526, 0x28002300, 0x31238682, 0x60022e34, 0x162d05cc, 0x33151716, 0x27023e35, 0x16163523, 0x21858227, + 0x93823636, 0x36340724, 0xd64f1537, 0x3a203409, 0x3a26aa26, 0x27562a20, 0x0b56802f, 0x150b0b15, 0x50272fcb, 0x2737091e, 0x250f3545, 0x45350f25, + 0x4e179427, 0x03a5a576, 0x2fa80303, 0x7294174e, 0xc020087b, 0x08250982, 0x00001400, 0x20e38225, 0x08f58237, 0x31373527, 0x31152335, 0x37330727, + 0x15013317, 0x802b2a2a, 0x55405580, 0x959540d5, 0x2a2b8040, 0x71658080, 0x87c04d38, 0x2ebc8287, 0x012b0040, 0x00c001e7, 0x00150011, 0x82400034, + 0x333521bc, 0x2323b182, 0x82112335, 0x26263148, 0x27363435, 0x17231533, 0x26072737, 0x07232727, 0x2a05bf4c, 0x37170717, 0x33171716, 0x82373637, + 0x34362119, 0x3d0bca4a, 0x2a402b01, 0xc62bc06a, 0x39230e0d, 0x18fa2b2b, 0x0d0a1f15, 0x0d072a07, 0x18151f0a, 0x0e8c0202, 0x12500122, 0x3d06a064, + 0x80557010, 0x2babfe15, 0x26182b12, 0x482a1a40, 0x080a2515, 0x05202005, 0x15250a08, 0x0d850e0d, 0x09051f2a, 0x0816250b, 0x1119300b, 0x8205737e, + 0x002b2abe, 0x01d90155, 0x000500ac, 0x20c08209, 0x20be8219, 0x21918227, 0xbb820717, 0x07271724, 0xa8830727, 0x2720a182, 0x012f0f82, 0x2e1e4c61, + 0xc0ee1e5a, 0x371ed5c0, 0x82381e38, 0x1e373102, 0xc0c09e37, 0x1e4c1501, 0x231e5a2d, 0x371e5e2b, 0x1a851182, 0xfa7a1520, 0x00ab2609, 0x00170011, + 0x205b8223, 0xd94b1823, 0x8305200f, 0x021f216d, 0x27216882, 0x18788437, 0x2a0de34b, 0x1e3cebfe, 0x631e4b1e, 0x87221e22, 0xf24b1802, 0x82d5200d, + 0x1f4c221f, 0x571f8a29, 0x1f220cce, 0x5b523a00, 0x0a6f5a12, 0x26221722, 0x1522e382, 0xeb823523, 0x0720f782, 0x37260982, 0x1e171636, 0x3e423302, + 0x06a06109, 0x7d090c21, 0x3e3605bd, 0x080f240b, 0x0b17161c, 0x143c0451, 0x08461521, 0x1509040f, 0x64520412, 0x553c0811, 0x0d09080d, 0x0d08090d, + 0x33141280, 0x1a4c551e, 0x0c151038, 0x32230c68, 0x0707031a, 0x00071312, 0x00540001, 0x01ac0155, 0x001500ab, 0x35272500, 0x23263637, 0x17062223, + 0x06071517, 0x08060c44, 0x7ba60128, 0x0706051c, 0x0506077e, 0x02067b1c, 0x2a01090c, 0x77020c09, 0x062459a5, 0x24060c0c, 0x0f07a559, 0x000f0c0c, + 0x00820006, 0x02000223, 0x32fd8200, 0x001c0017, 0x003b0028, 0x3700003f, 0x37231533, 0x54353632, 0x232a0bd8, 0x25352115, 0x15152135, 0x56183427, + 0x26210803, 0x087f7917, 0x29060650, 0x21011737, 0x66cd2111, 0xc34dde66, 0x02553609, 0x0155fe00, 0x1117e956, 0x10181810, 0x35961711, 0x131f120b, + 0x24028413, 0xfe351114, 0x281f82bc, 0x0d279a00, 0x12d51219, 0x29048419, 0xd52b2b2b, 0x108201d5, 0x2e821717, 0x354a1727, 0x1f131511, 0x25338512, + 0x4301350b, 0xb18200fe, 0x4b001126, 0xc001b501, 0x3424b282, 0x23250000, 0x24090c64, 0x3e330706, 0x07c55402, 0x2622232e, 0x33321523, 0x17373632, + 0x25371715, 0x36099842, 0x114b0137, 0x15111006, 0x251c3326, 0x2b02263d, 0x19291b02, 0x821a2c1a, 0x03290802, 0x06050305, 0x06122f19, 0xd5fe206a, + 0x35103435, 0x35341035, 0xd535350f, 0x192f1206, 0x1626321d, 0x18243a22, 0x2b1a1627, 0x292c821b, 0x10112b01, 0x206a1106, 0x228235ae, 0x9c822b86, + 0x78004021, 0x0b250549, 0x00004200, 0x0b304113, 0x18223521, 0x21082a67, 0x9a820606, 0x1537362b, 0x15060607, 0x33331614, 0x54278235, 0x232505b9, + 0x15062223, 0x05f34f15, 0x35272725, 0x53d51616, 0x29080745, 0x173c24eb, 0x16140d1d, 0x181c0d14, 0x4c2c243c, 0x0d0b521d, 0x1f2f1016, 0x06054016, + 0x0d400506, 0x16109a13, 0x1d520b0d, 0xde5c014c, 0xc3220807, 0x221c1e2a, 0x1c220f0f, 0x21242a1e, 0x14042130, 0x0b17100b, 0x04061f16, 0x0d130605, + 0x0b10170b, 0x16820414, 0x8c6b2420, 0x0009260a, 0x01000015, 0x22828221, 0x54112111, 0x80280e90, 0x191200ff, 0x47195601, 0x27082255, 0x80fe1119, + 0x19118001, 0x4e081a55, 0x03260af7, 0x18001400, 0x4d822000, 0x25204982, 0x270edd75, 0x35330323, 0x15333723, 0x15220582, 0x58820133, 0x6a000121, + 0xeb2e0b84, 0x5640d6d6, 0x0140d640, 0x01aafeab, 0xe24e2a56, 0x11562908, 0x8096fe19, 0x80801640, 0x0abe7618, 0x07000331, 0x32001700, 0x05250000, + 0x21152527, 0x4f132115, 0x230807f9, 0x33363435, 0x07163221, 0x2e070622, 0x0e222303, 0x1e303102, 0x3e323302, 0x16163702, 0xfec10133, 0x80010281, + 0x1520c083, 0x2508608b, 0x03271b2a, 0x30221605, 0x2336261e, 0x36231111, 0x22301e26, 0x27030516, 0x2014891b, 0x01204914, 0x19129555, 0x04831219, + 0x141c2729, 0x0e131406, 0x82131914, 0x140d2502, 0x1c140613, 0x1826ff8a, 0x28002100, 0xff823100, 0x9c542320, 0x0c005007, 0x4c263421, 0x352906e3, + 0x16323733, 0x36342315, 0x06c24717, 0x80013323, 0x0546552b, 0x6a502b20, 0x0cbd2508, 0x2a0c0909, 0x56220f82, 0x0a846719, 0x6c800121, 0xb45005bd, + 0x09552b0b, 0x2a090d0d, 0x12121956, 0x0a848019, 0x0a545918, 0x00000228, 0x2b112137, 0x0282aa01, 0x37081682, 0x01350008, 0x00c001f8, 0x25000010, + 0x23042e13, 0x07030e22, 0x01351513, 0x1903f800, 0x2b4a3b2c, 0x2c3b4a2b, 0x36f80319, 0x12023501, 0x10101819, 0x02121918, 0x0101cbfe, 0x2a081469, + 0x0017006b, 0x0027001f, 0x8237002f, 0x821520e2, 0x9b2719ba, 0x0779410b, 0x27373728, 0x17070727, 0x0684023f, 0x0e8d0720, 0x19d5012b, 0xfe161611, + 0x118080aa, 0x05c36c19, 0x3318a030, 0x33171833, 0x1d0d4d33, 0x1d0e0d1d, 0x0f8e281d, 0x8040012a, 0x802b1912, 0x12192b80, 0x19230882, 0x841733e7, + 0x1e372420, 0x821e0d0d, 0x8e882003, 0x08ab470f, 0x0400ab26, 0x1b001600, 0x1724a882, 0x37352315, 0x2e0b1952, 0x32331733, 0x23270716, 0x53013315, + 0x42a04022, 0x802f0709, 0x1911ab2b, 0x804b3540, 0x48232001, 0x41d5356b, 0x2b270788, 0xab355c19, 0x72000600, 0xeb3105c7, 0x46003a00, 0x5f005300, + 0x78006c00, 0x07130000, 0x11521806, 0x46172033, 0x37200a5b, 0x200a114e, 0x18189823, 0x200bfc63, 0x2c5218c3, 0x06682226, 0x051f770a, 0x1c1c1423, + 0x20038314, 0x05db4f7a, 0x55040621, 0x12210685, 0x06025945, 0x18950121, 0x20233852, 0x224d851a, 0x85200a06, 0x1c14224e, 0x07255010, 0xb1442020, + 0x52402007, 0x894107a6, 0x4811200a, 0xd6470632, 0x23072710, 0x21373335, 0xcd472135, 0xab91270d, 0x00ff55ab, 0xc2470001, 0x2b2a220e, 0x0db0602b, + 0x0727252a, 0x27112311, 0x95011707, 0x2905b160, 0x01621ec0, 0x62a7fe59, 0x2882951e, 0x6b00552d, 0xab019501, 0x00000800, 0x82152301, 0x15232225, + 0x07aa6033, 0x8d400126, 0x2af81ef8, 0x6b224e84, 0x2585ab01, 0x23352528, 0x35072737, 0x1d861523, 0x5e06b860, 0xd5260887, 0x40002000, 0x4e834400, + 0x73363621, 0x072505e6, 0x22232626, 0x05d04506, 0x33151724, 0x44473335, 0x22052f05, 0x36343526, 0x3636023f, 0x17163233, 0x06833017, 0x2a301528, + 0x0e223102, 0xf2821703, 0x95013b08, 0x17060621, 0x0b0a1727, 0x1e13210d, 0x21190c31, 0x2aeb1c24, 0xfe191912, 0x101911ee, 0x0708110d, 0x130d111c, + 0x0d121105, 0x1a131912, 0x171e1513, 0x2af21513, 0x0940012a, 0x36820c16, 0x0b032708, 0x081a200d, 0x2d1e1c2c, 0x192bb808, 0x19128011, 0x0d121920, + 0x10060516, 0x0509120f, 0x1119060d, 0x0f16170f, 0x3157808b, 0x00c02308, 0x7118000f, 0x0722124a, 0x01841523, 0xb8823520, 0x40180383, 0x27240c35, + 0x5e373734, 0x3d510383, 0x476b240d, 0x822b4747, 0x0a664403, 0x00000926, 0x23072701, 0x34051870, 0x34343401, 0x843384a1, 0x01833284, 0x5eaaaa2b, + 0xa26464a2, 0x08596e5e, 0x0d00c028, 0x15001100, 0x01521800, 0x37332f0a, 0x05263435, 0x17231533, 0x17333523, 0x85823335, 0x1911d530, 0x80d51219, + 0xd6eefe19, 0x6b6b6bd6, 0x8387752b, 0x12d58029, 0x562a6b19, 0x6875a02b, 0x17200c53, 0x2011bc49, 0x494c8213, 0x2922109a, 0x7e49aaaa, 0xd6fe2211, + 0x08cd5baa, 0x0b00c02b, 0x32001700, 0x00003a00, 0x0ac54725, 0x200b0249, 0x05f94101, 0x0706062b, 0x16160607, 0x36323333, 0x07856435, 0x0d422720, + 0x01172205, 0x07384b2b, 0x1543d620, 0x80013e07, 0x12142013, 0xbc071219, 0x0a0b0206, 0x091912a1, 0x110c0b0f, 0x192f147a, 0x6818391f, 0x05664b55, + 0x193b3587, 0x140b2701, 0x140f1422, 0x1107dc08, 0xba12190c, 0x0d12100b, 0x0c0b3e0b, 0x82681213, 0x007d21f7, 0x22058c5a, 0x82220014, 0x152325a6, + 0x35231533, 0x3321ac82, 0x4df28235, 0x54080586, 0x33373321, 0x37273317, 0x27230723, 0xd5011723, 0x0d56402a, 0x40402a09, 0xfe0d0d09, 0x0249399f, + 0x5d643949, 0x42024239, 0x15805c39, 0x0c092b16, 0x080d1516, 0x740d0816, 0x6b909b74, 0x0400906b, 0x16001600, 0xcc01d501, 0x17000b00, 0x20001b00, + 0x21010000, 0x27668217, 0x11353617, 0x17252634, 0x2405c95c, 0x01371721, 0x837b8217, 0x332b0803, 0xe7feab01, 0x69446faa, 0x5afe1905, 0x1119051a, + 0x1f3f1901, 0x567768fe, 0x01c4d6d6, 0x692babab, 0x00010a0a, 0x19021912, 0x82ff0a0a, 0x1e3f2907, 0x2bcc9801, 0x2b19672b, 0x0120cf8f, 0x0120cf93, + 0x012fcfa8, 0x2b15166b, 0x16150d08, 0x0915090d, 0x83eafe0c, 0x6a6a24d2, 0x50060090, 0x132008c1, 0x2b26d082, 0x3b003300, 0x35424300, 0x07172711, + 0x37272626, 0x97681616, 0x5f332007, 0x2728061c, 0x07060617, 0x07363627, 0x23831b82, 0x0b821720, 0x13823720, 0x2e106142, 0x21083b73, 0x33221816, + 0x111d1292, 0x84121d11, 0x194f2805, 0x3b082216, 0x8240330d, 0x1917271b, 0x18cf3322, 0x0f832116, 0x20118a42, 0x20198698, 0x833a879f, 0x8edf2040, + 0x49468736, 0x2b220a0e, 0xcd823700, 0x00005323, 0x070f4f25, 0x15060622, 0x2906634a, 0x3233023e, 0x1515021e, 0xaa421523, 0x35352406, 0x42052634, + 0x4e180adc, 0x37200b2c, 0x08054e4f, 0x36361727, 0x01021e37, 0x45361fc0, 0x37442626, 0x190b0a1f, 0x29171611, 0x361f1f36, 0xaaaa1729, 0x0c091912, + 0x0ce2fe0c, 0x05e94c09, 0x08878020, 0x2405553f, 0x30182036, 0x28021526, 0x2e0e0838, 0x482cfb3b, 0x341c1c35, 0x14052d49, 0x19122a0c, 0x833d8382, + 0x2b972b45, 0x051a1219, 0x0b310c12, 0x42840b12, 0x850d0d21, 0x0d3e084a, 0x311e330d, 0x3324131c, 0x2b421120, 0x00182b1c, 0x00400003, 0x01c0016b, + 0x00020095, 0x00090006, 0x27151300, 0x11170737, 0xb5371133, 0x95956848, 0x48019556, 0x95954890, 0xfe2a0195, 0x2e9195d6, 0x1735252b, 0x11273707, + 0x01071123, 0x202f854b, 0x232e84b8, 0x2a01d6fe, 0x4a182e83, 0xad5107d2, 0x01002205, 0x05cb7d21, 0x15211529, 0xfed50121, 0x87aa0156, 0x6b012603, + 0x366aa06a, 0x2682826a, 0x01400040, 0x53c001c0, 0x3e2010a7, 0x39127958, 0x17352315, 0x021d3335, 0x23273523, 0x15023b35, 0x15330723, 0x33353323, + 0x1f512515, 0x16322208, 0x25258215, 0x01331523, 0x0d4dd595, 0x12193306, 0x2b2b55d5, 0x802b2b2a, 0x2bab2a2a, 0xfe2aab2b, 0x1a8615eb, 0x15d52b24, + 0x374d6b01, 0x2b80210c, 0x2a202a82, 0x2b210482, 0x8600822a, 0x1515261a, 0x000300d5, 0xde741820, 0x00132208, 0x269d823b, 0x14152335, 0x82151716, + 0x2335256b, 0x27363635, 0x07227782, 0xb2510614, 0x26222105, 0x87064244, 0x15332208, 0x05a24833, 0x32302e82, 0xaad50116, 0x802b1c24, 0x2a241c2b, + 0x16204a56, 0x16256f82, 0x2b161f1f, 0x2205852b, 0x8220162a, 0x39058213, 0xc0c02b01, 0x98082d1e, 0x08982b2b, 0x4040b32d, 0xc02016b5, 0x161620c0, + 0x0483151f, 0x1f2b2b2b, 0x15201616, 0x0007001f, 0x309a8215, 0x00ee01eb, 0x00290024, 0x00410035, 0x00650061, 0x2aa28269, 0x27262634, 0x07060626, + 0x18231523, 0x27167258, 0x33253636, 0x17231716, 0xa284a785, 0x0b8a3320, 0x07073733, 0x06030f06, 0x34272627, 0x35373535, 0x023e033f, 0x06505617, + 0x35068753, 0x351eeb01, 0x34422222, 0x0a353a0f, 0x0d2d0311, 0x0c091509, 0x06840001, 0xfe2f2728, 0x29036175, 0x144920ad, 0x4cde2006, 0x313b06f4, + 0x04050404, 0x2e040505, 0x01052626, 0x01020101, 0x1a302409, 0x1d172819, 0x822b491a, 0x55012a00, 0x082a3d23, 0x202a0f07, 0xb958182a, 0x12a4260d, + 0x27392149, 0x079e586b, 0x78210787, 0x82008202, 0x1d0a2847, 0x05052f1c, 0x8206040a, 0x18032f5b, 0x05040f22, 0x1e192d1e, 0x6bb30e32, 0x31472b15, + 0x00112c0a, 0x00190015, 0x0100001d, 0x18232627, 0x200df05c, 0x06354725, 0x35233536, 0x67b30133, 0x12c3120c, 0x01121919, 0xfe19122a, 0xd69696d5, + 0x01230083, 0x180c674d, 0x27070043, 0x2b2b12c3, 0x2a2b2bab, 0x2c549949, 0x006b0002, 0x01c0012b, 0x000800d5, 0x28ac8214, 0x11233521, 0x27213533, + 0x0ad55923, 0xfec00129, 0x012a2ad5, 0x6b552b2b, 0xab250856, 0xaa56fe2a, 0x82b6836b, 0x0c002903, 0x40002b00, 0xc001d501, 0x57063f55, 0x3c28070c, + 0x44004000, 0x4c004800, 0xf3825882, 0x03820720, 0xfb862720, 0xfb823720, 0x03821720, 0x07260783, 0x37272607, 0xe35b2736, 0x16152306, 0x02861716, + 0x35353624, 0x17822634, 0x03833483, 0x34863320, 0x2a2b0125, 0x822b162a, 0x952a2704, 0x2a152b2b, 0x05842b2a, 0x51369d3c, 0x0208362f, 0x080c0110, + 0x030d0958, 0x4719171a, 0x2f55262c, 0x070a0d09, 0x25820b4f, 0x2a2a4025, 0x822a2aaa, 0xab012705, 0x6b2b152b, 0x0584402b, 0xde2b1523, 0xa2741936, + 0x01022a11, 0x0759090d, 0x0210010c, 0x825c8256, 0x28d98202, 0x012b0080, 0x00eb0180, 0x06c5541e, 0x9d822720, 0x0809c76c, 0x0622234c, 0x2707021d, + 0x33161613, 0x13373632, 0x07371707, 0x37370735, 0x35012715, 0x04040720, 0x161f2a07, 0x4b201f16, 0x060c026c, 0x6c020c06, 0x2a131165, 0x2a061141, + 0x28196c01, 0x0606050a, 0x160c0c05, 0x0a161e1e, 0xfe131928, 0x008207ba, 0x34460135, 0x8b7f050d, 0x8b050c11, 0x0002007f, 0x015500ab, 0x82ab0155, + 0x000a3d86, 0x23152500, 0x33153735, 0x07273335, 0x40aa5501, 0x5555402a, 0xd62b2b80, 0x5555abab, 0x15292a82, 0xeb012000, 0x1300e001, 0x05ef5300, + 0x07272726, 0x17070727, 0x17240183, 0x37371737, 0x2c050b53, 0x34eb0117, 0x49284d07, 0x074d2849, 0x31098834, 0x312051e0, 0x0001207d, 0x44124e3c, + 0x11441f1f, 0x09863c4f, 0x294e122f, 0x7e321f52, 0x00040020, 0x01160015, 0x208a82ff, 0x26098212, 0x0059004d, 0x82211300, 0x0775578b, 0x3316142a, + 0x25233533, 0x36051527, 0x2105d441, 0x4a510707, 0xb257180a, 0x17062307, 0x57180607, 0x2b5516b0, 0x4029080b, 0x192b8001, 0x1280fe12, 0xc0121919, + 0x800001c0, 0x01022401, 0x16020317, 0x071b0502, 0x05010409, 0x0401042c, 0x1c030805, 0x32128204, 0x01011703, 0x16030417, 0x081b0402, 0x2c050508, + 0x85040505, 0x04032219, 0x065b5f66, 0x6b800123, 0x084b836b, 0x1200ff21, 0x55802b19, 0x080a34aa, 0x26040312, 0x050b0104, 0x05051d04, 0x0304021d, + 0x2704020b, 0x8b130204, 0x04042118, 0x01201884, 0x03212882, 0x070e4405, 0x460acb60, 0x0f270586, 0x21250000, 0x82172111, 0x821120fd, 0x82352003, + 0x55012703, 0x2a01d6fe, 0x0085552b, 0x5656012a, 0x56aafe56, 0x0300562a, 0x3508944e, 0x001f000f, 0x0100005a, 0x34353632, 0x3031022e, 0x1415020e, + 0x0d8c0716, 0xaa4e2720, 0x8b013035, 0x15101f16, 0x10161010, 0x130d5520, 0x820a0c0a, 0x50132102, 0x3b26814e, 0x16205501, 0x141e210d, 0x0d211e14, + 0x13152016, 0x1112070d, 0x12110b0b, 0x55130d07, 0x1823714e, 0x24089840, 0x000600c0, 0x2bdf8216, 0x21153307, 0x22073335, 0x3e343526, 0x1e31e682, + 0x06141502, 0x40d50001, 0xd5402a01, 0x110d1912, 0x3a02820d, 0xc0c00119, 0x1955abab, 0x1d1c0911, 0x1c1d1414, 0x00191109, 0x002b0001, 0x6ed5016b, + 0x3727069b, 0x21352127, 0x4e072737, 0xf36e0930, 0x04003106, 0x2b004000, 0xd501e201, 0x1e000b00, 0x3e003600, 0x200fcf53, 0x05844534, 0x15331525, + 0x82263533, 0x76362085, 0x37220af7, 0x17550635, 0x36362b06, 0x35233735, 0x17331523, 0xeb446037, 0x19752b07, 0x19124011, 0x16144a2b, 0xe049ac29, + 0x0e122605, 0x311d2b20, 0x2502821d, 0x752b6116, 0x4d5a2335, 0x19122405, 0x822a8319, 0x80122904, 0x36140295, 0x6e442a1e, 0x1d302d86, 0x370a2e08, + 0x1c311d24, 0x401d311c, 0x174faa80, 0x2206e04d, 0x82c001d5, 0x002c23ad, 0xf2520100, 0x17072d05, 0x26272217, 0x26260707, 0x27363727, 0xb285a382, + 0x1e145608, 0x36323303, 0x26343535, 0x1201d501, 0x19192a1f, 0x01121f2a, 0x24284b75, 0x2d2f090d, 0x092f1749, 0x090c0c04, 0x250d084b, 0x3c6d5b42, + 0x010d0d08, 0x0f0d0296, 0x0d0f0c0c, 0x0c4b9602, 0x172f0a05, 0x092f2d49, 0x0828240d, 0x3c080d0d, 0x25425b6d, 0x094b080d, 0x2484820c, 0x0140005f, + 0x4e8482a1, 0x37230565, 0x6e371523, 0x362105a3, 0x2c6c8236, 0x37363407, 0x14150606, 0x33071716, 0x2c938235, 0xaa316401, 0x0a261f31, 0x212d2609, + 0x200584e1, 0x3010841c, 0xab318f01, 0x2b471731, 0x18112715, 0x46283050, 0x20088733, 0x82178419, 0x82802066, 0x82802066, 0x00112566, 0x13000019, + 0xcd485182, 0x3e3f0808, 0x07353502, 0x30333523, 0x1c80021c, 0xaa401f30, 0x1c301f40, 0x01aaaa2b, 0x352080c0, 0x2b570524, 0x2405572b, 0x6b802035, + 0x14191340, 0x55000300, 0xe1011500, 0x0f00e101, 0x27001b00, 0x7b010000, 0x17200712, 0x2720b083, 0x210b3844, 0x43562737, 0x2b012c09, 0x3d221516, + 0xabab1c30, 0x46a90101, 0xcf2506b2, 0x1e2d2e1e, 0x3202822d, 0x012e1e2e, 0x19068f2b, 0x6a28402e, 0x076a9292, 0x4d40070c, 0xd82207cf, 0x1d822e1e, + 0xd8472685, 0x5d0f200a, 0x002006e9, 0x10e28018, 0x21112122, 0x0383cd83, 0x2a0c934f, 0x01d6fe12, 0xd6d62a2a, 0x4f808056, 0xfe270d95, 0x6b0001ab, + 0x822a802b, 0x0d4047da, 0x23370024, 0x03853311, 0xa0331534, 0x769b7575, 0x75759a76, 0x80000140, 0xd5d580fe, 0x164d0900, 0x000b3708, 0x0026001a, + 0x003f0035, 0x00570053, 0x0069005f, 0x36321300, 0x97753435, 0x34172206, 0x06dd4e26, 0x15060625, 0x99373315, 0x35072c1a, 0x37271521, 0x17352515, + 0x75233505, 0x764206ed, 0x23232306, 0x085e1735, 0x35232905, 0x07333523, 0x23153315, 0x33220f82, 0x4c418015, 0x0e672c06, 0x101e0d0c, 0x0c0d1e10, + 0x92abaa0e, 0xfe403c13, 0x014040d6, 0x00ff402a, 0x07070435, 0x06042b04, 0x15200406, 0x1515ca15, 0x826a4016, 0x01362104, 0x2b08af73, 0x05150d49, + 0x06070706, 0x0c0d1505, 0x8b086d48, 0x2b962514, 0x2b40402b, 0x6a244c82, 0x40050615, 0x05354984, 0x0b200b06, 0x4040200b, 0x150b1515, 0x00155520, + 0x006b0006, 0x0a881815, 0x00312208, 0x05796835, 0xd7830120, 0x4f141121, 0x112705fc, 0x11032634, 0x18271133, 0x2608d659, 0x14151632, 0x86152306, + 0x2235261e, 0x36343526, 0x5dee8207, 0x35210517, 0x0af96333, 0x16d6e72b, 0x0980090c, 0x0d0d080c, 0x21088708, 0x00841642, 0x0e4b8818, 0x00019530, + 0x289500ff, 0x0a0e0e0a, 0x09090c2a, 0x0983260c, 0x09832820, 0xf7824a20, 0x15154008, 0x15000500, 0xd5012b00, 0x0700d501, 0x26002200, 0x4a003a00, + 0x17010000, 0x27070717, 0x35273727, 0x37173233, 0x2a232626, 0x33153104, 0x07060615, 0x34351733, 0x33032626, 0x23052335, 0x60173727, 0x272705d6, + 0x17152327, 0x73343137, 0x45460580, 0x01340808, 0x1d1d0e6a, 0x1d1d0d0e, 0x0f122a72, 0x12210d1f, 0x1c211d09, 0x2b1c2012, 0x167b5509, 0x5656ee27, + 0x2c969601, 0x0b3c2507, 0x2a9b110f, 0x1119aa96, 0x100d1911, 0x22058745, 0x840d1d95, 0x052d083b, 0x0a1f0a2e, 0x062e2a0b, 0x0e2e1c26, 0xfe1e2b1a, + 0x1080eab3, 0x0b0e0e14, 0xc0390711, 0x1911402a, 0x09121940, 0x13131d1c, 0x12091c1d, 0x0aad4f19, 0xd6820b20, 0x2f00213d, 0x49003b00, 0x23370000, + 0x33023e34, 0x020e2215, 0x06223537, 0x34331506, 0x42273636, 0xc28207a1, 0x0623372e, 0x22232306, 0x33151506, 0x17363635, 0x240ba342, 0x27262223, + 0x05235e23, 0xeb263433, 0x45351e2b, 0x29361f28, 0x311d9517, 0x1d112b1d, 0x07a943d9, 0x042a5f2b, 0x0e401823, 0x291d8012, 0x069351a4, 0x1840313e, + 0x032a0423, 0x12801d29, 0x344628d5, 0x29182a1e, 0x1d2b2136, 0x1d121e30, 0x19119611, 0x07293984, 0x0d131e17, 0x31093136, 0x07ef51eb, 0x161f152b, + 0x30093120, 0x00130d35, 0x08634308, 0xa000942e, 0xb800ac00, 0xd000c400, 0xe800dc00, 0x24050b64, 0x37272623, 0x05396733, 0x25065067, 0x27262607, + 0x006a3135, 0x0615270c, 0x35270706, 0x21833436, 0x20066d67, 0x20128217, 0x23fc8523, 0x33161415, 0x33202e82, 0x0722df82, 0x56182226, 0x2d8207ae, + 0x82373521, 0x56152012, 0x5d5a055e, 0x31232905, 0x37363635, 0x17140617, 0x37207282, 0x31215085, 0x20128227, 0x23438533, 0x27263435, 0x450a9a56, + 0x17970b09, 0x50188a4d, 0x012f0a63, 0x210a06c5, 0x01171c04, 0x05050d04, 0x83051605, 0x10182805, 0x09071627, 0x83200709, 0x28162304, 0x19821710, + 0x1b820d20, 0x0d050528, 0x100e1804, 0x6c562102, 0x02212407, 0x8a180d11, 0x10172238, 0x24388528, 0x060a0a06, 0x24388215, 0x0e040504, 0x223e8504, + 0x86110d17, 0x5da72038, 0x0d250553, 0x0c0c091d, 0x24038209, 0x0d0d082e, 0x20138208, 0x8607871d, 0x8642201f, 0x0d07220f, 0x25098509, 0x07092001, + 0x8d8e222c, 0x8b200321, 0x22c79a8d, 0x8a181027, 0x890120c7, 0x0607228f, 0x20c8890a, 0x25b08217, 0x11170505, 0xc3831627, 0x09072023, 0x82a38435, + 0xcf4518a7, 0x20089108, 0x51238740, 0xda86086f, 0x0002002e, 0x01150080, 0x00e001ab, 0x0040000b, 0x4505044a, 0x6c1807b8, 0x23230978, 0x65262635, + 0x15210535, 0x29158217, 0x27070727, 0x36343537, 0x0c820737, 0x36313730, 0x17161732, 0x16161731, 0x01163233, 0x2e601220, 0x9d260805, 0x05040616, + 0x26181506, 0x0106050d, 0x04262b2a, 0x06372240, 0x732b2005, 0x0b0a160a, 0x290a1106, 0x01130d19, 0x2660198b, 0x96210806, 0x0605e0e0, 0x0f150506, + 0x0d131c06, 0x07040f1d, 0x6b8b3c04, 0x1a564b36, 0x2412724a, 0x654c1212, 0x281e8241, 0x1b14240c, 0x00040012, 0x20b1822b, 0x24b184d5, 0x002e0026, + 0x0d6e4635, 0x33030729, 0x33151737, 0x82372735, 0x05425d8f, 0x0721cf82, 0x23128207, 0x11331537, 0x35280182, 0x35233507, 0xcb173533, 0x3d068243, + 0x252d3b3e, 0x0d2c2b2e, 0x1e233c15, 0x06140f30, 0x08080b13, 0x50c02a70, 0x4b555020, 0xa389354b, 0xfe492e08, 0x802babd3, 0x19402ca1, 0x181d2a1e, + 0x030b0922, 0xa347642e, 0x01d5fe95, 0x2680952b, 0x00352520, 0x001e0006, 0x01c4011e, 0x001600d5, 0x06f2451a, 0x9e824020, 0x17153323, 0x23038335, + 0x23232634, 0x2e08ec45, 0x15333723, 0x07011323, 0x15141417, 0x43161415, 0x06860645, 0x17373224, 0xc6833527, 0x47080384, 0x202514fc, 0x2b111940, + 0x0856080d, 0x2a2f040d, 0x78fed92a, 0x11194d1e, 0x0d08090d, 0x09080d80, 0x270a0a0d, 0x202520fb, 0x40010f25, 0x59392514, 0x1912ae40, 0x0c0c0940, + 0x2b2b4009, 0x8801bcfe, 0x02014d1e, 0x1912ea01, 0x0806f441, 0x27050926, 0x79209962, 0x0e342054, 0x0004000e, 0x0180002b, 0x008001d5, 0x00340025, + 0x005e0044, 0x06220100, 0x23022e07, 0x8205556e, 0x229e8206, 0x4e17021e, 0x3e220554, 0xc1823503, 0x3c760520, 0x29b78206, 0x25022e17, 0x07060614, + 0x8a4e3636, 0x82072008, 0x3635280e, 0x36363736, 0x82163233, 0x15172237, 0x06024826, 0xa0012408, 0x14021e15, 0x1717211f, 0x02141f21, 0x1f16151e, + 0x18302a19, 0x14142610, 0x30181026, 0xfe1f192a, 0x82090c95, 0x100a29a5, 0x6a01121e, 0x0a101e12, 0x092fc482, 0x1107d10c, 0x050c080c, 0x0c0c1209, + 0x82060812, 0x113c080a, 0x080c0807, 0x80010c08, 0x1305151c, 0x05130e0e, 0x161f1d14, 0x2740300b, 0x0c0a0112, 0x12010a0c, 0x0b304027, 0x0b401f16, + 0x080d0d08, 0x11251540, 0x27331e08, 0x081e3327, 0x40152511, 0x0b2c1383, 0x03090420, 0x03070316, 0x05080805, 0x16280682, 0x04050903, 0x0b000606, + 0x34087145, 0x0018000b, 0x00310024, 0x004c003d, 0x00670058, 0x00820073, 0xb9611889, 0x26172d0d, 0x07222326, 0x33151516, 0x25263435, 0x820b3346, + 0x07062317, 0x19840606, 0x230b2455, 0x34352317, 0x21091741, 0xe7440715, 0x581a8e0a, 0x1a8e0b43, 0x23353726, 0x37172315, 0x09f36118, 0x1e0d662a, + 0x14141510, 0xb9fe0e6a, 0x29067c43, 0x1015143b, 0x0e0c0d1e, 0x5546406a, 0xaa802107, 0x20092049, 0x07564c15, 0x0fab802d, 0x101e0e0b, 0x0c0e1d10, + 0x43abfe0e, 0x8021078b, 0x2b0e82ab, 0x1e10101d, 0x250f0b0e, 0x40403020, 0x20085b4c, 0x26d4823b, 0x0c0c1b13, 0x8727150d, 0x821b2042, 0x15052612, + 0x1b0c0c0d, 0x064e4359, 0x1e826e20, 0x20073f49, 0x2013928c, 0x24139274, 0x402a2ab4, 0x084a5940, 0x0f00d52b, 0x2b001f00, 0x00004300, 0x09aa4d01, + 0x26222323, 0x0d944e17, 0x18352321, 0x27087c46, 0x35211537, 0x37363634, 0x2d05c858, 0x26260717, 0x1e152323, 0x094b0102, 0x02820a0d, 0x0e0d1324, + 0x8b4e5512, 0x10152505, 0x2b2a751f, 0x30080082, 0x00ff402a, 0x2b1e311c, 0x0d211280, 0x0911081e, 0x1c301e2a, 0x12077501, 0x110c0c11, 0x130d0712, + 0x161fa813, 0x131e210e, 0x0e211e13, 0x2b151f16, 0x3435822b, 0x20d5d555, 0x2d052435, 0x1f0a0b2a, 0x052d0505, 0x02003524, 0x0b8a1800, 0x00172a07, + 0x2500001e, 0x06141533, 0x25ab8223, 0x36341135, 0xa3553733, 0x33112206, 0x06bf6737, 0x88186b20, 0x30080d5f, 0x6b6b556a, 0x19125595, 0x80011219, + 0x19011812, 0xff155512, 0x40558000, 0x0500402a, 0x2b002b00, 0xd501eb01, 0x2e000f00, 0x3a003400, 0x00005600, 0x0cbd4e01, 0x36342723, 0x86651837, + 0x06062111, 0x26287e82, 0x17071727, 0x37272707, 0x37210482, 0x055d5a17, 0x37362336, 0x26270627, 0x36363726, 0x15161617, 0x32333617, 0xc0011716, + 0x2608fb4e, 0x1c080c5d, 0x182c2746, 0x2c073a79, 0x01213b4d, 0x05090402, 0x28152115, 0x08008217, 0x17842d38, 0x17172d2d, 0x18260b96, 0x240b2618, + 0x103f1309, 0x06060c10, 0x080c1907, 0x1c184c08, 0x010d3b25, 0x08121940, 0x14141c1d, 0x12081d1c, 0x1e0b2b19, 0x211a180f, 0x61184d3b, 0x092b08b5, + 0x01020911, 0x170d2214, 0x82171617, 0x2d2e2d49, 0x13a01617, 0x18131818, 0x09092413, 0x4d824782, 0x080f0528, 0x212a0c2c, 0xfd830300, 0x82000221, + 0x000528fd, 0x00330027, 0x82070100, 0x033721cb, 0x082d8818, 0x8c171621, 0x23da83fa, 0x15233706, 0x3708c875, 0x5bf3d501, 0xb7d53c1f, 0x1b2f3e23, + 0x233e2f1b, 0x1f142e19, 0x2c223e1a, 0x9283d582, 0x17331c29, 0x82231020, 0x822b4040, 0x91012802, 0x3c1e5af3, 0x83a6fed5, 0x24308328, 0x121f0d0e, + 0x25b98714, 0x08200d0d, 0x27836b08, 0xce684020, 0x0019220c, 0x10a67128, 0x430a0049, 0xa1710eb5, 0x089f4c0a, 0x680a9343, 0x08770bc4, 0x0cab2508, + 0x0605160d, 0x05220082, 0x915d0d16, 0x0003290a, 0x1300000f, 0x03112111, 0x2709d466, 0x80014007, 0x4d4d1e55, 0x01270287, 0x0180fec0, 0x8af3fe80, + 0x01002912, 0x2c002b00, 0xd501d501, 0x0f897f18, 0x23351730, 0x34353335, 0x33333636, 0x06222315, 0x06821515, 0x183e1521, 0x320a8d7e, 0x243e2f19, + 0x21152a2a, 0x092a3515, 0x2940400d, 0x5a1d3446, 0x350809bf, 0x26384527, 0x35409107, 0x40142215, 0x402b080d, 0x39240494, 0x00060049, 0x02800000, + 0x00800100, 0x001a000e, 0x00340028, 0x00520042, 0x16322500, 0x15161617, 0x08452115, 0x45072005, 0x36450c35, 0x0c4f450b, 0x8208424e, 0x18332039, + 0x080fd460, 0x1a000120, 0x1412122e, 0x121400ff, 0x12912e12, 0x11121919, 0x05291919, 0x1d10070c, 0x600e0c0e, 0x70444b01, 0x82672006, 0x101d260d, + 0x0d050c07, 0x07bf7d60, 0x111d1232, 0x0bf01d11, 0x12200808, 0x20132223, 0x050b0808, 0x2b070545, 0x06010118, 0x0d160506, 0x2f1a2221, 0x4a2c1387, + 0x0605160d, 0x17010106, 0x0001221a, 0x85055951, 0x05002905, 0x2b006b00, 0xd5019501, 0x2408796b, 0x01000035, 0x09ec4723, 0x4b06ce4e, 0xe447052a, + 0x35362107, 0x03202082, 0x200a8556, 0x280b8213, 0x0d2b6b01, 0x0d085608, 0x47b6832b, 0x0c8208e1, 0x2020b12d, 0x10202045, 0x20354040, 0x47800120, + 0x192105df, 0x0ad64712, 0xff290c84, 0xc0c0c000, 0xcbfe3540, 0x064144c0, 0x9482d520, 0x18002921, 0x20cd9b49, 0x08684903, 0x12000e24, 0x4c182400, + 0x11340810, 0x21331614, 0x25173732, 0x37173335, 0x31343027, 0x33153335, 0x40080382, 0x15151616, 0xc4013527, 0x3b1e78fe, 0x12190202, 0x0a0a0001, + 0x44dafe12, 0x40a74e2a, 0x251b4056, 0x88013c2b, 0x0b053b1e, 0x1100ff06, 0xb7120519, 0xa72b2b2b, 0x2a2a2d01, 0x1e2d082d, 0x00442ac3, 0x12d84905, + 0x49010021, 0x172114d5, 0x22d64927, 0x17352324, 0xd3491001, 0x1c40240b, 0x49e44040, 0x452213d4, 0xd3492020, 0x7540220f, 0x1bd44935, 0x5e18ac82, + 0x4618072a, 0x02207623, 0x20084449, 0xeb421813, 0x07072613, 0x33273727, 0x09404415, 0x25069345, 0x6a1e6a04, 0xda5e782d, 0x84cb2011, 0x03002117, + 0x2006bd44, 0x24e082d4, 0x002f001a, 0x05114600, 0x34053d08, 0x35173736, 0x06061723, 0x021e1415, 0x032e3517, 0x022e3425, 0x031e1527, 0x07061415, + 0x27331527, 0x79013636, 0x3c1f5b97, 0x1ffafe79, 0x2f803319, 0x341d251f, 0x36202946, 0x80011729, 0x18860987, 0x9735013b, 0x793c1e5a, 0x17412553, + 0x1d2f8032, 0x492a2e51, 0x2b042439, 0x392e1d04, 0x870a8a21, 0x0a09691e, 0xb3770d20, 0x1edb6e12, 0x6e0a1146, 0x104612d7, 0x1540220b, 0x05cc6e0d, + 0xde6e2b20, 0x35798207, 0x0136002b, 0x00ca01d5, 0x000f0007, 0x17373700, 0x27071737, 0x07823507, 0x07822720, 0x55a02b3f, 0x55b51e97, 0xb5558080, + 0xa055971e, 0xaa56a056, 0x8056cc1e, 0xcc568080, 0xa056aa1e, 0x09407300, 0x15000f24, 0x40432500, 0x514f1808, 0x82272008, 0x4f461848, 0x06142909, + 0x27372707, 0x78fec401, 0x270bef72, 0x3c1f5bc4, 0x981e1e04, 0x26083073, 0x3c1f3972, 0x731e8801, 0x80220a41, 0x22821e5a, 0x11985a22, 0x24073c73, + 0x001e3972, 0x08aa7001, 0x00001327, 0x33153313, 0x3dd61815, 0x33353708, 0x33352335, 0xabab2aeb, 0x6b2a6b6b, 0x01abab6b, 0x56406ad5, 0x04836a40, + 0x745fb482, 0x2337280e, 0x21053311, 0x82072115, 0x2a552e3f, 0xfe80012a, 0x805501ab, 0x012bd5d5, 0x283095aa, 0x23113301, 0x21352101, 0x29668217, + 0x2a2aab01, 0x550180fe, 0x3182abfe, 0xfed50128, 0x40000156, 0x649140d6, 0x2f822520, 0x68820120, 0x64823720, 0xaa282684, 0x404000ff, 0x2b404096, + 0xd5217084, 0x27cf82d5, 0x01400027, 0x00c001d5, 0x0124cf82, 0x15233523, 0x8b480384, 0x33152305, 0xc4853335, 0x836e6e21, 0x150121c9, 0xe084d683, + 0x01246b91, 0x13352115, 0x9f84a382, 0x6a209282, 0x01216884, 0x22a982d5, 0x82550156, 0x4303206a, 0xf059085a, 0x37002105, 0x21209982, 0x03200382, + 0x22070241, 0x82b52a2a, 0xaa01219a, 0x4024cf82, 0x001400d6, 0x85077460, 0x740f202f, 0x3b331222, 0x47003f00, 0x51004d00, 0x59005500, 0x23250000, + 0x82273335, 0x8237204d, 0x20078303, 0x28078621, 0x23353337, 0x35331507, 0x201f8217, 0x20078603, 0x21078637, 0x79493503, 0x832f8305, 0x23168203, + 0x23353733, 0x0d841582, 0x01201c82, 0x40260383, 0x2a2b2b2b, 0x0584ab2a, 0x2a00ff2f, 0x2b2b2a2a, 0xa02b2b95, 0x80802040, 0x84048360, 0x552b2809, + 0x5655552b, 0x82805656, 0x2b16242b, 0x8220452b, 0x00012900, 0x2b402020, 0x55956a6a, 0x56201582, 0x20263482, 0x80604040, 0x0583e0fe, 0xfe240484, + 0x402b40ab, 0x56201782, 0x402a5b82, 0x50552a2b, 0x0120e020, 0xb8452020, 0x00c42e08, 0x00140010, 0x00300024, 0x13000037, 0x05994e27, 0x2315372d, + 0x23262637, 0x23170622, 0x76131715, 0x01210c27, 0x200e8227, 0x060d4315, 0x0706233a, 0xb9363617, 0x1c34161f, 0x2e1a4c2c, 0x3c143380, 0x4c241323, + 0x40912a2a, 0x21081282, 0x1e354528, 0x1e400e10, 0xca7d8801, 0x29170909, 0x24131f36, 0x0d042b88, 0x010e0b20, 0x100e1f83, 0x31821e25, 0x1e192508, + 0x2b192109, 0x0e40f7fe, 0x45351e10, 0x16341c28, 0x78fe1e40, 0x2410ca41, 0x29361f13, 0x1a770917, 0x29121f18, 0x08151042, 0x33151725, 0x21150535, + 0xfed50135, 0xfed66a56, 0x01aa01c0, 0xb52a2ad5, 0x2acb4040, 0x0002002a, 0x01950055, 0x826b0195, 0x113008ea, 0x33130000, 0x23352315, 0x07233717, + 0x07172327, 0x33173733, 0x2b2b5655, 0x23323cfd, 0x443c3124, 0x322a2b32, 0xabd66b01, 0x3b3b653a, 0x48487165, 0xda5a6f84, 0x001a2405, 0x8232001e, + 0x088c433f, 0x36323328, 0x34353536, 0xf7592326, 0x23262105, 0x28057f57, 0x15060622, 0x16161415, 0x2b1f8733, 0x6b802b26, 0x1180806b, 0x121b121d, + 0x1d280282, 0x5555ea11, 0x111d1255, 0x06851082, 0x40950123, 0x82018235, 0x1328250f, 0x28131a1a, 0x40231b82, 0x8240aaaa, 0x85aa200f, 0x21068326, + 0x13440700, 0x00ab2e06, 0x00280018, 0x0030002c, 0x00380034, 0x8a918e3c, 0x33232190, 0x2305b066, 0x26222323, 0x36261682, 0x15231733, 0x4b490533, + 0x86172006, 0x6b553307, 0x6b6b5555, 0x0e081912, 0x1219080e, 0x191912c0, 0x04844012, 0xfe404026, 0x552b2beb, 0x2a330282, 0x8080ab2a, 0x2b2bab01, + 0x192b2b2a, 0x130d2012, 0x83200d13, 0x86802022, 0x802b2304, 0x00856ad5, 0x00020029, 0x01950040, 0x826b01c0, 0x9a2f20a3, 0x4e052099, 0x35230702, + 0x83333634, 0x053763a6, 0x566b4030, 0x116b6b56, 0x0e0e1219, 0x01111912, 0xa0181915, 0x9524085c, 0x6b01356a, 0x5621818e, 0x61858955, 0xa4570677, + 0x000d2105, 0x2c05784c, 0x15062221, 0x32213711, 0x34113536, 0x9a501826, 0x0b64500e, 0xfeab012c, 0x551912ab, 0x19112b01, 0x1f50bc19, 0x4c672006, + 0x80270f79, 0x01121955, 0x58191100, 0x7a4c08ef, 0x22f88510, 0x8224000d, 0x05e044f8, 0x3315332c, 0x23353335, 0x15331537, 0x9d183523, 0xbc580760, + 0x2bc02908, 0x2b552b2a, 0x2aab2b2b, 0x0b46a118, 0x6b6b012a, 0x4040966b, 0x2b2a152b, 0x35076041, 0x00551219, 0x00150003, 0x01000295, 0x0016006b, + 0x00300022, 0x54950100, 0x58453320, 0x8c25200a, 0x15012485, 0x8280552b, 0x23e0834a, 0x95191255, 0x02827d82, 0x2a95fe29, 0x2a562b2b, 0x8d011616, + 0x822b2070, 0x802b211b, 0x00218a85, 0x08df5d04, 0x17000326, 0x33002f00, 0x23237e83, 0x42233735, 0x072111eb, 0x5a149235, 0x0121069b, 0x0ef84295, + 0x426ad221, 0x402005df, 0x2405234c, 0x01404040, 0x10f84255, 0x08434020, 0x250a830a, 0x40406a2a, 0x0c430800, 0x00032308, 0xca790013, 0x893b2009, + 0x41152099, 0x34210868, 0x8b958426, 0x4c918610, 0x0d430759, 0x80012107, 0x12208382, 0x21060343, 0x0d436ba7, 0x4315200b, 0x80200b0c, 0x2408326f, + 0x19128012, 0x063e6f2b, 0x112b1229, 0x2b552b19, 0x4300ff2b, 0x8f47090f, 0x05e66107, 0x0e9b5318, 0x35271327, 0x01171533, 0x0b505000, 0x4d3b2126, + 0x4f2a5b1a, 0x2511e449, 0x745bc7fe, 0xb24c4f62, 0x00022505, 0x1800eb01, 0x2606ad45, 0x01000043, 0x50352335, 0x545811e6, 0x7523200b, 0x33260e6f, + 0x33130606, 0x51782315, 0x01332606, 0x2b132b80, 0x22878b17, 0x61800505, 0x8820068e, 0x2a06a965, 0x0d3b2558, 0xb03b0dda, 0x822a2b2b, 0x40012502, + 0x0909582b, 0x220bbb50, 0x180f2011, 0x21082c57, 0x3c850e12, 0x202aca28, 0x35012a20, 0x32822a2b, 0x20081965, 0x25ba82c0, 0x00430031, 0x4c182500, + 0xee4d0762, 0x26342906, 0x33352323, 0x37161632, 0x2007e171, 0x08ff5333, 0x21152126, 0x07363632, 0x16250683, 0x23061415, 0x200d8215, 0x24268235, + 0x1d113501, 0x33028212, 0x09080d2b, 0xca090d0d, 0x111d12ca, 0x14221460, 0x2b142215, 0xfe238585, 0x822001e0, 0xfe0a2410, 0x836001a0, 0x220b8295, + 0x42952214, 0x95580572, 0x112a2305, 0x2f82ce1d, 0x15221422, 0x2a29ea85, 0x2a4c2214, 0x120e0d13, 0x8212822b, 0x0828612e, 0x1600ab25, 0x5e002500, + 0x15200553, 0x44098b5c, 0x07240762, 0x37173727, 0x362c0383, 0x06161716, 0xa6feaf01, 0x19111911, 0x20080282, 0x11560111, 0xbd451619, 0x331b1423, + 0x34561e34, 0x02020f08, 0x19ab0108, 0x12195512, 0x12551912, 0x05bc7919, 0x3d32c732, 0x590d1506, 0x020e5008, 0x0e090808, 0x6b000400, 0x220a225d, + 0x821b0017, 0x2227217a, 0x2005206c, 0x05d64433, 0x11230328, 0x15330733, 0xa5181723, 0x15251333, 0xea018080, 0x079a6301, 0x12800137, 0x0196fe18, + 0x20205500, 0x00010020, 0x012b0080, 0x00d5017b, 0x20548305, 0x2db78207, 0xd5267b01, 0x01af26d5, 0xd5d525b0, 0x7c82b025, 0x2607bb42, 0x0022000e, + 0x82420036, 0x06222427, 0x44151506, 0x342305d5, 0x42272626, 0x7a520ece, 0x021e2609, 0x020e1415, 0x08bc4103, 0x0126222c, 0x161b0a00, 0x16203620, + 0x65420a1b, 0x3a4e2608, 0x4d3b2121, 0x077f522c, 0x43220786, 0x22680d13, 0x4b013005, 0x620a0d07, 0x0a626060, 0x218a070d, 0x842c4e3a, 0x25308238, + 0x213b4d2c, 0x895280fe, 0x21078707, 0xbc412001, 0x47132005, 0xc0220829, 0x0b820300, 0x1f001728, 0x27002300, 0xbf822b00, 0x33072323, 0x058e7707, + 0x0c714718, 0x17333726, 0x07232723, 0x15221d82, 0x1f833723, 0x01270382, 0x2c150201, 0x182b2bd6, 0x380bd36a, 0x19381a16, 0x1a0e3c0e, 0x562b2b25, + 0x80552a2a, 0x3e7a0180, 0x23956aa7, 0xdc71183a, 0x95d52509, 0x6a6b2626, 0x9b5c0083, 0x000f220a, 0x2880821b, 0x003f0033, 0x0057004b, 0x0a9f6f62, + 0x20063942, 0x0a656903, 0x0bf84718, 0xa30bfe5b, 0x23372217, 0x65481835, 0xab012407, 0x7411aafe, 0x19210606, 0x07d758fc, 0x37200786, 0x22210f9e, + 0x053963d6, 0x240a624d, 0xfe191156, 0x056343ab, 0x400d0822, 0x153608ac, 0x1d1d301e, 0x02001e30, 0x2b009500, 0xd5016b01, 0x1f001300, 0x074c0000, + 0x0dce4205, 0x91440720, 0x33152b08, 0x562a5501, 0x0d0d092a, 0x0482aa09, 0x2a2b1e23, 0x2702822b, 0x2a2aab01, 0xabfe090d, 0x0125bf83, 0xd60d0955, + 0x2016822a, 0x0aa0462b, 0x28001e26, 0x3c003200, 0x35285d82, 0x23262634, 0x07062223, 0x06230685, 0x82061515, 0x35332103, 0x21050667, 0x78563327, + 0x36342205, 0x229f1807, 0x35072108, 0x21200a82, 0x013f1783, 0x121d11c0, 0x08160d55, 0x550d1608, 0x0a111d12, 0x56012a0b, 0x559f0b2a, 0x0d800c09, + 0x82090cb7, 0x16802479, 0x8201090d, 0x1a01229e, 0x2320823b, 0x09070709, 0x3b2d3282, 0x800e1809, 0x0e802a2a, 0x090d5a18, 0x201d822a, 0x28ba8216, + 0x2b6b2a09, 0x080d0d08, 0x0abc4a2b, 0x29000f23, 0x8b921800, 0x03230812, 0x37272622, 0x35371716, 0x27372707, 0x15331733, 0x36171523, 0x06173736, + 0x27063706, 0x33160707, 0x41353732, 0xbc3f0cd8, 0x161e4d2a, 0x21120d0b, 0x4e152015, 0x12167825, 0x16060c06, 0x390f4d1e, 0x2401113a, 0x41242728, + 0x20200fc0, 0x08382d82, 0x1515551f, 0x16401125, 0x0a041f35, 0x201e1605, 0x1e151550, 0x01111101, 0x290af243, 0x000e0003, 0x0034001e, 0x83821300, + 0x2223172b, 0x15311506, 0x26343533, 0x0e777837, 0x35230329, 0x35231523, 0x49373634, 0x152d07c9, 0xc0151616, 0x9b8e8080, 0x0bc00b08, 0x0a834256, + 0xc0203c37, 0x190e1220, 0x19126a12, 0x4b01120e, 0x080b202b, 0x0b081818, 0x0c8c78d5, 0x2020c02f, 0x051a1058, 0x19191224, 0x1a052412, 0x0aa15310, + 0x0d00092b, 0x21001100, 0x00003c00, 0x05825501, 0x26343523, 0x06ad4327, 0x1720979f, 0x8305664a, 0x60012d9c, 0xea0c09c0, 0x5555ce0c, 0x9b555575, + 0x273ea08a, 0x0720ea20, 0x48111907, 0x0b0a0a0b, 0x07191148, 0x0d000107, 0x08161608, 0x2b2b4b0d, 0xa78fb52b, 0x120b5225, 0x82123408, 0x12193125, + 0x0b120834, 0x40000400, 0x80012b00, 0x1d00d501, 0x2d29a582, 0x00003100, 0x35231325, 0x052f5623, 0x33161424, 0x194c1733, 0x33332105, 0x2305304c, + 0x17333527, 0x290be043, 0x33272337, 0x55285801, 0xfd836a56, 0x120e2f2c, 0xaa121916, 0xff161912, 0x52180d1c, 0x283f0771, 0xbd9c1d62, 0x15150301, + 0x12551219, 0x2b0e5819, 0x19111619, 0x19161119, 0x5555912b, 0x43090cd5, 0x6a2105d6, 0x0c8557c0, 0x90821120, 0x06010024, 0xab791415, 0x34352105, + 0x47053063, 0x152f07fa, 0xab000133, 0x223d301c, 0x1c303d22, 0x4380806b, 0xd52f0668, 0x41286a91, 0x2e18182e, 0xc46a2841, 0x832b402b, 0x06002b16, + 0x40002b00, 0xeb01d501, 0x09821f00, 0x4500372d, 0x4b004800, 0x23010000, 0x6e353337, 0x23211754, 0x464b1822, 0x0b506e0c, 0x23271323, 0x05dd7e15, + 0x3733153a, 0x07172727, 0x01350717, 0xc316d940, 0x03110acb, 0x15090c2c, 0x00010d09, 0x40230684, 0x45b51912, 0xb32006de, 0x7d2d0786, 0x0f310b3c, + 0x310f3b3b, 0x042e3c0b, 0x29008214, 0x2a402b01, 0xab80090c, 0xb5410d08, 0x080d2405, 0x486e19ab, 0x32860502, 0x120e0d38, 0x513d0301, 0x3c3c0f31, + 0x3d51310f, 0x1414422e, 0x00281448, 0x02500001, 0x56cb8307, 0x15240991, 0x33331614, 0x0881a018, 0x4a262621, 0x7b4205d9, 0x085c4a05, 0x2f843320, + 0x2009ed5d, 0x05f64d16, 0x35290582, 0x0dab0135, 0x0d092a09, 0x238f8215, 0x19121219, 0x2105837a, 0x10820816, 0x01211694, 0x821b8295, 0x09552b2b, + 0x1911960c, 0x17d61119, 0x02821727, 0x090c9623, 0x29189855, 0x2b000700, 0xd5015500, 0x3471ab01, 0x10f8660e, 0x200bf94d, 0x0a054e01, 0x240c4f44, + 0x5656effe, 0x21028480, 0x068400ff, 0x01230c82, 0x7c1219ab, 0x9621094c, 0x2100836b, 0x068400ff, 0x92050021, 0x2d79907d, 0x2b113307, 0x23331102, + 0x21231133, 0x7b181123, 0x012108bb, 0x2ae48256, 0x2a3636a7, 0x36963636, 0x82560136, 0x24698c03, 0x0100ff2b, 0x36038300, 0x55000200, 0xab014000, + 0x0400c001, 0x00001800, 0x21110701, 0x4e270711, 0x152e0f43, 0xab000137, 0x2a565601, 0x0955090d, 0x04820c0c, 0x012a0d24, 0x418380c0, 0x15179724, + 0x16860d09, 0x8a161521, 0x0013254f, 0x2500001f, 0x2107766a, 0x9b431614, 0x35172305, 0x63822707, 0x3521352e, 0x33151737, 0x0d800135, 0x0d085608, + 0x2b220484, 0x6382802b, 0x80d5fe25, 0x86eb2b80, 0x080d2612, 0x17581716, 0x256882eb, 0x6060c02b, 0xa4822b16, 0xfdff0027, 0x03020002, 0x225e8300, + 0x82430031, 0x272324b2, 0x67230723, 0xff630db1, 0x0323080b, 0x031e3517, 0x023a3017, 0x13042e31, 0x3027032e, 0x1e31022a, 0x01273704, 0x56151555, + 0x19121515, 0x82aa1219, 0x82672004, 0x82122003, 0x5f5b2f03, 0x20344226, 0x0d110d03, 0x52432a04, 0x0d8c075a, 0x015f2c25, 0x7b15156b, 0x122405d1, + 0x96191280, 0x2f07e15e, 0x3e5f2001, 0x42342003, 0x3d533325, 0x29fe0723, 0x0e2b0b89, 0x0002005f, 0x01400015, 0x82c001eb, 0x003d23b4, 0xf7821300, + 0x37363422, 0x25074447, 0x16151506, 0xbf832516, 0x12822120, 0x1622c886, 0xad591533, 0x21352105, 0x12510887, 0xd6953206, 0x1d121c24, 0x1d11d611, + 0x01241c12, 0xfe19122b, 0x828483d6, 0x090d2912, 0x00010d08, 0x0d09080d, 0x19281b82, 0x2a2a1501, 0x18082d1e, 0x2705064e, 0x0d2d0818, 0x55551219, + 0x1221e082, 0x4212826a, 0x058505f4, 0x6a262d82, 0x04001912, 0xa5826b00, 0xa5829520, 0x475a2120, 0x01002106, 0x20054d45, 0x5b948623, 0x951808a0, + 0x352108c4, 0x240a8227, 0x33352315, 0x24038227, 0x19116b01, 0x82988219, 0x16163504, 0xd62a1911, 0x1611192a, 0xd6d6d6c0, 0x01565640, 0x4011192b, + 0x40307c83, 0x192b1911, 0x40409512, 0x2b191295, 0xaa40402a, 0x5007bd4c, 0x1324055f, 0x3d002800, 0x3711df76, 0x22303503, 0x27262231, 0x37362626, + 0x17160617, 0x35371616, 0x36273717, 0x23201183, 0x15241a82, 0x36153727, 0x06201683, 0x3310d857, 0x2814012b, 0x060f1210, 0x060b170e, 0x0f1c0b12, + 0x0c181c3c, 0x0e240883, 0x153d3d01, 0x0f4e1984, 0x2b963112, 0x2f12100f, 0x15181530, 0x0b0b1231, 0x1e3c2d01, 0x2e250985, 0x012b3c3c, 0x241a8310, + 0x55000400, 0x05775500, 0x1c001826, 0x29002500, 0x2122b582, 0xae620622, 0x023e2406, 0x4d333535, 0x07250646, 0x05352315, 0x080e8223, 0x1415163a, + 0x15210506, 0xfe8b0121, 0x161912f5, 0x201f3428, 0x0b182b37, 0x14142214, 0x01d54a22, 0x0d0b0b0b, 0xbdfe1313, 0xaafe5601, 0x1219c001, 0x2c371f79, + 0x17010119, 0x161f3729, 0x2006754d, 0x25008240, 0x130d0e12, 0xfd572bea, 0x0021220a, 0x227b822d, 0x48353335, 0x352d0840, 0x35363623, 0x14152335, + 0x11231716, 0x20068233, 0x618b8233, 0x20080bef, 0xfe2b8001, 0x191912d5, 0x562b0112, 0x17d51813, 0x0c2b5614, 0x0d08ab09, 0x09090c80, 0x09090d0d, + 0x2020820c, 0x0595472a, 0x2c0f2a2e, 0x1b6a6a1b, 0x56010f2c, 0x0c0c092b, 0x2907de4a, 0x40000a00, 0xab012b00, 0x1c45d501, 0x0028260c, 0x0033002c, + 0x0a9a5e3a, 0x240a4c4d, 0x15333505, 0x06504d27, 0x0b822720, 0x26221526, 0x23173335, 0x312f0382, 0x14313335, 0x15310306, 0x36343123, 0x83c08001, + 0x2304859a, 0x2bc0fec0, 0x95320082, 0x2b952b2b, 0x4a2b1912, 0x2b6b2a2a, 0x192bc719, 0x5118d501, 0xfe310b63, 0xeb0001d6, 0x2a752b2b, 0x2b4a2ab6, + 0x11194a2b, 0x2300822a, 0x55011911, 0x1a4a3382, 0x00ab2608, 0x00140010, 0x06a7411a, 0x16141135, 0x23353333, 0x34352135, 0x35210726, 0x07270321, + 0x45273717, 0x6b2307b1, 0x8380016b, 0x560127ff, 0x5b1e3d6c, 0xa8451e96, 0x802b2d07, 0x56191280, 0x3ce7fe2b, 0x1f965a1e, 0x2008cc7b, 0x205a82d4, + 0x3158822b, 0x15021e15, 0x17070614, 0x34353636, 0x2203022e, 0x1862022e, 0x030e2105, 0x08052248, 0x27373652, 0x15010606, 0x05223a24, 0x09093805, + 0x3e46341d, 0x1729361f, 0x29243a22, 0x211d3446, 0x352c4e3a, 0x14381d5a, 0x40d4013d, 0x263f2906, 0x210c1c0e, 0x29172c14, 0xfe24394a, 0x3629179b, + 0x293f261f, 0x24044006, 0x2c2a4939, 0x2f213b4d, 0x1e1a2128, 0xd42ade88, 0x1c000b00, 0x00003700, 0x89601513, 0xa4352009, 0x40eb2591, 0x40402a40, + 0x552095a1, 0x2a222683, 0x9cb17f40, 0x0f00d526, 0x45003200, 0x4d0a7b41, 0x0728069e, 0x15070614, 0x26263523, 0x2108c065, 0xdb4e3533, 0x87152005, + 0x23172108, 0x27202082, 0x7f4d2182, 0x06142107, 0x080c5847, 0x0d13d120, 0x06120e20, 0x10060504, 0x06040506, 0x04040710, 0x20016107, 0x0f141002, + 0x190e0f18, 0xa94b140e, 0x0fb12f0d, 0x90900416, 0x510f1604, 0x05060605, 0x05893535, 0x88822f08, 0x25070188, 0x14201517, 0x17142114, 0x00030025, + 0x01150029, 0x00eb01d6, 0x00390014, 0x2500003e, 0x06062722, 0x23062726, 0x32331523, 0x02821637, 0x35333325, 0x18323325, 0x27079988, 0x33331616, + 0x27263637, 0x4a05546d, 0x0739079f, 0x37170606, 0x07271521, 0x292dab01, 0x1a3b3b1a, 0x2a2a2d29, 0x5a282a2c, 0x08088228, 0x017ffe36, 0x0f102c1a, + 0x2c1a1a2c, 0x1a2c100f, 0x05022801, 0x12191b0b, 0x12408040, 0x070a1b19, 0x00015403, 0x1c408080, 0x120c0c12, 0x14152b1c, 0x2b2b1514, 0x18121218, + 0x8e340383, 0x09031206, 0x40191263, 0x63121940, 0x07110309, 0x2a2a5587, 0x33069744, 0x00d501ab, 0x00300024, 0x0040003c, 0x0e220100, 0x14151502, + 0x11c46118, 0x35353623, 0x22038236, 0x4f022e34, 0x97780b25, 0x3521280c, 0x20000121, 0x181d313d, 0x200ac861, 0x230b8209, 0x6e3e2f1b, 0x300ec452, + 0x0100ff28, 0x06d50100, 0xcb1c2211, 0x2c0a1b0f, 0x082c4a08, 0x1b0a2c2a, 0x221ccb0f, 0xd6fe0611, 0x210f344a, 0x59704080, 0x4f952008, 0x372006ca, + 0x584eb182, 0x07072105, 0x2abc9118, 0x33372724, 0x91180117, 0xe02015b6, 0x2105f550, 0x0786b313, 0xdc16f127, 0x09800116, 0x0ed24a0c, 0x9c915520, + 0x03004023, 0x05204900, 0x1800d526, 0x28002400, 0x26094d41, 0x15073316, 0x47273521, 0x41410596, 0x4137200d, 0x15260835, 0x01201521, 0x06822000, + 0x3e2f1b23, 0x207e8623, 0x0a284173, 0x14221426, 0x16151516, 0x20410682, 0x4080230e, 0x7a8e0500, 0x5f183420, 0x15220867, 0x7e9b1614, 0x33352322, + 0x210dfd4c, 0xc4413335, 0x418e8c05, 0x282307bf, 0x4b606b6b, 0x0a8206c5, 0x9a06c041, 0x41c02097, 0xa2400726, 0x09b55ca5, 0x1d001324, 0x5c482700, + 0x34073111, 0x3233023e, 0x17260717, 0x16372722, 0x020e1415, 0x29104448, 0x3e2f1bd7, 0xef2f3a23, 0x0483ab25, 0x33480c82, 0x23d52811, 0x251b2f3e, + 0x82712fef, 0x833a2003, 0x0898450b, 0x18059351, 0x4612b0a3, 0x372a061f, 0x37060617, 0x33363627, 0x15761e32, 0x06926005, 0x07872c20, 0x13254d83, + 0x3516f011, 0x20038269, 0x910d841e, 0x05b5537f, 0x16351e26, 0x421311f0, 0xa4820382, 0x351e2322, 0x220c6b5f, 0x8223001f, 0x231521fd, 0x25069e46, + 0x07062223, 0xbb602517, 0x32332d06, 0x37173736, 0x17331701, 0x196b0123, 0x096f5218, 0xf7fe9d22, 0x0c645218, 0x19597827, 0x1501442b, 0xbd52182a, + 0x919d2109, 0x240a725f, 0xaf88011e, 0x0816472a, 0x1720f983, 0x20117041, 0xe3421817, 0xd63f2213, 0x21d491d6, 0x38512aea, 0x0013260a, 0x00370027, + 0x554f913b, 0x9318101c, 0x6f940e76, 0x540f1b55, 0x22240967, 0x80801c3a, 0x16558b91, 0x542b2012, 0x95200b9e, 0xed4ef783, 0x000d2607, 0x25000011, + 0x06fd4c11, 0x15231125, 0x83273521, 0x199537f5, 0x1911d611, 0xd580012b, 0x016b2b2b, 0x1919122a, 0x2bd6fe12, 0x3bac802b, 0x3b8f8020, 0x654f0320, + 0x00112408, 0x87190015, 0x23112679, 0x06222311, 0x207d8815, 0x30818317, 0x701219ab, 0x19127020, 0xeb800115, 0x2a802a2a, 0x2386842a, 0x5501abfe, + 0x2a218a87, 0x08f4442a, 0x0400c027, 0x20000b00, 0x06174e00, 0x35262226, 0x37061433, 0x2005af67, 0x07a74737, 0x15161638, 0x00013315, 0xab5601ab, + 0x0c2a0c09, 0x1915aa4c, 0x07070917, 0x63821709, 0x3e05234e, 0x09090cb5, 0x3215200c, 0x06052519, 0x060a0a06, 0x19250506, 0x00020032, 0x0155006b, + 0x82c00195, 0x000a2d6e, 0x35213700, 0x35232521, 0x17231523, 0xfe2d9282, 0x552a01d6, 0x55955580, 0x8080c02b, 0x202b8295, 0x262b8253, 0x00ab01ad, + 0x82090005, 0x0727328e, 0x07170727, 0x01211521, 0x5ac41ead, 0x0160781e, 0x2031822a, 0x210b838d, 0x0d542a79, 0x0013240b, 0x421e001a, 0x07261132, + 0x33153335, 0x19422707, 0x2a412514, 0xc0555540, 0x3c138e42, 0x565555aa, 0x002b9656, 0x002b0006, 0x01d4012c, 0x000700d4, 0x0017000f, 0x0026001f, + 0x2864823a, 0x15272626, 0x17171616, 0x2c088233, 0x07161607, 0x37363617, 0x07060623, 0x23078215, 0x27060627, 0x4408dc84, 0x2e150737, 0x3e343503, + 0x0e153702, 0x16141502, 0x18870116, 0x2a18203a, 0x032b4012, 0x0d1e1319, 0x131e1f12, 0x032b0319, 0x3a207f12, 0x2a111f18, 0x6b562a18, 0x4629806b, + 0x341d1d34, 0x442a2946, 0x01442828, 0x212185a5, 0x2282720d, 0x2a121e2a, 0x39181e96, 0x522a1720, 0xa6214086, 0x2600826b, 0x24042ba9, 0x642a4939, + 0x05320538, 0x2c2c4830, 0x01003048, 0x9500ab00, 0x6b015501, 0xae820b00, 0x33238e82, 0x83352335, 0x55012e03, 0x8080aaaa, 0x2b400180, 0x2a2b2bd6, + 0x2c28822b, 0x013f0040, 0x00c101c0, 0x13000043, 0x055d5326, 0x31331622, 0x2105ed46, 0x09823636, 0x15161625, 0x82222315, 0x820620dd, 0x361629f2, + 0x34353536, 0x31232626, 0x15241182, 0x06061415, 0x26380982, 0x33353526, 0x37363632, 0x84262636, 0x1d121f13, 0x311d1e30, 0x111d121c, 0x11280282, + 0x01131e12, 0x121c0f01, 0x7b821796, 0x13201223, 0x05de56d1, 0xc44eaa20, 0x0f952305, 0x3684121b, 0x11241994, 0x0200131f, 0x22084f70, 0x57570013, + 0x46480a06, 0x26342208, 0x21a08627, 0x9d822223, 0x9e821620, 0xc682b682, 0x1c301526, 0x16143104, 0x4a066252, 0x8b720681, 0x2a248306, 0x31043c30, + 0x01262634, 0x502b15c0, 0xe63a08ef, 0x18132114, 0x05171110, 0x19191205, 0x13191112, 0x20141421, 0x11111714, 0x11840617, 0x14191232, 0x156b0120, + 0xc0090d15, 0x080d0d08, 0x150d09c0, 0x70282282, 0x11171711, 0x11190164, 0x14243483, 0x14202421, 0x17974682, 0x00060029, 0x022b0000, 0x18d50100, + 0x29085940, 0x0023001f, 0x15331300, 0x03822723, 0x07862520, 0xda770320, 0x3523250f, 0x2b2b4033, 0x01210282, 0x210684d5, 0xe850aa40, 0xaa122807, + 0x966b01aa, 0x82d69656, 0x40012103, 0x2805e44d, 0x56011119, 0xc0fe1911, 0x0ca756d6, 0x17000724, 0x6b851b00, 0x63936783, 0x2a2a2b27, 0x2a2a8001, + 0x915d9056, 0x00033359, 0x012b0055, 0x00eb01c0, 0x00160011, 0x25000022, 0x456d3523, 0x36172c08, 0x07273435, 0x07273733, 0x82262737, 0x073a08cb, + 0x36371707, 0x6a2a0134, 0x0e1c0e78, 0x1c303d22, 0xb60aabab, 0x832d832d, 0x08070fcf, 0x0f040903, 0xeb06102d, 0x05047869, 0x28412e18, 0x6a91916a, + 0x844d1c20, 0x0f92832d, 0x1b820307, 0x12060f22, 0x2830c882, 0xd5012800, 0x0c00d501, 0x35002500, 0x00004400, 0x250b0c71, 0x36323735, 0x6a181637, + 0x35230791, 0x83022e34, 0x16172275, 0x0e104716, 0x06060132, 0x022e2223, 0x35343435, 0xa5373636, 0x100b0b10, 0xd0390383, 0x030c170c, 0x20080904, + 0x3b210e0d, 0x351c2c4d, 0x37187117, 0x152fd0fe, 0x360e8317, 0x2f1b4225, 0x0178fe1e, 0x1c32151c, 0x1b2f3e23, 0xeb102717, 0x840f0f0b, 0x02403a3b, + 0x0c180c03, 0x1f112414, 0x2c1c3517, 0x0e213b4d, 0x0f0e720d, 0x421b2f86, 0x330d8325, 0x1e2f1517, 0xa7fe8901, 0x2f1b1110, 0x0101233e, 0x111a0801, + 0x0a8a5c18, 0x45000d21, 0x1c2005e1, 0x290a614f, 0x35363221, 0x15332535, 0xcb431723, 0x27332705, 0x55011735, 0x431812ea, 0x6b220852, 0x0083d66b, + 0x7b552b21, 0xea29097c, 0x2bab2b16, 0x552b2a2b, 0x06214855, 0xd501c426, 0x09000400, 0x32085e82, 0x21350100, 0x37171715, 0x25172335, 0x33151707, + 0x01371735, 0x2700ff80, 0x83ae2bae, 0x8d1ee7fe, 0x011e51aa, 0x27194095, 0x84164080, 0xee8d1edd, 0x821e5043, 0x00802443, 0x8280012b, 0x00032c43, + 0x0017000b, 0x15211300, 0x83151521, 0x3537213d, 0x280b8c53, 0xff000180, 0x2baa2b00, 0x060a4b80, 0x40d50129, 0xea40162a, 0x181640ea, 0x82082660, + 0x0745474c, 0x19001027, 0x00003c00, 0x08234e01, 0x2506014e, 0x35331137, 0xc85e3533, 0x76152005, 0x57780b28, 0x52b78209, 0x012605bc, 0x2b121855, + 0x75441813, 0x2a162b05, 0xd726122b, 0x09120907, 0x04820606, 0x06072508, 0x2a121909, 0x01091912, 0x0a2c1c69, 0x2c0ad7d7, 0x1827181c, 0xfe3f2718, + 0x1280ab80, 0x06091b28, 0x09064646, 0x712d0587, 0xd5d51912, 0x06711219, 0x00070009, 0x20ef824a, 0x0a9543b5, 0x2b431320, 0x28f78206, 0x23153313, + 0x07173717, 0x24078207, 0x27371737, 0x820b8325, 0x016b2c03, 0x80d6fe2a, 0x26862a2a, 0x85a4261e, 0xbcfe3506, 0x271e261e, 0x01261e27, 0x15018040, + 0x1e271e40, 0x5b40ee27, 0xdc201f82, 0xdc231782, 0x58261f27, 0x15210e6d, 0x05cc4d00, 0x50171421, 0xf0410560, 0x00012106, 0x24052243, 0x0d3d301c, + 0x2100822a, 0x1643d501, 0x41282807, 0xebfe182e, 0x6a6b2a2b, 0x19200c2d, 0xa041468d, 0x244a8a0b, 0x19191222, 0x8d038212, 0x18d5204d, 0x2208d764, + 0x46950001, 0x1620064c, 0x27183363, 0x6b2b0001, 0x6b111995, 0x12234682, 0x6319116b, 0x00240e09, 0x002b0005, 0x2405f853, 0x0017000b, 0x200d821b, + 0xc14c1855, 0x07372219, 0x7a891833, 0x06ef7211, 0x56233521, 0x363008b2, 0x37363736, 0x36313630, 0x30333136, 0x31161716, 0x16240382, 0x2b011517, + 0x10f74918, 0xb80e0724, 0xa55a5d0e, 0x0709250b, 0xd609070a, 0x0d2a0584, 0x03010410, 0xb60e0601, 0x0782060e, 0x0d100423, 0xf14918eb, 0x2b7e230e, + 0x3c45752b, 0x08b2260c, 0x19080a0a, 0x31058319, 0x0a32288a, 0x09010405, 0x01090303, 0x320a0504, 0x7e418a28, 0x985f1810, 0x71072009, 0x012d0a47, + 0x2e1aab00, 0x3e25253e, 0x1e601a2e, 0x05797f2d, 0x012f0582, 0x288240d5, 0x092c3f4c, 0x4c3f2c09, 0x8ac28228, 0x21588c1a, 0x86180013, 0x27240c8c, + 0x17371737, 0xc225528a, 0x5b2d1e4b, 0x254c8e1e, 0x2d1e4ce1, 0x67421e5a, 0x42a18a12, 0x9d880866, 0x66429620, 0x22968c05, 0x422b2aea, 0x55280566, + 0xab01ab01, 0x1f001b00, 0x35208e82, 0x200b916a, 0x09956a23, 0x07201782, 0x01235682, 0x822a56ab, 0x56562101, 0x2a240685, 0x2b015656, 0x0e860482, + 0x56210683, 0x0a254256, 0x2f002b24, 0x044c3300, 0x75598906, 0xc76b0689, 0x15332305, 0x03883533, 0x2406dd48, 0x23153321, 0x87158315, 0x40d521c8, + 0x2a217583, 0x88008440, 0x00ff210a, 0x80208782, 0x56220382, 0x1b8f6b01, 0x31844020, 0x1d835620, 0x4c562a21, 0xe5a50ae0, 0x2b95d525, 0x82952b2a, + 0x24068400, 0x012a2a2b, 0x200e8915, 0x221c8295, 0x43002a2a, 0x6b20054e, 0x20069b49, 0x85d48223, 0x012325c8, 0x2b2b8040, 0x01260282, 0x56d65615, + 0x7c82d656, 0x95005524, 0x2884d501, 0xe4481720, 0x202a8606, 0x0aa26617, 0x85000121, 0x2ad52236, 0x8200822b, 0x213d8471, 0x82822b56, 0x240b204b, + 0x00170003, 0x2145831f, 0x74623307, 0x27132d0f, 0x37230723, 0x01011733, 0x23462202, 0x2b0e954e, 0x165f1418, 0x582a5828, 0xe2615401, 0x830baa64, + 0xc0fe2626, 0xebeb3c3c, 0x1d941800, 0x00093609, 0x001c000d, 0x002c0020, 0x003c0038, 0x0054004c, 0x15233700, 0x05a14533, 0x35230723, 0x240d8333, + 0x33173335, 0x05474a27, 0x05201283, 0x200a0241, 0x06e24105, 0x3521e682, 0x20a88201, 0x0fe14d27, 0xd53aa986, 0x130d4a4a, 0x2a2a0d13, 0x18204b8b, + 0x08132013, 0x2b0d130b, 0x2bebfe2b, 0x02822020, 0x208a012c, 0x2b202a2a, 0x2c15fffe, 0xba4d0115, 0x0926080a, 0x1a0e3c0e, 0xab381a39, 0x400d1380, + 0x4060140c, 0x2a2a8020, 0x0910052c, 0x36140c16, 0x802b0b16, 0x36803535, 0x3c832b2b, 0x3e1a0126, 0x3a22463e, 0x092f9418, 0x2727c024, 0xe9889696, + 0x0e00d828, 0x1e001200, 0xe9842800, 0x5000452b, 0x00005600, 0x26343525, 0x86ed8223, 0x822720df, 0x20db8bee, 0x0c084133, 0xa5610520, 0x3627370b, + 0x2707031e, 0x27022e36, 0x1e061707, 0x37173703, 0x2e061727, 0xa7820102, 0x2020df87, 0x8a20de89, 0x0120fc87, 0x2008ab85, 0x21eafe2b, 0x21343f21, + 0x07211005, 0x7b2b1f0d, 0x0510241e, 0x213f3421, 0x68cb1f23, 0x0d1f2b18, 0x87de8275, 0x87e485e8, 0x2a3622ff, 0x2357822a, 0x0f223201, 0x22213084, + 0x232d8217, 0x20241e20, 0x062b4c82, 0x8e1e2310, 0x200c0668, 0x4a08002a, 0xf48b089a, 0x58004822, 0x3224f2bb, 0x14151616, 0x09fe6f18, 0xe8413720, + 0x24faa70e, 0x261800ff, 0x05145e17, 0xeb410582, 0x26f4a00a, 0x18271736, 0x82172717, 0x27182302, 0xea412a17, 0x0700210b, 0x2008ad46, 0x2a0b8203, + 0x002a001b, 0x00420036, 0x6400004c, 0x404307d8, 0x1403250f, 0x23170706, 0x08c99618, 0x2506b144, 0x35331533, 0xe7411733, 0x1435220a, 0x059c6706, + 0x2bb51527, 0x2020802b, 0x0e6a4335, 0x080b2c22, 0x09bc9618, 0x2b202025, 0x84207520, 0x0d132a00, 0x130d4040, 0x40ab16cb, 0x108143b5, 0x1009e030, + 0x2a2a2c05, 0x350c1480, 0x2b803535, 0x3184d52b, 0x130d5525, 0x5f0d1380, 0x23200a95, 0x2109cf54, 0x9f823333, 0x51183420, 0x343d0e76, 0x0001022e, + 0x1e354528, 0x55551219, 0x1f362917, 0x1729361f, 0x19125555, 0x0145351e, 0x250482c0, 0x19129528, 0x511815ab, 0x15240721, 0x951219ab, 0x894d2e83, + 0x4d33200c, 0x25201589, 0x2005894d, 0x25788516, 0x32333636, 0x51181616, 0x6b4d08ef, 0xe2fe340f, 0x19223a24, 0x1a352b11, 0x2c1a1b2b, 0x122b361a, + 0x4d3a2319, 0x23220e5c, 0x9982233a, 0x82156b21, 0x2102821f, 0xb3826b15, 0x21471282, 0x000b290a, 0x37000019, 0x35333523, 0x2105f771, 0xe4461323, + 0x35e02309, 0x02824035, 0xe2462020, 0x83eb2008, 0x0136220e, 0x0ce34620, 0x00040034, 0x01c00040, 0x004001c0, 0x0023000b, 0x0036002a, 0xa8441300, + 0x0ff05e0c, 0x82152321, 0x0715296f, 0x33172327, 0x15232337, 0x2507704f, 0x15753533, 0x02822020, 0x0d4b0138, 0x0c092b08, 0x082b090c, 0x1515200d, + 0x15201070, 0x95201536, 0x00822a4a, 0x2b150128, 0x80353580, 0x0e5f162b, 0x400b2709, 0x8060350b, 0x3a828080, 0x4b200b21, 0xc42908bb, 0x0f000500, + 0x00001400, 0x087e8201, 0x01012135, 0x14111707, 0x17213316, 0x17372537, 0xc0011737, 0xe7fe1219, 0x7cfe4401, 0x1219221e, 0x1e221901, 0x3040bcfe, + 0x95012d11, 0xbcfe1912, 0x221e4801, 0x8212e7fe, 0x56592415, 0x542d1740, 0x1b220c31, 0xdf823300, 0x23540720, 0xef82180c, 0x5403200a, 0x821809b5, + 0x3c200ae5, 0x2c0ba673, 0x3e23c41e, 0x0b0d1b2f, 0x6f2b14ea, 0x08ab731f, 0x0d0b1f2a, 0x233e2f1b, 0xc4012b18, 0x210bb073, 0x1585191e, 0x0bea1426, + 0x1f3e010d, 0x2308b773, 0x182b1320, 0x002d4684, 0x00150002, 0x01eb016b, 0x00170095, 0x20ee8227, 0x09266d21, 0x35331522, 0x24081670, 0x23061417, + 0x069a6f21, 0x16322130, 0xfe950115, 0x172718d6, 0x2a182717, 0x08842ad6, 0x12191324, 0x224dd6fe, 0x95012a07, 0x6b182617, 0x15172717, 0x26048215, + 0x1726186b, 0x4a1911c0, 0x002106b5, 0x08a16d03, 0x25001724, 0x74822d00, 0xce5b2220, 0x33680806, 0x35023e32, 0x07042e30, 0x15031e32, 0x043e3421, + 0x26222317, 0x06062127, 0x49320001, 0x170c1d31, 0x801f3629, 0x1d2f3316, 0x2f1a0b02, 0x3f31354a, 0xfe051125, 0x150a02aa, 0x7a673b25, 0x010c3622, + 0x01360d43, 0x28211495, 0x361f1028, 0x24111729, 0x22162739, 0x2a152226, 0x181e1e14, 0x19100103, 0xd60f181a, 0x241c1c24, 0x0ea08b18, 0x6a5e2120, + 0x17162108, 0x09566518, 0x3a473520, 0x23032105, 0x079a5a18, 0xaafe2408, 0x090c1a10, 0x010a140d, 0x0d140a2a, 0x7b1a0c09, 0xfe6b8080, 0x015601aa, + 0x411119d5, 0xf106130b, 0x820b140b, 0x06f12d02, 0x11410b13, 0x2b00ff19, 0x0a00406b, 0x6206ab60, 0x79490ff3, 0x107f6205, 0x23150527, 0x1533023d, + 0x21068817, 0x0a863735, 0x15333523, 0x248a8235, 0x80fec001, 0x05617e12, 0xfe191937, 0x562a2ac3, 0xaa6a2b2b, 0x2b2b2b95, 0x012a2a2a, 0xfe1219ab, + 0x231e84eb, 0xab191215, 0x04821484, 0x80231a82, 0x84551616, 0x082e820e, 0x002a563d, 0x00350018, 0x01cb0135, 0x000b00cb, 0x00230017, 0x003b002f, + 0x00530047, 0x006b005f, 0x00830077, 0x009b008f, 0x00b300a7, 0x00cb00bf, 0x00e300d7, 0x01fb00ef, 0x01130107, 0x1800001f, 0x230ba55c, 0x15062207, + 0x22055661, 0x8a272634, 0x8b178b0b, 0x7c05202f, 0x27200a20, 0x4a180b8a, 0x3b8b0b46, 0x538a1720, 0x2f8a0320, 0x0cd24718, 0x2f8b238a, 0xa78b9b97, + 0x3b8b2f97, 0xd7a20320, 0x8020538b, 0x200eaf6a, 0x240f8609, 0x07070449, 0x20038204, 0x210f863c, 0x10863701, 0xd86d9120, 0x090d2905, 0x04060604, + 0xe6060605, 0x0f861787, 0x13820520, 0x0b830520, 0x0d0d0923, 0x5c2b8309, 0x9d200626, 0x70876896, 0x99205f87, 0x47863787, 0x3f865a20, 0x77860e20, + 0x71664d20, 0x0e122109, 0xeb201b82, 0x09226585, 0xe04d560d, 0x084b6b07, 0xa0840b20, 0x60208c82, 0x75201a87, 0x07146e18, 0x11874b20, 0xe5844a20, + 0xd520e982, 0x95201a87, 0x01211187, 0x2009876a, 0x202d874a, 0x23728476, 0x0a120e0d, 0x55207599, 0xb5202c87, 0x01226c99, 0x44821300, 0xb6204c83, + 0x60202d87, 0x56205a87, 0x08895e18, 0x51000221, 0x1c2f0709, 0x00002800, 0x15233501, 0x1415030e, 0x18333316, 0x270818ae, 0x34353632, 0x2307022e, + 0x2907b847, 0x242a1501, 0x191a2f3e, 0xfd484012, 0x12402705, 0x3e2f1a19, 0xbb479539, 0x7f012a07, 0x21044141, 0x12254233, 0x05e54819, 0x25121926, + 0xbb213342, 0x5407c147, 0x17260a00, 0x39002900, 0x77825300, 0x15062222, 0x65096551, 0x342507c9, 0x33150726, 0x05c86435, 0x83232321, 0x16162122, + 0x4f102b6a, 0x2684079e, 0x33363622, 0x2705e347, 0x01151616, 0x960c0960, 0x0631fa83, 0x0604d604, 0x1c56940c, 0x760d1314, 0x1c14130d, 0x0b914fd6, + 0xd6111931, 0x0c0e1911, 0x76111d12, 0x0c121d11, 0x6b0b010e, 0x0d3805fc, 0x06054a09, 0x094a0506, 0x0a0a160d, 0x16021e15, 0x0d13130d, 0xcb1e0216, + 0x290c924f, 0x191912d6, 0x180f4a12, 0x40561d07, 0x071d3705, 0x03000f18, 0xab005500, 0x5501c001, 0x0d000500, 0x00001900, 0xdc823337, 0x33173322, + 0x20055174, 0x0a155705, 0x6b408037, 0x2a2b402b, 0x0001802b, 0x40406b6b, 0xaa2ad540, 0x2a80802a, 0x2a06822a, 0x00162a16, 0x00150004, 0x880002ab, + 0x8f252049, 0x4717204b, 0x232109ed, 0x0a9a4d05, 0x57824020, 0x2b225682, 0x55839580, 0x016b4023, 0x05196a00, 0xaa215f86, 0x215d822a, 0xa94d402a, + 0x00043105, 0x0140002b, 0x00ab01d2, 0x0020000f, 0x00520046, 0x11ee7618, 0x23262237, 0x06070622, 0x33151506, 0x34352626, 0x26341736, 0x07273727, + 0x8f691826, 0x15142509, 0x07171414, 0x0c936918, 0xf6513620, 0x0677180b, 0x6420080c, 0x26040704, 0x0f0e1f48, 0x080f0cc5, 0x190101de, 0x0d0a1f16, + 0x0d062b06, 0x18151f0a, 0x15180101, 0x162b0e88, 0x50010119, 0x12191912, 0x18191911, 0x3c0c1977, 0x12150154, 0x39101e08, 0x11182c12, 0x07033120, + 0x0b251603, 0x1f1f0509, 0x250b0905, 0x300e8216, 0x15040604, 0x05080a25, 0x08052020, 0x0415250a, 0xd3451806, 0xb5631808, 0x00802a08, 0x00070003, + 0x002c001c, 0x27f28230, 0x15333523, 0x05331523, 0x0f309318, 0x07061424, 0x79182717, 0x05250e51, 0x95233533, 0x2500826a, 0x0d512201, 0x7a18101e, + 0x0922089b, 0x8c185108, 0xfe2f0c82, 0x01d5d5c0, 0x2b6b2b40, 0x0908516a, 0x851d311c, 0x1e102428, 0x428c520c, 0x1126052f, 0x1d12121d, 0x88822a99, + 0xc0671520, 0x00082406, 0x821a0016, 0x0664508e, 0x15372723, 0x09b47817, 0x83071121, 0x556b26a5, 0x962a956b, 0x3600822a, 0x2a2a5680, 0x80d51501, + 0x406bd580, 0x2a166b2a, 0x01552b2b, 0x182b8080, 0x260a2384, 0x000e0005, 0x822b0011, 0x2bde8450, 0x27071717, 0x33351737, 0x27370717, 0x0c820a82, + 0x0c4d2720, 0x32333b0b, 0x27351716, 0x5580c037, 0x901137b3, 0x490d3a11, 0x2b18183c, 0x120c551e, 0xaf4c540c, 0x27173f05, 0x09160b18, 0x7c011ea2, + 0x92195544, 0x11911137, 0x1849613b, 0x1ed31818, 0x0c130d55, 0xd84c4454, 0x05072408, 0x821ea225, 0x075f4488, 0x21001326, 0x27002400, 0x15238882, + 0x4d232626, 0x35230b74, 0x6c173533, 0xc026124b, 0x180b1609, 0x70821727, 0x55285382, 0x3b0d4980, 0x13484812, 0x37219282, 0x256f8205, 0xe1c00118, + 0x494d0705, 0x55d62908, 0x3b6149c9, 0x13474713, 0x37288e82, 0x5618184f, 0x03003018, 0x24086f68, 0x00130003, 0x237a821f, 0x17211521, 0x5d767b82, + 0x6d23200c, 0x802a094b, 0x00ff0001, 0x1911d6eb, 0x04831119, 0x40352723, 0x28028235, 0x152bc001, 0x12ea1219, 0x20048419, 0x081283c0, 0x0200352d, + 0x1e001e00, 0xc401c401, 0x11000600, 0x33010000, 0x15330727, 0x17072517, 0x37172315, 0x37173523, 0x55405501, 0xfe2a4055, 0x838d1ee7, 0x1ed12b08, + 0x55556b01, 0x1edd2b59, 0x0782848d, 0x181ed021, 0x080af044, 0x0e000421, 0x15370000, 0x37273733, 0x07222627, 0x36371707, 0xec504034, 0x06328e50, + 0x50270612, 0x82900627, 0x320c220c, 0x200b8406, 0x0838b912, 0x6000012e, 0xa0012b00, 0x1700d501, 0x22130000, 0x021e0706, 0x06061415, 0x33161607, + 0x35023e32, 0xcb022e34, 0x2018361d, 0x301b1b30, 0x1d361820, 0x2d06234e, 0x0d0fd501, 0x27473813, 0x13384727, 0x064e0f0d, 0x0a304a07, 0x5605355f, + 0xa66e0636, 0x079b6607, 0x2306ed4d, 0x37020e14, 0x230a744f, 0x16163233, 0x5f100261, 0x1d230f2f, 0x43121d11, 0x05820525, 0x20232d5f, 0x212d88ab, + 0xa0411d11, 0x0014220a, 0x39ee822d, 0x17323336, 0x26371716, 0x35272627, 0x07061523, 0x36170706, 0x06010727, 0x11822223, 0xc1550720, 0x335d0805, + 0x37363635, 0x37173736, 0x14130de1, 0x29040d0c, 0x18101608, 0x0a0c0d2a, 0xa4021f09, 0x0e07011e, 0x10101713, 0x1c0b2a07, 0x2a0b1409, 0x0a070e07, + 0x011e6209, 0x0a0b0b61, 0x1217110e, 0x2d2c040d, 0x08060503, 0x1e63021e, 0x0f0af9fe, 0x26111710, 0x02090714, 0x04012c2e, 0x61070403, 0x0a64591e, + 0xd6740f20, 0x0e94710a, 0x10606118, 0x82072471, 0xf2541807, 0x8aa7200c, 0x163d23ed, 0x02842016, 0x24097f59, 0x19122a01, 0x0b4141c0, 0x83164b21, + 0x35451800, 0x0039280e, 0x00510049, 0x70171300, 0x2e240a61, 0x07222302, 0x2008774d, 0x280d820e, 0x3435022e, 0x06143736, 0x07e97423, 0x07231726, + 0x36320733, 0x18148775, 0x250ea28f, 0x14211b1c, 0x6f50172d, 0x6109210b, 0x24078748, 0x3319026c, 0x0a3a5119, 0x411e1427, 0x10450f1e, 0xad8f181d, + 0x20092110, 0x0fad8f18, 0x07766b18, 0x7a465822, 0x2324408a, 0x2c2cabe0, 0x200c615c, 0x069d5f16, 0x2707172b, 0x17372717, 0x22262735, 0xb6a81807, + 0x33172a09, 0x23132315, 0x00013315, 0x2800825e, 0x62809a9a, 0xab0c240c, 0x2402820c, 0x2b620c24, 0x2a00832a, 0x5e5f5f01, 0x9a99995e, 0x85624d80, + 0x261e8217, 0x2a924e62, 0x45ab0001, 0xd52f0866, 0x1b000d00, 0x27002300, 0x07250000, 0x82273727, 0x32363403, 0x14161717, 0x07270707, 0x27272206, + 0x37373426, 0x83133727, 0x07272218, 0x29208217, 0x37c90117, 0x2f9a2f27, 0x70843726, 0x511e1122, 0x0c320885, 0xf31e5037, 0x115e111e, 0x5e9a2f1e, + 0xe25e115e, 0x25822637, 0x84372721, 0x1eb2227a, 0x28088550, 0x1e51370c, 0x121ed1fe, 0x2026835f, 0x2726829a, 0x55000100, 0x95012b00, 0x2305da43, + 0x17163201, 0x2005f85f, 0x075b5c17, 0x01023e36, 0x17361d2b, 0x1a1a3020, 0x36172030, 0x3b4e2c1d, 0x4e3b2121, 0x1816db43, 0x29097c85, 0x001c0008, + 0x0038002c, 0xeb410100, 0x37072106, 0x2e103778, 0x26260706, 0x37363435, 0x17161617, 0x42172617, 0x06290839, 0x15074401, 0x0f101521, 0x0f6d521f, + 0x1b43252d, 0x11131513, 0x1923043d, 0x6474122f, 0x17270972, 0x22150f0f, 0x525c0714, 0xeb2f106b, 0x38161518, 0x16351e1f, 0x0324193d, 0x6429032f, + 0x0f2c0b7d, 0xd3010f00, 0x1900eb01, 0x32002800, 0x270aba48, 0x35172315, 0x23232634, 0x2406c55b, 0x07271707, 0x05656017, 0x32213327, 0x27371737, + 0x25b58522, 0x12be0606, 0x0282121e, 0xc45b2208, 0x1d151219, 0x37231d31, 0x1e91230b, 0x19100c62, 0x0a000112, 0xd31e210a, 0x07081912, 0x0111063c, + 0x25288580, 0x1199c32b, 0x29822b19, 0x22202a37, 0x05621e54, 0x11d60d16, 0x1e210519, 0x09121968, 0x073c0611, 0x08f64608, 0x1600eb2b, 0x27002200, + 0x00003100, 0xed821801, 0x069d6a0e, 0x220be67b, 0x82352303, 0x083c4297, 0x5995012b, 0x15152007, 0x12590720, 0x208a8219, 0x2405822a, 0x090907a7, + 0x31038207, 0x2e7f2d37, 0x162d1625, 0x1e030903, 0x13c00104, 0x6d501818, 0x09052d0c, 0x0a0a0607, 0xfe090706, 0x2d7f2ed0, 0x04252883, 0x09031e04, + 0xb9461800, 0x20558b55, 0x42e8824b, 0x15280f20, 0x022e3523, 0x031e3727, 0x20050a61, 0x069b6227, 0x15333528, 0x0717021e, 0x0c48022e, 0x16172106, + 0x08151967, 0x0726192a, 0x2307181a, 0x140b0501, 0x181c0f0e, 0x17180919, 0x170a020f, 0x18132614, 0x0122020c, 0x070e1109, 0x1c1c0d12, 0x17101a26, + 0x0ad07418, 0x26074242, 0x1b1ab0fe, 0x821a0c02, 0x0e2a0832, 0x12100c11, 0x03091310, 0x12181009, 0x14161001, 0x041a1b04, 0x0e051413, 0x060c0d04, + 0x100f0b0d, 0x16260d0a, 0x060e1b15, 0x02520400, 0x006b2206, 0x3c098203, 0x00390027, 0x15213700, 0x17373721, 0x35332737, 0x07273723, 0x23170727, + 0x33073315, 0x20128f17, 0x851d8a25, 0x012b2b1c, 0x1856feaa, 0x121c1212, 0x04822424, 0x131c1227, 0xab132525, 0x82108a1c, 0x07012318, 0x128b1325, + 0x9525132b, 0x1f1f812a, 0x20201f10, 0x82028410, 0x8d0d8a0a, 0x05002415, 0x5b005500, 0xbb500511, 0x18752007, 0x500e9b5d, 0xed4f1659, 0x4207200e, + 0x372007a2, 0x2005b562, 0x62078627, 0x172105a4, 0x83078d07, 0x33372223, 0x27068a16, 0x55262635, 0x19121219, 0x2b200383, 0x19210685, 0x32078e92, + 0x05140c12, 0x0c130636, 0x2806130c, 0x12050642, 0x624c0219, 0x098507ca, 0x19210585, 0x21208212, 0x27840537, 0x12252e83, 0x01190119, 0x204b8680, + 0xf5511899, 0x20088708, 0x2c11882a, 0x0c0a0a0c, 0x02420a0c, 0x06051219, 0x8305824c, 0x85098532, 0x19122105, 0x0a212185, 0x4832830c, 0x17220cc5, + 0xbd421b00, 0x066c7512, 0x2510ad48, 0x552b2b41, 0x96482b2b, 0xaad62312, 0x5368aaaa, 0x0019240c, 0x912a0024, 0x1e072f59, 0x07231702, 0x37023e34, + 0x17032e11, 0x146a3335, 0x27173312, 0x9405293f, 0x362917c0, 0x29362020, 0x0594c017, 0x71913f29, 0x15822c20, 0x2015272e, 0x041d2e3a, 0x1d04aefe, + 0x94893a2e, 0x61183782, 0x0f260a3c, 0x36001600, 0x1a6f6900, 0x23053611, 0x37270735, 0x35231733, 0x36373636, 0x23263435, 0x27070622, 0x380b8234, + 0x16161716, 0x06071415, 0x33150706, 0x020e3715, 0x022e3023, 0x16143727, 0x05c34316, 0x35232322, 0x30830886, 0x33023e23, 0x82308232, 0x1507212e, + 0x3b6f0782, 0xfe48080d, 0x0c1319e7, 0x537d1325, 0x0c051711, 0x09090809, 0x0d081502, 0x0e08170b, 0x0f041305, 0x0170330b, 0x0b0d1008, 0x16030e0f, + 0x07080a03, 0x0a090d0c, 0x090d0609, 0x02080807, 0x11080115, 0x0110120d, 0x07040505, 0x01060609, 0x3a0dc976, 0x130e60eb, 0x1116801b, 0x0a0c0617, + 0x060a0907, 0x07110109, 0x07040205, 0x83150315, 0x15012a57, 0x08090112, 0x0d0d0501, 0x36078209, 0x08090808, 0x060a0615, 0x09050807, 0x0e0a0d03, + 0x06130802, 0x82010308, 0x45152057, 0x16200c13, 0x2111a541, 0x8e183503, 0x612111b5, 0x11844195, 0xc0cbfe35, 0x00040060, 0x01150040, 0x00d501eb, + 0x001b0016, 0x822e002b, 0x1732214f, 0x073b7618, 0x16141130, 0x26263333, 0x023e3435, 0x15333523, 0x795a1727, 0x8207200e, 0x0a80226a, 0x0775720b, + 0x0e0d9b2c, 0xcc362917, 0x1db5356b, 0x02871d31, 0x01563824, 0xc6180115, 0x122a088f, 0x361f182b, 0x96961729, 0x238a4a20, 0x6aa01d23, 0x0ad84235, + 0x2c000e24, 0xe2624e00, 0x3233230d, 0x7c852716, 0x70371721, 0x07210cf5, 0x05d34917, 0x2005665a, 0x4b1d8516, 0x062007c2, 0x2e261d85, 0x0c2b0102, + 0x40432a0a, 0x232b2805, 0x1316233a, 0x520f0e1f, 0x0f24050b, 0x16131f0e, 0x2c301282, 0x23213b4d, 0x1e181e1f, 0x233e2f1b, 0x1b2f3e23, 0x1f320a82, + 0x4d3b2123, 0x130c0001, 0x06b0b006, 0x19120c13, 0x29826e19, 0x12301c26, 0x13210c1e, 0x26054b5b, 0x1e0c2113, 0x821c3012, 0x82552016, 0x2e2c272b, + 0x171e1d4f, 0x3f832540, 0x25264783, 0x1d1e1740, 0x5b832e4f, 0x0002002d, 0x0140003d, 0x00cf01c1, 0x82440038, 0x27072ddc, 0x16173735, 0x26363736, + 0x07262727, 0x3905a944, 0x26262315, 0x07060607, 0x17171606, 0x35211523, 0x37362723, 0x16141533, 0x2a823233, 0x36373726, 0x26262736, 0x0b619218, + 0xa9013908, 0x4d31314d, 0x02030d06, 0x0d540604, 0x0b06250b, 0x08440d08, 0x1d121928, 0x10130403, 0x16014237, 0x03066a4e, 0x0b080d44, 0x0d0b2506, + 0x02040654, 0xd1fe0d03, 0x090c0c09, 0x01260382, 0x1e2f2451, 0x3a82242e, 0x0d062f08, 0x0b062802, 0x090d0922, 0x06191615, 0x15131d04, 0x40b40923, + 0x0808c540, 0x080c0915, 0x27070b22, 0x06060c03, 0x090d0105, 0x080d0d08, 0xa8430d09, 0x002f240c, 0x43350032, 0x7c1811a8, 0x17231f47, 0x18273327, + 0x210ec3b9, 0x7c1855bc, 0x5525104b, 0x2a55552a, 0x0d47432b, 0x0c168029, 0x0c094009, 0x872a1616, 0x2bb03208, 0x002a2a5b, 0x006b0002, 0x01c00140, + 0x001f00c0, 0x076e5d25, 0x35333523, 0x07737223, 0x33161423, 0x07067433, 0x37363236, 0x17072707, 0x0d000137, 0x356b5608, 0x0c09202b, 0x6a55090c, + 0x08310882, 0x3c79a20d, 0xeb975a1e, 0x2b0c0955, 0x0d15152b, 0x2a088709, 0x1f3d7913, 0x0500975a, 0x67001500, 0x032405b3, 0x13000700, 0x35206d82, + 0x2320fe82, 0x33206984, 0x200b6956, 0x0a755633, 0x82332721, 0x27373371, 0x23272307, 0x07173315, 0x33161606, 0x01213521, 0x00822a15, 0x19118028, + 0x19121119, 0x0382c419, 0x0b821220, 0x0c9fcf3d, 0x254f0514, 0x465b964f, 0x081d4d2b, 0x01101607, 0x0100ff00, 0x6b2b2a2b, 0x831995fe, 0x862d8321, + 0x0c6b2d07, 0x9615950a, 0x34a22ac0, 0x2b141d0f, 0x2c0ac545, 0x00180008, 0x00420024, 0x11231300, 0x4d6d8514, 0xdf720eb7, 0x06372a0b, 0x06060706, + 0x34342315, 0x059b6a37, 0x06222322, 0x2f05514d, 0x16161716, 0x11192a55, 0xd5fe2b01, 0x00ff5601, 0x0121a483, 0x08a68200, 0x0d0a912b, 0x0d09090e, + 0x120a2c0d, 0x20020205, 0x07150705, 0x0e0e0105, 0x1e030f0e, 0x14171f07, 0x0306071b, 0xd5fe8001, 0x012a1911, 0x0c977680, 0x0deb2f08, 0x0d0d0a09, + 0x840d090a, 0x040a0e0f, 0x14060c09, 0x0a100c09, 0x110f1308, 0x1a120c09, 0x20090c0f, 0x2b000200, 0xc0002b01, 0x0e00d501, 0xc2821200, 0x080a305e, + 0x06141520, 0x33152327, 0x182b1aa6, 0x126a2a28, 0x401c0f19, 0x3b660140, 0x18aa3939, 0x150d1d12, 0x48441d3f, 0x001b270a, 0x00690044, 0x7a762500, + 0x299f1805, 0x37362c09, 0x32343736, 0x22073635, 0x5635022e, 0x82180725, 0xeb5109a8, 0x1737340a, 0x36370606, 0x26232726, 0x06300726, 0x17140631, + 0x83161615, 0x22232114, 0x230d8644, 0x1917a501, 0x270b044c, 0x081c4526, 0xa0070109, 0x83070a44, 0x11132407, 0x180d0b1f, 0x3708c8a9, 0x1e102614, + 0x030b3515, 0x0c010805, 0x0d010c23, 0x0b16080d, 0x0c150a20, 0x25084152, 0x1c790606, 0x894c2645, 0x1719270b, 0x01010906, 0x44181d06, 0x1e260b8b, + 0x101f1635, 0xb5181525, 0x0d2a08ac, 0x13121e0b, 0x09150ba0, 0x0182010c, 0x010c2427, 0x20030508, 0x09775206, 0x09160c3c, 0x1e000300, 0xca011e00, + 0x0c00c401, 0x26002200, 0x37250000, 0x23373317, 0x02832707, 0x17251722, 0x08099861, 0x17353537, 0x33373307, 0x17013717, 0x01333523, 0x1f110c6e, + 0x0f102020, 0x200f1021, 0x66e4fe0f, 0x14172044, 0x0c081420, 0x08200e1e, 0xfe1ec201, 0x2b2b4f78, 0x804132cf, 0x39008240, 0x8066a43e, 0x052d2b2b, + 0x1f0e0a0f, 0x1ec2203a, 0x15b98801, 0x40000500, 0x7982c000, 0x0e004026, 0x1a001200, 0x2b238782, 0x8b130000, 0x2634226f, 0x20698207, 0x22758437, + 0x83072733, 0x2097867b, 0x21a48333, 0x72864b8b, 0x2b0c1430, 0x2020502b, 0x20082508, 0x0b052520, 0x9585aa05, 0x101f2022, 0x0121a282, 0x2c7a8640, + 0x35130d15, 0x20802015, 0x15408020, 0x25948215, 0x41804040, 0xec188041, 0x18220c17, 0x9a792800, 0x26262812, 0x07062223, 0x77073335, 0x06260960, + 0x26262223, 0x6c536b01, 0x18112808, 0x361d1d36, 0x51abd618, 0xeb230cf5, 0x5bfe1219, 0xfe2708dd, 0x0d0d0cd1, 0x8555c40c, 0x1d122721, 0x001d1111, + 0x60540004, 0x00072607, 0x0013000f, 0x2a7d8317, 0x33171507, 0x07073537, 0x82352723, 0x442720f1, 0x232b05a7, 0x70a05001, 0x2b70a070, 0x82577c57, + 0x2aaa2102, 0x01210082, 0x221082c0, 0x838ea070, 0x2d572110, 0x002de582, 0x00550002, 0x01ab0141, 0x001500d5, 0x234b8225, 0x35170735, 0x27063162, + 0x023e1507, 0x022e3435, 0x2d08c482, 0x06062737, 0x16161415, 0x022e3517, 0x55550001, 0x1c233a23, 0x442a1f30, 0x3e2f1b28, 0x1f1214a3, 0x44281b17, + 0x1c301f2a, 0x55409501, 0x1d824055, 0x2336203c, 0x2f062c05, 0x3e232c49, 0x1aaa1a2f, 0x171e112f, 0x492c233e, 0x052c062f, 0x83483623, 0x180d200a, + 0x1809717c, 0x2608fb4c, 0x37272707, 0x78171737, 0x552a0591, 0x19112b01, 0x21219b19, 0x03824a4a, 0x0c35d218, 0x4949cc29, 0x49492122, 0x82060021, + 0x01c02444, 0x844001eb, 0x82192009, 0x002922c7, 0x26cb8241, 0x27230733, 0x43071733, 0x052211fe, 0x3d7c1523, 0x060e4405, 0x23152724, 0x4e183315, + 0x3521077f, 0xb3821833, 0x55012308, 0x01822520, 0xd3155208, 0x19122013, 0x120e4b20, 0x2b2b150b, 0x202b6b01, 0x13130d4b, 0xd62b2b0d, 0x0c092b40, + 0x404b090c, 0x0d0a0630, 0x80400109, 0x2d0a4980, 0x12802b2b, 0x100a150e, 0x2b20152f, 0x150d1380, 0x1535120e, 0x0d102035, 0x0d082608, 0x07091020, + 0x000d082b, 0x08745f05, 0x0f00032e, 0x2a001e00, 0x00003900, 0x23113313, 0x200b135d, 0x05454217, 0x15060627, 0x34353315, 0x0b225d26, 0xeb221a8e, + 0x06462a2a, 0x0e4d2b07, 0x1e10101d, 0xab0f0b0e, 0x1146e30e, 0x184d2006, 0x2507135e, 0x95010fab, 0x0446d6fe, 0x18222008, 0x20071567, 0x005e180c, + 0x33148b0a, 0x2b000300, 0xd5014000, 0x1f00d501, 0x2f002300, 0x27010000, 0x4409374b, 0x1e2b05e7, 0x35333104, 0x37331533, 0x77073537, 0x013c0e24, + 0x040230a7, 0x1a0d1303, 0x206b0e2d, 0x0d071f36, 0x75080c0d, 0x3c24752b, 0x406a6ac0, 0x3c050b48, 0x3060010d, 0x06060b0e, 0x1317120e, 0x10213520, + 0x2c363830, 0x772b2b1b, 0x2b209514, 0x0a304856, 0x0b594a18, 0x8c821920, 0x47188882, 0x032a0d8a, 0x07331123, 0x15233533, 0x05831733, 0x68432320, + 0xd6d6250b, 0x205535a0, 0x4a180283, 0x3525125f, 0x56805620, 0x12ac6936, 0x03072325, 0x50331614, 0x032006b5, 0x2d06a047, 0x7fab8001, 0x01121901, + 0x19191200, 0x00822a7d, 0x80d50126, 0x191100ff, 0x2207ed6f, 0x446a2b2b, 0x13260c1d, 0x00001a00, 0x68181113, 0x23240920, 0x01062223, 0x2320ab83, + 0x2324ab82, 0x11196b17, 0x28071044, 0xd6d60001, 0x402a4016, 0x0ddf5f55, 0x0001ae26, 0x55555580, 0x1920558e, 0x83127344, 0x07272455, 0x8d170727, + 0x1e1625fb, 0x3c1e1e4b, 0x11446818, 0x4c1e5622, 0x00201782, 0x09b54b18, 0x07000327, 0x1b001700, 0x06bd5b00, 0x13231522, 0x22100171, 0x82eb3311, + 0x802a21f3, 0x2709c444, 0x2bc0d6d6, 0x000180d6, 0x220cb644, 0x43000195, 0x11210ae2, 0xb1721800, 0x1415290a, 0x32161717, 0x34363737, 0x2f0c894a, + 0x120cbdc9, 0x0c191199, 0x0c240cbd, 0xb6fe0c99, 0x2706905e, 0x0cbc0d01, 0x12991119, 0x0c241782, 0x55230d99, 0x3208c65d, 0x00400005, 0x02c00100, + 0x00140000, 0x00240020, 0x822c0028, 0x0606330f, 0x27262223, 0x17161607, 0x33353311, 0x36113315, 0x50433736, 0x3303240b, 0x86172335, 0xb5013203, + 0x2d2d5f29, 0x1e0b295f, 0x2a2b2042, 0x1e42202b, 0x066d4fc0, 0x2b2b5935, 0x552a2a56, 0xab012b2b, 0x0c0a0a0c, 0x020b082b, 0x828000ff, 0x0b0222e3, + 0xce791808, 0x82fe2008, 0x2b2b341f, 0x0004002b, 0x012b0027, 0x00d501eb, 0x000f0007, 0x82450035, 0x37272886, 0x07171737, 0x82271707, 0x37172b03, + 0x07170737, 0x07070627, 0x9a822723, 0x34372724, 0x02823534, 0x17372731, 0x33373736, 0x37171617, 0x14160717, 0x5b141415, 0x013f0f71, 0x18333373, + 0x17333317, 0x2510113b, 0x25111025, 0x30352a91, 0x6b060707, 0x30060806, 0x86292935, 0x0707290c, 0x012a3530, 0x121d1146, 0x21082446, 0x37847301, + 0x4f331826, 0x11112424, 0x13330382, 0x05145c1f, 0x04333303, 0x205c1404, 0x02020401, 0x88200204, 0x1f5d2111, 0x02220e82, 0x9e5b0604, 0x26ca820a, + 0x012c002b, 0x82d401d5, 0x001b2e09, 0x002b0023, 0x003f0033, 0x2500004b, 0x06767515, 0x07823420, 0xb3633520, 0x35172605, 0x3325022e, 0x22dc8226, + 0x82271616, 0x16152406, 0x82021f16, 0x0623221e, 0x22d38906, 0x18273617, 0x080a344c, 0x20160131, 0x121e173a, 0x4327d72a, 0x3545282a, 0x45351d1d, + 0x27432a28, 0x042b5401, 0x0e1f1318, 0x3a172012, 0x122a1720, 0x18131f1e, 0x12032b04, 0x82271840, 0x5518275a, 0x0e095555, 0x0382090e, 0x95755720, + 0x492b3a07, 0x042b0530, 0x29493a24, 0x243a4929, 0x30052b04, 0x3a204049, 0x2a111f18, 0x06ce7578, 0x181ef028, 0x2a18203a, 0x42831b6a, 0x49351b26, + 0x0a0d2249, 0x09324182, 0x04000d0a, 0x2b001500, 0xeb01eb01, 0x1c000800, 0xe7822000, 0x23130023, 0x06ec4a15, 0x0d574718, 0x32212d08, 0x27353536, + 0x15231533, 0x2b401735, 0x55011219, 0x4001abfe, 0x12551219, 0x11196a19, 0x19122b01, 0x755555eb, 0x11eb4001, 0x40012a19, 0x19220e82, 0x3f5b2b12, + 0x2b2b3705, 0x004a95d5, 0x00400001, 0x01c0016b, 0x00100095, 0x15270100, 0xd4452223, 0x36363f06, 0x01153333, 0x1e9580c0, 0x112b1d30, 0x0195121d, + 0x1d6a8015, 0x55551d31, 0x6b111d12, 0xd05b0700, 0x05e85208, 0x3d003126, 0x55004900, 0x200d7773, 0x055a7537, 0x23061424, 0x0b8b2622, 0x23350328, + 0x15020e15, 0xcb822115, 0x4e182620, 0x30970bdd, 0x090d9526, 0x090c0c09, 0x200af661, 0x830d8355, 0x2a2b2915, 0x01223a24, 0xa43a222a, 0x95222399, + 0x1c870d09, 0x012e078c, 0x062c2c08, 0x2b263f29, 0x293f262b, 0x2596c7fe, 0x200a774b, 0x27f78203, 0x2500000f, 0x11233533, 0x232a0382, 0x15012115, + 0x01013523, 0x00822aab, 0xabfe2b33, 0xfe2aaa01, 0xffab80e7, 0x012a2a00, 0xfe1980aa, 0x0a6c44e7, 0x10000422, 0x233b3982, 0x03012315, 0x07270727, + 0x37170717, 0x01273717, 0x01eac0d5, 0x2d1e15aa, 0x822c1e2c, 0x1e2d2802, 0x01c0eb2c, 0x87e2feaa, 0x1e2c220d, 0x2d43822d, 0x02400000, 0x00ab0100, + 0x00150009, 0x7c470100, 0x35012305, 0x47890733, 0x0002372b, 0x4b4b8431, 0x00013184, 0x2a4c8ac0, 0x3240012c, 0xff323939, 0x862bc000, 0x2050825e, + 0x2251d22c, 0x86000001, 0x820720a3, 0x062223a1, 0xa6820107, 0x84000121, 0x82012090, 0xab01219a, 0x01258583, 0x00393200, 0x212a8303, 0xce84e901, + 0x11000d22, 0x37292e86, 0x26263335, 0x23153313, 0x86038235, 0x7e6b2538, 0x2b52772f, 0x3d850082, 0x28aa6b28, 0x2bd5fe2e, 0xbf8a80d6, 0x0f000722, + 0x05276f89, 0x32333636, 0x8a071716, 0xf3fe2877, 0x3535632a, 0x89c22a63, 0x1f6c2580, 0xc31f2222, 0x220a296a, 0x8214000d, 0x07232243, 0x0a554711, + 0x82332721, 0x01332487, 0x4780ab80, 0x92240653, 0x402a4055, 0x220e5347, 0x18555556, 0x280ab949, 0x00130003, 0x002f002b, 0x824c823b, 0x0f1e63c3, + 0x490b3850, 0x33210ac8, 0x25f18217, 0x23061417, 0x08821523, 0x15163227, 0x2a2a4b01, 0x0a166360, 0x354ae727, 0x090c0c09, 0x31068655, 0x802a2a40, + 0x2035090c, 0x010c0955, 0x19a01520, 0xb94eff12, 0x19122206, 0x07c9498b, 0x26080d2d, 0x80800d08, 0x2b0c0940, 0x18080d80, 0x220a7553, 0x5012000f, + 0x032111d1, 0x06d04a35, 0x22052a48, 0x5095f119, 0xfe250d97, 0x0060c0f5, 0x08164a06, 0x0bd85b18, 0x21010026, 0x15150622, 0x27063741, 0x03263435, + 0x07213521, 0x2720fc82, 0x3548038a, 0xff522b0c, 0x40000100, 0x20352020, 0x05843620, 0x257d0120, 0x11192905, 0xff1911d6, 0x205bd600, 0x00210085, + 0x069b6804, 0x2a00d528, 0x3a003600, 0xb8824600, 0x23216082, 0x07ff6123, 0x79832320, 0x21053a53, 0x82883316, 0x2006095d, 0xef681805, 0x4533200d, + 0xab2c0ce3, 0x11401219, 0x1d12121d, 0x19124011, 0xe4410885, 0x230b8405, 0x0d13e4fe, 0x2305b076, 0x15aaaab5, 0x13250985, 0x112b4001, 0x05884619, + 0x2b111922, 0x11222784, 0xa1181255, 0x352009bc, 0x2406b766, 0x122b2b68, 0x200b850e, 0xfecb1800, 0x000b2809, 0x0026001a, 0x583f0035, 0x454b0e0b, + 0x27172928, 0x07352115, 0x15213517, 0x2108d557, 0x72180d66, 0x0e210784, 0x061e48b9, 0x12894d20, 0xff550e29, 0x01555500, 0x4b950100, 0x3b210669, + 0x28008206, 0x0c0d1605, 0x27160d0c, 0x06675119, 0x148a2220, 0x4056af25, 0x18555640, 0x2d081b69, 0x00d501ab, 0x00130003, 0x00270017, 0x7d820100, + 0xe9412520, 0x2513920f, 0x00ff8001, 0x90420001, 0x12192109, 0x01240f8e, 0x2a6b6bab, 0x28092176, 0x6b6bebfe, 0x6b12192b, 0x057f6b11, 0x000e0022, + 0x2005247e, 0x597b18ab, 0x181f200e, 0x35086292, 0x003f003b, 0x35231300, 0x15233333, 0x35330733, 0x23353723, 0x03821715, 0x0b832320, 0x0b821383, + 0x82350721, 0x2335230c, 0x07823311, 0x0a821720, 0x35251682, 0x35331527, 0x310b8217, 0x35331537, 0x552b2beb, 0x2b802b2b, 0x2a2ad52b, 0x0982562a, + 0x802a2a22, 0x2a210783, 0x2514832a, 0x2b552a55, 0x00822b2a, 0x21820120, 0x2b2bab22, 0x2b202284, 0x0a830882, 0xfe2b2b24, 0x1b82abaa, 0x3c820b83, + 0xe1450982, 0x00092f0a, 0x01000014, 0x17073317, 0x27370727, 0x84183733, 0x2908076e, 0x00012723, 0x14303c14, 0x30143434, 0xa134143c, 0x84843283, + 0x34a18332, 0x23424201, 0x40272740, 0x5eaad523, 0xa26464a2, 0x4ccdaa5e, 0x3a000430, 0xc6012b00, 0x1e00d501, 0x3e003200, 0x9d824e00, 0x06022e2e, + 0x07060607, 0x06233726, 0x16171606, 0x362f0282, 0x37363637, 0x36330716, 0x06072636, 0x82272626, 0x20108201, 0x231a8336, 0x06061617, 0x200b155d, + 0x076e4337, 0x34066543, 0x36129401, 0x171e4340, 0x1a040b22, 0x1705112d, 0x2036121b, 0x2a0f8a20, 0x3b431f6f, 0x0d030312, 0x881c2105, 0x425c2009, + 0x122006ac, 0x330ab371, 0x281f5501, 0x0d110811, 0x42471625, 0x2f656630, 0x0809281f, 0x48210e84, 0x2a0e8241, 0x21011295, 0x1d07061f, 0x8810363f, + 0x5a8a2009, 0x2a200765, 0x8208f771, 0x0ad6614f, 0x19000d28, 0x31002500, 0x8e4c3400, 0x3221250a, 0x05353536, 0x440aed49, 0x0b8b0b15, 0x17351725, + 0x82d54001, 0x011126a8, 0xfe19122b, 0x07a46aeb, 0x7821078e, 0x09e36175, 0x6aabd521, 0x55221023, 0x3085080d, 0x75751522, 0x4d0e244d, 0x032ef77a, + 0x2b005500, 0xd501ab01, 0x13000d00, 0x9b411600, 0x08cd4e06, 0x37270727, 0x27173717, 0x89931835, 0x05c8780c, 0x18764d21, 0x280ad849, 0x1e4cd500, + 0x471e5b2e, 0x61871875, 0x0005220b, 0x844f8231, 0x16072142, 0x0e4eb418, 0x0ec26b18, 0x35023e2f, 0x01272634, 0x1f5bf3d5, 0x0211d53c, 0x0b765403, + 0x0ebd6b18, 0x3b4d2c30, 0x01060621, 0x1e5af391, 0x0989d53c, 0xf7540a13, 0x180e200b, 0x280bbc6b, 0x2c4d3b21, 0x00112413, 0x9d571802, 0x00172208, + 0x05ae5729, 0x18056467, 0x830a73f5, 0x4635207e, 0x152405a2, 0x15331523, 0x01200484, 0x21069446, 0x415a1813, 0x68182605, 0x0c09090c, 0x21008215, + 0x7a46aaeb, 0x0faa3405, 0x311d1a2d, 0x1d311c1c, 0x80392d1a, 0x090d0d09, 0x82161515, 0x53002002, 0xd52d057a, 0x1f00c001, 0x36002e00, 0x00003a00, + 0x8b638213, 0x31172177, 0x2306205e, 0x36363131, 0x07231b82, 0x87373734, 0x16172b82, 0x07231315, 0x17333733, 0x04822733, 0x3f7deb20, 0x14250805, + 0x010a0b17, 0x1a1a2d0e, 0x0b0a0f2c, 0x11199317, 0x0d08090d, 0x22a21a11, 0x4e112148, 0x1c762111, 0x00011c02, 0x08998580, 0x2c0f8024, 0x0e20121a, + 0x14171714, 0x1a12200e, 0x1320462c, 0x0c09950d, 0x0d95090c, 0x00011f14, 0x4d3131c0, 0xa6824f4f, 0x2607d071, 0x00170003, 0x1835001d, 0x2009655e, + 0xeb611806, 0x3305270e, 0x23113315, 0x17842205, 0x15333322, 0x28083777, 0x33352323, 0x40150135, 0x08c24740, 0x11111d37, 0x2beefe1d, 0x76016b40, + 0x0e12120e, 0x0d605535, 0x360d1313, 0x035f1856, 0x01ea3513, 0x0d13802a, 0x16130d2a, 0x2a0e122a, 0x2a16120e, 0x55000200, 0x2206014d, 0x84320017, + 0x14705390, 0xfa692520, 0x18322009, 0x230eaf62, 0x3555c001, 0x60207283, 0xfe220685, 0x008380f5, 0x111d122d, 0x1a12121a, 0x01121d11, 0x82162a15, + 0x120e2174, 0x0d230684, 0x18408013, 0x4c0fa662, 0xe0290662, 0x1400d501, 0x4b002000, 0x05da5700, 0x630c9d69, 0x33270827, 0x14151632, 0x57150706, + 0x17240ae3, 0x27262623, 0x23211482, 0x08048523, 0x23153324, 0x15060627, 0x01021e14, 0x1a09069c, 0x2c1b1a2c, 0x1b2c1919, 0x440b1a0e, 0x1f17951e, + 0x1f16171f, 0x8057611f, 0x45273a07, 0x2c072638, 0x1925360a, 0x090d2a12, 0x66152a2a, 0x2f1b0302, 0x190c973e, 0x055c750f, 0x08243c82, 0x421e4507, + 0x16243684, 0x2a401f17, 0x2f071058, 0x243e2f19, 0x090f3d27, 0x092b1911, 0x66402b0c, 0x55061f43, 0x07214f45, 0x05397e00, 0x1748c020, 0x0024250a, + 0x3700002d, 0x0a194318, 0x17370724, 0x03822507, 0x23353722, 0x3c0e6943, 0x26221533, 0x23062223, 0xc02a2aeb, 0x6a014040, 0x1e424040, 0xe2fe1e2d, + 0xc02d1e2d, 0x096d4380, 0x0b052a23, 0x26028205, 0x2aea406b, 0x82672a2a, 0x26028221, 0x6b6bfe2d, 0x431a2c0f, 0x1a250590, 0x022c4f2c, 0xd2881802, + 0x0008300a, 0x0015000c, 0x0100002e, 0x30170727, 0x8227033e, 0x3707278e, 0x1e300727, 0xab180503, 0x214b09f6, 0xc3012c0d, 0x0f1e4c1e, 0xd8101617, + 0x82622a2a, 0x1610260a, 0x22010f17, 0x05524a6b, 0x53116b21, 0x192206af, 0x1b866501, 0x3c6b5b22, 0x7f4a3086, 0xcc631807, 0x02002108, 0x11544718, + 0x15333535, 0x27333533, 0xfe2a016b, 0x558055d6, 0xab2b5595, 0x4c958080, 0x13220a02, 0xaf821800, 0x2f0b085f, 0x35363221, 0x05351735, 0x17371737, + 0x12198001, 0x2e063554, 0x55191200, 0x233296fe, 0x20014838, 0x4c191260, 0x60370768, 0x43caea55, 0x00604b2e, 0x002b0003, 0x01d50155, 0x001300ab, + 0x962e001f, 0x16322354, 0xac681415, 0xa6701806, 0x4a6a8d0f, 0xff820535, 0x0eab6723, 0x0729560c, 0x2020798f, 0x2107b94a, 0x7d180caa, 0x898a093a, + 0x14000f24, 0xe14c1900, 0x11012911, 0x33050733, 0x21253723, 0x0c4b5018, 0x3f99fe2c, 0x44040131, 0xfbfe323f, 0xf34c1201, 0x01d52c0e, 0xba46ba00, + 0x00020046, 0x8253002b, 0x82ad20e5, 0x53232057, 0x262508c8, 0x14111506, 0x76761816, 0x35363a07, 0x07263411, 0x37070622, 0x26173717, 0x20b90126, + 0x603e3e5b, 0x11110b1b, 0x2109830b, 0x0982205b, 0x25c42b08, 0x2a4f2046, 0x4620603d, 0x140baa01, 0x0d040915, 0x0bd6fe0b, 0x140b030d, 0x0d030b14, + 0x0b2a010b, 0x0405ed0d, 0x7449345f, 0xfb4c0504, 0x0002260a, 0x000a0006, 0x2a78820e, 0x03132113, 0x23130321, 0x82353315, 0x00012b03, 0xa1befea1, + 0xebd601eb, 0x00822a15, 0xfe80012e, 0xfe6a01eb, 0xfe95016b, 0x6bab2bd6, 0x2b224082, 0xb5828000, 0x01006b2e, 0x7d003f00, 0x0000bb00, 0x32253125, + 0x2005116c, 0x26078b33, 0x022e2235, 0x820e2223, 0x24078e03, 0x023e3215, 0x8c189705, 0x84288242, 0xb14a830f, 0xd5012d63, 0x0d0a9dfe, 0x100f130e, + 0x0a0d0d13, 0x0e8e098e, 0x0f25228e, 0x010e0e13, 0x26058225, 0x0e090a0d, 0x840f140d, 0x0d0a2409, 0x8410130d, 0x8e0e8e28, 0x2127834b, 0x148ed4fe, + 0x18986089, 0x5a822284, 0x16d50e25, 0x8b070807, 0x062b2302, 0x028e0609, 0x1f822b20, 0x0f8f168f, 0x12833282, 0x3a8e8020, 0x5d8e2a20, 0x2a200e82, + 0x6f502282, 0x0007350c, 0x000f000b, 0x0100001a, 0x05071737, 0x13211521, 0x07231533, 0x07220b82, 0xce413421, 0x6a013405, 0xfe2d1e2d, 0xfeaa01a3, + 0x2a2ac056, 0x1e2d1e9f, 0x742a010e, 0x4720081e, 0xa9251c82, 0x4056012b, 0x24188214, 0x29361f7f, 0x481a8217, 0xd82a064c, 0x0d00c001, 0x21001b00, + 0x60514200, 0x51172005, 0x3722055c, 0xe2592626, 0x29108606, 0x26371707, 0x07072223, 0x88182726, 0xf57f13d5, 0x27450805, 0x60012627, 0x17173e24, + 0x1c1d3213, 0x17171233, 0x270e283e, 0x0f271616, 0x101b0a17, 0x520a1b0f, 0x120c1e1e, 0x52350112, 0x0208352e, 0x080b0210, 0x030c0959, 0x4719161b, + 0x2e56262c, 0x070a0d09, 0xc0010c4e, 0x353e821b, 0x17131616, 0x0e5f1b17, 0x170e1111, 0x0a0c0c0a, 0x0d1e1e17, 0x88183673, 0x033011d1, 0x0859090c, + 0x030f020b, 0x2b000500, 0xd5015400, 0x1d28cd82, 0x44003600, 0x4c004800, 0x0623cf84, 0x63161415, 0x16262772, 0x022e3317, 0x32822207, 0x33161729, + 0x35363732, 0x18372634, 0x270860a3, 0x14233a23, 0x0d0c1e12, 0x2405884c, 0x121e0c0d, 0x3f128214, 0x213b4d2c, 0x171e1d21, 0x3e2f1b1b, 0x17462823, + 0x47381334, 0x0d191227, 0x0d11110d, 0x2a99190d, 0x01210082, 0x2927826b, 0x1f122e1b, 0x17121f0b, 0x02821727, 0x2e210a84, 0x0774631b, 0x824e2c21, + 0x243e3a40, 0x1a2f3e23, 0x30201e22, 0x1119ab1b, 0x0d0d0c12, 0x1911120c, 0x2b2b8016, 0x05ed5e00, 0xc401d52e, 0x3a002800, 0x00005000, 0x06170713, + 0x3720d78a, 0x37250d8b, 0x31061417, 0x23bf8314, 0x27371733, 0x2e07426c, 0x32333217, 0x14151616, 0x1e322715, 0x64141502, 0x23220756, 0x0a820622, + 0x391e3c24, 0xc4841715, 0x1e0f1224, 0xe5840b09, 0x01230822, 0x0125c382, 0x4a1ea302, 0x28a78206, 0x01251315, 0x17261802, 0x23a48255, 0x0d20111b, + 0x07204918, 0x01231f28, 0x1b391ec4, 0xc3862443, 0x15321c26, 0x13230f1e, 0x1324ed86, 0x02012212, 0xa224ca82, 0x1414871e, 0x07214582, 0x35fc8224, + 0x1aae0103, 0x27233e2f, 0x35172022, 0x3b4d2c1d, 0x200d0e21, 0x46180010, 0x77520934, 0x10987a09, 0x3523072f, 0x23152333, 0x15331535, 0x33353323, + 0x0ce54515, 0x96961124, 0x038396c0, 0x220a404c, 0x85191156, 0x96962313, 0x8b180300, 0x0f2608ce, 0x2f001f00, 0xe54e0000, 0x660f8f0f, 0x80200f2c, + 0x0287bc82, 0x0b966920, 0x1e73eb20, 0x27182308, 0xbf73d517, 0x82088208, 0x8240180c, 0x0ae66209, 0x3f000f26, 0x5b004f00, 0x2511cc46, 0x33363405, + 0xba4b1732, 0x250b8207, 0x06141516, 0x67471607, 0x18272005, 0x2208d2e1, 0x82262223, 0x26372823, 0x26221726, 0x82323526, 0x3634271f, 0x06143336, + 0x1a532706, 0x0c28410a, 0x13effe35, 0x13080b0e, 0x09130e0e, 0x0a130e0a, 0x130a0909, 0x8b090a0e, 0x2355210f, 0x09a16518, 0x18834420, 0x56410383, + 0x0d843e0d, 0x0d030614, 0x030d1414, 0x0a0d1406, 0x10040410, 0x06140e0a, 0x13130e02, 0x1406020e, 0x2011840e, 0x684118dc, 0x83c8200b, 0x140e351a, + 0x00030014, 0x022b0055, 0x00d50100, 0x00220006, 0x3700002e, 0xc582ad82, 0x1614372a, 0x33151716, 0x33352115, 0x3620d082, 0x2908b44c, 0x06061716, + 0x23352317, 0x1c822315, 0x3335333f, 0x121956d5, 0x16561912, 0xfe2b1926, 0x2b192baa, 0x0d0d131c, 0x0f141613, 0x2b40d510, 0x08028240, 0x19115523, + 0x301cfc19, 0x2a320924, 0x331d962a, 0x0e0f0724, 0x0f0e1212, 0x2b100e05, 0x2a404003, 0x08004040, 0xef7f1800, 0x15290807, 0xaf008800, 0xef00e300, + 0x0401f800, 0x00000d01, 0x17363613, 0x16161716, 0x30070607, 0x2627030e, 0x1437033e, 0x22230606, 0x05b37327, 0x32333122, 0x17231c82, 0x82071416, + 0x2722220f, 0x067a4126, 0x22831d82, 0x14151424, 0x228b3316, 0x88062321, 0x34352522, 0x27262637, 0x75634982, 0x36153008, 0x36363736, 0x36301533, + 0x31163233, 0x82070622, 0x833420fe, 0x0516250b, 0x36171614, 0x35222e82, 0x1a82023e, 0x23057e45, 0x07141516, 0x36211582, 0x06f04535, 0x34340524, + 0x50823435, 0x27275182, 0x36343736, 0x72331635, 0x0722081c, 0x114e2707, 0x20478205, 0x23238307, 0x15141415, 0x27201f82, 0x250a4e72, 0x22233427, + 0x33821415, 0x14930720, 0x05ec4808, 0x0306070f, 0x02010204, 0x20201509, 0x0f010216, 0xe9111818, 0x07060f0b, 0x303a0806, 0x0c080b02, 0x0d030208, + 0x05050406, 0x03060e13, 0x01010502, 0x0802120d, 0x191b0910, 0x0c090c01, 0x0e020308, 0x06040405, 0x84070e12, 0x140e251b, 0x07312702, 0x0f233b82, + 0x821e140b, 0x152e0813, 0x1803253d, 0x0a0b0b0e, 0x010b080b, 0x0311311d, 0x141e0e07, 0x020396fe, 0x04040c06, 0x16251501, 0x0b0b1b0f, 0x25160f1b, + 0x060c0715, 0xc6460302, 0x08152708, 0x121f0b07, 0x6e820809, 0x1104062b, 0x1a10101a, 0x0e111611, 0x2404820e, 0x151b101a, 0x256e8211, 0x5c5c2408, + 0x98551207, 0x08102a06, 0x04040808, 0x0e0d135a, 0x83128312, 0x0503250e, 0x04070601, 0x36089482, 0x0b040a04, 0x11130c06, 0x1302020b, 0x25111a1b, + 0x05091c1b, 0x070b4035, 0x0f080809, 0x030a0305, 0x05010704, 0x05070b03, 0x12020409, 0x0501010d, 0x09010301, 0x8909070d, 0x0c36081b, 0x04080507, + 0x05101703, 0x2f3d0e06, 0x1b1c0905, 0x0d1c2c18, 0x05251c05, 0x0a15120f, 0x07070a0a, 0x0d051723, 0x0d2e2c1c, 0x13160b17, 0x16091008, 0x0a0b1624, + 0x06820b0a, 0x10112008, 0x170b1514, 0x29361f0d, 0x36291818, 0x0203017a, 0x0c0d1e10, 0x0907020f, 0x01010201, 0x83101b10, 0x0c0c2102, 0x15280683, + 0x07110421, 0x101e0d0f, 0x3b257e82, 0x151510b0, 0x25038210, 0x09080803, 0x0c8b0f05, 0x00040025, 0x5e4b0015, 0x17200802, 0x25059d60, 0x17173737, + 0x9c18020f, 0x032d0df1, 0x27371737, 0x01072707, 0x142c2c2c, 0x20038214, 0x820483eb, 0x18743003, 0x17183333, 0x803e3333, 0x981eb655, 0x8501a055, + 0x2c14221e, 0x2008862b, 0x2a1e843f, 0xd8fe1817, 0x1fcb5580, 0x5ba055aa, 0x0b200a2d, 0x33237082, 0x42010000, 0x17210a49, 0x056a4a14, 0x20079c66, + 0x09ce5707, 0x9d4a1420, 0x35012505, 0x1f16161f, 0xa0200383, 0x210f7b72, 0x6347562a, 0x18562005, 0x2008aa6a, 0x25298500, 0x4d2c161f, 0x2e8b213b, + 0x51055c54, 0x002d06ab, 0x001e0002, 0x01d5011e, 0x000500c4, 0x2790820f, 0x07173727, 0x07172527, 0x3739f482, 0x01013701, 0x801e6299, 0xb3fe1e4c, + 0x1e804c59, 0x11012e62, 0x0178fe1e, 0x24138200, 0x59d41f4d, 0x2612834d, 0x011ef0fe, 0x84040088, 0x01c42646, 0x000900eb, 0x230b820c, 0x2500002a, + 0x087d4318, 0x1735252b, 0x15333537, 0x26341117, 0x07bc6f23, 0xbe181720, 0xc43f0c0d, 0x221e78fe, 0x19011219, 0xeec5fe22, 0x192b2a12, 0x20075912, + 0x07201515, 0x09196b48, 0x82090c0c, 0x013c3a03, 0xfe221e88, 0x221912e7, 0xeaeeee4d, 0x012bee40, 0x13191219, 0x6b131818, 0x074c546b, 0x0a17bf18, + 0xcc820b20, 0x83851b20, 0x1115062f, 0x21331614, 0x33352517, 0x32212717, 0x080e8216, 0x33270735, 0xd3012335, 0x211e5afe, 0x01111905, 0xa0fe4719, + 0x01325619, 0x05191119, 0x2dc46f94, 0x211ea601, 0x00ff0b09, 0xf1461912, 0x19ab5555, 0x0b00ff12, 0x18559409, 0x200a2e46, 0x0f826d1f, 0x20055644, + 0x06dc4426, 0x0001232a, 0x1e354528, 0x2845351e, 0x012e0783, 0x1d311001, 0x1a1f3420, 0x070f0716, 0x1687c001, 0x10820783, 0x1f1a162b, 0x311d2034, + 0x00010110, 0x38b58206, 0x01d5010f, 0x001300d3, 0x001b0018, 0x002c001e, 0x1300003a, 0x33171533, 0x06cc6235, 0x34290782, 0x17212326, 0x23153335, + 0x29188327, 0x33321715, 0x07013717, 0xe8841417, 0x17113529, 0x23173315, 0x83353315, 0xd9a72407, 0x832a2e27, 0x12192f00, 0x5584fcfe, 0x3c194043, + 0x01022b2e, 0xfb821e32, 0x11191c31, 0x5915442b, 0x2b2e156b, 0x27d99501, 0x822a2b2b, 0x12220802, 0x402f8419, 0x2e3d1940, 0x011e31a7, 0x011c1ea6, + 0x12d6fe03, 0x03012b19, 0x5615442a, 0x2a2f1544, 0x0a460200, 0x00cb2406, 0x4239000b, 0x03240dc2, 0x32331617, 0x2f052969, 0x17372527, 0x26262737, + 0x36373736, 0x17171616, 0x372c0382, 0x26260717, 0x07170727, 0x31313717, 0x01220f82, 0x8671198b, 0x3a2e0806, 0x1a151510, 0x26101818, 0xfe191c14, + 0x24940ad5, 0x0b04094c, 0x190c4a0c, 0x07070415, 0x1f0b1520, 0x0f3d2718, 0x422f4136, 0x080f082c, 0x2657a001, 0xfe320806, 0x0b070690, 0x090a0918, + 0x5f351e6d, 0x181a0a4f, 0x02062b07, 0x17170d0f, 0x0a220923, 0x24320649, 0x187b4a1f, 0x0105038a, 0x55000400, 0xc0012b00, 0x0982d501, 0x27000e24, + 0xb6822e00, 0x23071723, 0x09c87a35, 0x45470720, 0x20158214, 0x05694707, 0x2677012e, 0x17b0266a, 0x12030903, 0x40031226, 0x250a4647, 0x626d151a, + 0xc983566f, 0x267b0127, 0x1774256a, 0x22228403, 0x47678509, 0x06280c4b, 0x6b626d11, 0x00191911, 0x2e057043, 0x00e001e0, 0x00390025, 0x22272500, + 0x46232322, 0x152906a1, 0x35262223, 0x023e3235, 0x2e108335, 0x35363435, 0x27013727, 0x35363235, 0x5b232634, 0x320806e1, 0x15062223, 0x23a60123, + 0x51010101, 0x0512150e, 0x0e141304, 0x16191251, 0x04040d19, 0x0116190d, 0x88011e23, 0x1f1f1619, 0x55121916, 0x1f161620, 0x87221e2e, 0x12192b1b, + 0x13140e51, 0x15120504, 0x3e82510e, 0xfe1e232a, 0x1f2e5678, 0x55201616, 0x31823f82, 0x080a8d7a, 0x1100054e, 0x35130000, 0x07331533, 0x17070117, + 0x17371723, 0x17211523, 0x4c5580c0, 0x1e78fe7b, 0x0d951966, 0x0301d937, 0x447c0138, 0x01b74d80, 0x95661e88, 0x372b370c, 0x0f000400, 0xd5010f00, + 0x0300d501, 0x17000d00, 0x00001c00, 0x33372701, 0x17220282, 0xc4821117, 0x27012123, 0x21e38221, 0xd7822711, 0x07273c08, 0x0c013733, 0x24020512, + 0x88362e0c, 0xbcfe1119, 0xfe1c4e01, 0x1c1911bc, 0xd1a6011e, 0x172c3346, 0x0e133001, 0x8891200f, 0x19114401, 0x191c3afe, 0x1c440111, 0x945afe1e, + 0x82418847, 0x005f2c5f, 0x01950115, 0x000b00e0, 0x8237002d, 0x05264167, 0x15062232, 0x26171614, 0x26272726, 0x06222326, 0x31060e07, 0x098b8818, + 0x33151725, 0x82072311, 0x37372719, 0x17173636, 0x4a422001, 0x67260806, 0x16091f13, 0x0c0c1506, 0x08010317, 0x0b0e0d0c, 0x2c272d07, 0x100d2d2b, + 0x2020192c, 0x0a082ed6, 0x1d031101, 0x88181812, 0x2f080986, 0x11180671, 0x100b0a22, 0x3c28040f, 0x22394445, 0xa0802bab, 0x1b12402b, 0x2b01d905, + 0x0f010958, 0x14125309, 0x02000504, 0x2b002b00, 0xc001eb01, 0x3120a282, 0x6805e15c, 0x342205a7, 0x08823336, 0x15331133, 0x32211523, 0x23353636, + 0x23060614, 0x35333523, 0x24b98534, 0x26222327, 0x260f8217, 0x360406ab, 0x82060436, 0xab2b0805, 0x55015540, 0x2b1d311d, 0x2b121d11, 0x0f1e1340, + 0x07150e3a, 0x8006043c, 0x4b018080, 0x06160604, 0x40060504, 0x2a2bc0fe, 0x831d311c, 0x3d260822, 0x04162217, 0x0c12030f, 0x002bf106, 0x00000004, + 0x01000215, 0x001a00d5, 0x00570026, 0x25000061, 0x06312722, 0x02832722, 0x32227883, 0x02851637, 0x15333322, 0x230bd06e, 0x07063013, 0xa4659282, + 0x82058705, 0x31250811, 0x37363630, 0x17363637, 0x17311716, 0x37273737, 0x1e020f17, 0x27072703, 0x33323207, 0x01171632, 0x1e1e22c0, 0x27028444, + 0x22151522, 0x1d461d1e, 0x1e230282, 0x41d51522, 0xee2b0672, 0x160d272d, 0x13210c09, 0x850c2113, 0x09260805, 0x2d270d16, 0x1d2d4427, 0x040f1c05, + 0x243c3502, 0x1c441c0b, 0x42264f1c, 0x20c01a30, 0x0a050f25, 0x0b160b05, 0x00841015, 0x14152b22, 0x15230082, 0x4476012b, 0xff2a0743, 0x040b1300, + 0x120e0a10, 0x03830e12, 0x100a2208, 0x0f130b04, 0x0f590815, 0x0201050f, 0x1c4f201b, 0x0a401e3f, 0x101005b2, 0x1412610b, 0x0001012e, 0x06c74405, + 0x0b00eb2a, 0x2a000f00, 0x5b005400, 0x5305a141, 0x25260797, 0x13170723, 0x23412335, 0x20058205, 0xed621823, 0x37322c08, 0x35331631, 0x07060614, + 0x45222306, 0x273006fa, 0x26273736, 0x36343535, 0x36323333, 0x06061737, 0x884a2e83, 0x27072605, 0x023e1707, 0x07c66f80, 0x2d2c0125, 0x41741634, + 0x0b820b13, 0x24072b41, 0x0a1f311c, 0x0512410a, 0x1b0f2108, 0x21120e0b, 0x4012190a, 0x1e0e2716, 0x1e1f3614, 0x381f243c, 0xbc1a0d15, 0x0612350f, + 0xc0011313, 0x24064a41, 0xfe17343d, 0x07114175, 0x00841020, 0x2710d034, 0x1203152b, 0x0c120e0e, 0x3f0d0c09, 0x12551612, 0x44821119, 0x284a1838, + 0x250b100d, 0x042b0210, 0x09000b0b, 0x15001500, 0xeb01eb01, 0x6b461000, 0x00482806, 0x00640056, 0x50800072, 0x244b0808, 0x75072009, 0x2326064c, + 0x14150622, 0x0d8c2116, 0x11822720, 0x35221083, 0x1e822634, 0x0d8c1120, 0x18260321, 0x2209d38e, 0x8a172736, 0x2734240d, 0x18343611, 0x2208138f, + 0x8c073716, 0x0001210d, 0x250b2e74, 0x0d092ad5, 0x0483090d, 0x88890121, 0x0cb7220a, 0x061e4809, 0x6b2d0786, 0x07061206, 0x11071607, 0x07010606, + 0x820682f2, 0x2112840c, 0x06820707, 0x05841620, 0x0b8af220, 0x8b6b0121, 0x8f802063, 0x88ea204e, 0x77fe2169, 0x01210a88, 0x204c9740, 0x827d9500, + 0x0100218a, 0x08915b18, 0x00001827, 0x23351701, 0x05727d17, 0xae822620, 0x3637172f, 0x16171732, 0x01373616, 0x318031a4, 0x2a458259, 0x21210c19, + 0x711e710c, 0x84071106, 0x3101210a, 0x06251884, 0x08080d19, 0x8517830d, 0x04002409, 0x45005500, 0x98720505, 0x002c2b05, 0x35232500, 0x07232333, + 0x0f451333, 0x0307210a, 0x35090345, 0x26223533, 0x26262727, 0x33150707, 0x20950135, 0x2b21f420, 0x4a42aa21, 0x443c2007, 0x153005f8, 0x311e233d, + 0x2009160c, 0x152b6c0f, 0x7601c0c0, 0x22075d56, 0x44d3fe49, 0x182b05eb, 0x171d2a1d, 0x060a0e22, 0x1848642e, 0x260ae17d, 0x000a0006, 0x4b1b0014, + 0x3329054f, 0x27072715, 0x35171517, 0x0bf54507, 0x27372731, 0x35331315, 0x3b660123, 0x1e573c95, 0x491a2b86, 0x1e3705d7, 0x686b8801, 0x68221e22, + 0x0184593c, 0x3b953c84, 0x592d1e57, 0x4ae2842b, 0x1e230518, 0x842f78fe, 0x01ee231d, 0x70822b2a, 0x00001530, 0x0002eb01, 0x2c000b00, 0x54005000, + 0xf9825800, 0x35262235, 0x32333634, 0x06141516, 0x35022e07, 0x17161423, 0x82171616, 0x363622e6, 0x06644537, 0x020e072e, 0x26262223, 0x020e2213, + 0x16141515, 0x37221682, 0x05823317, 0x17203582, 0x2e820882, 0x35361630, 0x022e3435, 0x37362707, 0x17162717, 0x1a410001, 0x5c410806, 0x2a0c1005, + 0x1208161b, 0x120a800a, 0x2a1b1608, 0x0805100c, 0x15151b12, 0x3142121b, 0x17254055, 0x0304020b, 0x12202a2b, 0x25141425, 0x2b2a2012, 0x0b020403, + 0x55402517, 0x1d1920b4, 0x191d16f0, 0x07aa4495, 0x04142a08, 0x2b1d2211, 0x0a061139, 0x034d4d03, 0x3911060a, 0x11221d2b, 0x060a0604, 0x85010a06, + 0x1321190e, 0x070c0d4a, 0x64020202, 0x22048286, 0x82648602, 0x0c072f05, 0x21134a0d, 0x4cf00e19, 0x5b5b0609, 0x4e180906, 0x0a280af2, 0x1e001100, + 0x36130000, 0xfb84fa83, 0x26261723, 0x08028227, 0x0701174a, 0x07060617, 0x15150606, 0x0bb91721, 0x26181626, 0x7c111517, 0x08101201, 0xfe610a13, + 0x1dbd1e78, 0x13101432, 0x01381901, 0x17161184, 0x26161827, 0x1e117c0b, 0x04080409, 0x1e88019e, 0x0b1103be, 0x3c121e08, 0x00040037, 0x2707be70, + 0x001d000f, 0x002f0026, 0x21116752, 0x6d791533, 0x33352505, 0x27161415, 0x33200483, 0x21201282, 0x42181487, 0x7c300c14, 0x09056005, 0xb70d2a0d, + 0x05090d2a, 0x452a0145, 0x30600d83, 0x2a012d09, 0x60f51912, 0xb5090c60, 0xca0c09b5, 0x0b840382, 0x2708634c, 0x000900c4, 0x001a0012, 0x230c634c, + 0x17352327, 0x332a7882, 0x33351733, 0x17373632, 0xeb4b2715, 0x35272505, 0x07141523, 0x01200582, 0x2109634c, 0x778345f6, 0x08052030, 0x4547020a, + 0x1219016f, 0x042a2b19, 0x614c2a52, 0x4e2b360b, 0x60600c09, 0x29460609, 0x12196ee7, 0xee2be7fe, 0x520605b5, 0x4583826e, 0x8c5c0531, 0x00302205, + 0x228e5c3b, 0x07062723, 0x37018327, 0x30371737, 0x2617031e, 0x043e3027, 0xa8011731, 0x2b1a0807, 0x1a2b1b1b, 0x0e250582, 0x1f420b1a, 0x06b14d94, + 0x15171e3b, 0x4e40510c, 0x55406b23, 0x0b12110c, 0x10171538, 0x10191b19, 0x1a0b7623, 0x822e850e, 0x07082605, 0x1f401f43, 0x37328516, 0x120901b5, + 0x197c4b84, 0x128b4bab, 0x0b12191a, 0x27190209, 0x1919272c, 0x370e9e69, 0x01000027, 0x15352315, 0x27353315, 0x22230606, 0x3435022e, 0x1533023e, + 0x087d5e18, 0x33021e2d, 0x01373632, 0x552a2ad5, 0x4e264218, 0x23240622, 0x30541da1, 0x2c07444e, 0x011b4124, 0xd6abab2b, 0x1a3a2a2a, 0x076b4e20, + 0x21a1c023, 0x07614e28, 0x00141623, 0x08584704, 0x12000222, 0x463c0b82, 0x35370000, 0x2e342107, 0x1e302303, 0x06141502, 0x21173106, 0x36171616, + 0x16163736, 0x05877083, 0x17201182, 0x36196f47, 0x8001abeb, 0x2d322d1d, 0x0609060c, 0xfeca0a0b, 0x121a0556, 0x4807120b, 0x07200b41, 0x1a211082, + 0x16594705, 0xf5f5e035, 0x3043502d, 0x3227161b, 0x213a251c, 0x0f291820, 0x48080e05, 0x0825072f, 0x290f050e, 0x0d444793, 0x0001002b, 0x01150055, + 0x00eb01c0, 0x053a411b, 0x33352324, 0xed5e2335, 0x83352009, 0x15332a0f, 0x2b013533, 0x96363640, 0x82008236, 0x95402904, 0x2b2b4001, 0x2b80802b, + 0x80200182, 0x002b0983, 0x002b0005, 0x01d50169, 0x820d0097, 0x0027274a, 0x00430035, 0x2e4e3700, 0x56172005, 0xeb180597, 0x07210c0e, 0x0a477827, + 0x06141723, 0x211d8907, 0xc7562725, 0x12a62a0b, 0x1e121414, 0x0c0d0d0c, 0x20098896, 0x06b0443c, 0x171b9924, 0x69571d1e, 0xdcfe2105, 0x1b2f0987, + 0x1b2e11a6, 0x1e112e1b, 0x12121f0b, 0x8c1e0b1f, 0x4467200d, 0x2b2e07a1, 0x1e183e23, 0x2c2c4e1d, 0x181e1d4e, 0x0a89563e, 0x3e232322, 0x200a5b57, + 0x29d6821e, 0x13000039, 0x16141506, 0xce850717, 0x0d879e86, 0x07013730, 0x35363627, 0x07272634, 0x14151616, 0xcc8c3707, 0x0d03ae2b, 0x14111f0c, + 0x0b1f0606, 0x29ad840d, 0x1e301112, 0x321e8801, 0xd6840606, 0x0d59032f, 0x12111f0b, 0x171e1d21, 0x0b16011b, 0x2ab1820b, 0x1b2e121f, 0x200c1c0f, + 0x86182c13, 0x3b212ba4, 0xfe1e301a, 0x0cab1e78, 0xd9860f1c, 0x160b0b29, 0x1f132c18, 0x85213b1a, 0x040031c1, 0x55000000, 0xab010002, 0x1f001300, + 0x33002d00, 0x4218b582, 0x17200e01, 0x8306e257, 0x0d7241a9, 0x2707072c, 0xab153335, 0x1b2e3e24, 0x74582e1b, 0x2f1a2e05, 0x1e10bd3e, 0x0d0f0f0d, + 0x144a101e, 0x829e8211, 0x141127be, 0x2b491ed9, 0x7c18ab01, 0xab210f36, 0x232a8216, 0x23141423, 0x16202c82, 0x1f23a182, 0x82233e18, 0x111f2cbb, + 0x491d4f2e, 0x05004d5d, 0x82004000, 0xeb01229a, 0x05306e00, 0x5b005622, 0x0de39218, 0x200b904b, 0x0a194233, 0x07223727, 0x23230606, 0x66951835, + 0x07232d0c, 0x07333717, 0x07171706, 0x23262726, 0x30059959, 0x32333316, 0x35363736, 0x23072634, 0x01172737, 0x07e84115, 0x09077a28, 0x0a060709, + 0x0783af0a, 0x31080382, 0x09050743, 0x5c060f1b, 0x253e1227, 0x0b0b301d, 0x7a0e1203, 0x32292435, 0x1d060b33, 0x050e1643, 0x03090708, 0xcb18280d, + 0x040d2817, 0x3e74760a, 0x854a4b15, 0x72fe2308, 0x45860709, 0x3d080786, 0x0e0b074b, 0x1d3d3980, 0x1a202b24, 0x5510061a, 0x11524217, 0x06515813, + 0x060a0712, 0x14120505, 0x05051214, 0x4a200a06, 0x05002f47, 0x12001500, 0xcb01ee01, 0x35000b00, 0x3f003b00, 0x5a504200, 0x0e133d0d, 0x25312702, + 0x27371737, 0x37351737, 0x16161736, 0x36370707, 0x07021f16, 0x31170727, 0x2905537d, 0x25021e37, 0x37372617, 0x13821707, 0x07273724, 0xe6872b01, + 0x2207bb28, 0x9afe162c, 0x0182540a, 0x75222908, 0x0e100d0e, 0x0f2d1605, 0x2a2c0619, 0x470a470a, 0x07072715, 0x17091514, 0x92fe0a1e, 0x16050816, + 0x0a8ea929, 0x5519188f, 0x3d096950, 0x0a1e169e, 0x1b1e7507, 0x0b1e1c1e, 0x04063257, 0x460f1c05, 0x0d0e0208, 0x171f0d60, 0x3c82171e, 0x06281523, + 0x3663821f, 0x0f0f0769, 0x2ea21244, 0x373b2e1e, 0x00030013, 0x011d002a, 0x82eb01d6, 0x004022d4, 0x0dd34145, 0x0726132a, 0x032f0606, 0x33161637, + 0x20069049, 0x09b94123, 0x26262723, 0x22018227, 0x82060706, 0x051721e8, 0x3727de83, 0x37252636, 0x82171727, 0x06a26ad4, 0x089e3a08, 0x101d0b06, + 0x26461618, 0x1e253f12, 0x030c0b2f, 0x36790f11, 0x35322825, 0x4b12040a, 0x06180f0a, 0x0b070803, 0x09020101, 0x0e011723, 0x04112b17, 0xfe070101, + 0x3d0a41eb, 0x09b44110, 0x0502a527, 0x0603080a, 0x0ca64184, 0x0f554408, 0x02324a12, 0x080d1303, 0x06080201, 0x1d140505, 0x0c053a04, 0x0705030f, + 0x472b1a0b, 0x0200632b, 0x5500feff, 0x95010002, 0x32002c00, 0x14250000, 0x27232306, 0x34353636, 0x2331052e, 0x07173315, 0x82170727, 0x26db82de, + 0x36363233, 0x82173335, 0x32530814, 0x05353636, 0x14173723, 0x0cd50106, 0x202f0409, 0x241f1228, 0x40121f24, 0xcb4f1f30, 0x0e4b6120, 0x1115070a, + 0x17271780, 0x80402b55, 0xfe111d12, 0x3a7080ab, 0x0d089519, 0x171e072f, 0x231f1704, 0x2a101b22, 0x40163a1c, 0x1b08281d, 0x2717131b, 0x822b2b18, + 0x3c153026, 0x00191211, 0x00550002, 0x01ab0113, 0x410b00e0, 0x03200f68, 0x16278b82, 0x36371617, 0x82262736, 0x37272401, 0x83151737, 0x8237208e, + 0x232625ae, 0x07060722, 0x2a0d3f43, 0x07020e22, 0x37353315, 0x4a0b0107, 0x6b0807f4, 0x331a1884, 0x07091711, 0x02050304, 0x020a0f04, 0x2b2d134a, + 0x08151b53, 0x04040809, 0x0d2d100d, 0x1f243d15, 0x06160d30, 0x0e060b13, 0x2b252d1a, 0xb5012226, 0x12191912, 0xfe191911, 0x41141fc6, 0x06030915, + 0x02060e03, 0x020c0602, 0x612a4434, 0x09050d20, 0x08020a06, 0x402a8101, 0x1e2a1d18, 0x0c092216, 0x10130a04, 0xae0f4964, 0x28083e47, 0x001a00e0, + 0x00560026, 0x28ab4f5d, 0x17070726, 0x17161615, 0x2209ab4f, 0x4b022e27, 0x172a0510, 0x37362627, 0x27072737, 0x8c531737, 0x15332905, 0x17072622, + 0x3517021e, 0x2018a84f, 0x28c1866a, 0x09513048, 0x1b0b0710, 0x05954e0f, 0x0a0a2208, 0x1a1c311f, 0x1629100d, 0x0a09020b, 0x183c2b2e, 0x0e07774a, + 0x320d1305, 0x6b45291d, 0x191a0a09, 0x0fa34f09, 0x19cb4e08, 0x19191112, 0x95191211, 0x06524020, 0x0c09060d, 0x120e0e12, 0x272b1503, 0x090b1010, + 0x150b4209, 0x29071f07, 0x02163423, 0x19210809, 0x16292b1d, 0x0f0d0538, 0x04002005, 0x1e001e00, 0xd501c401, 0x10000900, 0x34002e00, 0x33010000, + 0x06d04915, 0x35172726, 0x33072733, 0x4763f283, 0x374e0808, 0x26222335, 0x26263535, 0x27373435, 0x27070137, 0x06273527, 0x40011507, 0x26051555, + 0x2b2a5515, 0x2a2b4040, 0x12190c0a, 0x0a0c1912, 0x0a191240, 0x1e5b0e0b, 0x8d1e8801, 0x0604362e, 0x2b555501, 0x1926090b, 0x55592b52, 0x0531d555, + 0xb5830c14, 0x06130c25, 0x83111931, 0x0c132d0d, 0x78fe1e5c, 0x042a8d1e, 0x31040536, 0x08564b18, 0x0c00c424, 0xf2561500, 0x67062009, 0x17340696, + 0x35231527, 0x35333523, 0x36361717, 0x26343535, 0x32172323, 0x8205895c, 0x0136229d, 0x2c4a82c4, 0x190f0c28, 0xe662ef11, 0x442a2a2b, 0x200b84e1, + 0x057859b9, 0x823c1321, 0x04292e94, 0x12aa0e16, 0x2bcd6219, 0x43192a2b, 0x210d8568, 0x816f1340, 0x0aec5606, 0x16000a27, 0x00001a00, 0x07dc5613, + 0x13233522, 0x34056f4d, 0x37273734, 0x23272701, 0x19019215, 0x25051911, 0xfe47cec4, 0x260882e7, 0xa6011e21, 0x6319d68f, 0x0a3505d7, 0xfec3260a, + 0x121946ba, 0x090b0001, 0x5afe1e21, 0x00d5d553, 0x08437a02, 0x13000933, 0x17250000, 0x27273727, 0x07170707, 0x27170725, 0x08568207, 0x0117372b, + 0x47155000, 0x5e24245e, 0x25011547, 0x84842374, 0x3c997423, 0x5b30b73c, 0x5656083e, 0xb45b3e08, 0x50509665, 0x8d0d6596, 0x824d8f8d, 0x204a8392, + 0x85498237, 0x0717244a, 0x82d50117, 0x8499203c, 0x89612046, 0x823b2057, 0x840d203d, 0x881f2047, 0x09002157, 0x08b98e18, 0x0700033b, 0x1c001800, + 0x27002000, 0x32002e00, 0x00003600, 0x35231513, 0x15233517, 0x05145d17, 0x33023e2c, 0x15021e32, 0x15230515, 0x03823733, 0x820e1121, 0x023b270c, + 0x26263435, 0x13861727, 0xaa2ad527, 0x80fe952a, 0x07b64715, 0x2aeafe36, 0x2b2b562a, 0x6b1c301f, 0x301c6b2a, 0x2b2b2b1f, 0x012a2a55, 0x02830682, + 0x56aaaa3c, 0x1a2f3e23, 0x233e2f1a, 0x56562a56, 0x05540156, 0x561f3624, 0x24361f56, 0x0f82fe05, 0x0a934218, 0x9a820b20, 0x18010021, 0x220ab951, + 0x18072703, 0x280990e7, 0x37323316, 0x2a2bc001, 0x2d02832b, 0x11199595, 0x1d0c0a96, 0x090c1d31, 0x12846b01, 0x40abfe2a, 0x12550140, 0x12210d19, + 0x02201682, 0xe6295786, 0x1000c801, 0x00001600, 0x274b8f25, 0x17372727, 0x95011737, 0x19264a8b, 0x4c1e1e3c, 0x488c401e, 0x13842920, 0x0323a68a, + 0x82001400, 0x333525a6, 0x22230607, 0x2405c449, 0x15062223, 0x244c8211, 0x2b8080c0, 0x2a958409, 0x1911960a, 0x6b019595, 0x82027e2a, 0x2112248d, + 0x8312190d, 0x284682a0, 0x0140005a, 0x00c001a6, 0x2897820c, 0x17030100, 0x35331537, 0x08038233, 0x27371724, 0x01333523, 0x1724a600, 0x17562a56, + 0x2a2a9124, 0xf5fec001, 0x6b842516, 0x1625846b, 0x06002b20, 0x3b821500, 0xeb01eb33, 0x1c000f00, 0x25001f00, 0x2d002900, 0x14130000, 0x2f888206, + 0x34231506, 0x32333636, 0x07173536, 0x07152335, 0x21215782, 0x27538335, 0x17330737, 0x05352115, 0x153f0382, 0xd5152135, 0x08121d11, 0x1d122b0d, + 0x550d0911, 0x1a402b80, 0x26560126, 0x2a53c21a, 0x711fc261, 0x01230562, 0x82eb0100, 0x090d211e, 0x2b360484, 0x31422262, 0xc8c81d22, 0x1f5e221d, + 0x1414174a, 0x802b2b3e, 0xc8822a2a, 0x55003524, 0xc884d501, 0x84823820, 0x27071724, 0x78822315, 0x0735232a, 0x37232527, 0x35230727, 0x10820482, + 0x17072724, 0x04822315, 0x33152322, 0x33209482, 0x33209984, 0x35219983, 0x349e8233, 0x1ea0d533, 0x552b5517, 0xa0011e18, 0x1f0f1019, 0x0f101f13, + 0x22078416, 0x8519100f, 0x100f2110, 0x01211088, 0x262d8260, 0x646b6b64, 0x85b51e17, 0x820f2024, 0x1e102624, 0x100f1f14, 0x22108515, 0x861a1a10, + 0x41a28208, 0x1025072f, 0x00002000, 0x07174101, 0x20076f41, 0x0e384125, 0x8000012d, 0x261a402b, 0x26962a96, 0x41eafe1a, 0x01210a27, 0x060441c0, + 0xc8808025, 0x41de221d, 0x6282091c, 0x2405856e, 0x002100ab, 0x20628228, 0x6b8b1823, 0x33332508, 0x07272615, 0x3d05aa4d, 0x35070627, 0x35363233, + 0x07263435, 0x27222306, 0x80013335, 0x27185580, 0x2b121917, 0x2d4c1113, 0x14103707, 0x1919122b, 0x15151667, 0x40015616, 0x1827176b, 0x3f191180, + 0x8a4c100b, 0x0c0f2b05, 0x4011193f, 0x06e51912, 0x76825006, 0x40008b26, 0xab017501, 0x2005d64f, 0xc8561801, 0x6017200a, 0x352507c4, 0x023e3523, + 0x9a411827, 0x1f752d0f, 0x36202036, 0x1c2b191f, 0x2b2a2b2b, 0x19240582, 0x152115c0, 0x012c0288, 0x20352135, 0x1c213520, 0x2d052131, 0x2a2c1f82, + 0x3121052d, 0x1422151c, 0x14152214, 0x5e180583, 0xab2608d6, 0x0d000900, 0xf3851300, 0x07231526, 0x05352115, 0x0805c050, 0x17313722, 0x2bc08001, + 0xaa015515, 0xd6d680fe, 0x2b565601, 0x2b80012b, 0xc0c0552b, 0x2b846b2b, 0x0004002b, 0x3007ee69, 0x000b0005, 0x00180014, 0x27352500, 0x33151723, + 0x22058211, 0x43070111, 0x07330611, 0x01333523, 0x6e3c5d80, 0x4b3c3980, 0x6a8000ff, 0x826b6b2b, 0x5df93246, 0x1c01e76f, 0xf5fe4b3a, 0xd6805601, + 0x40d66b6b, 0x2695882a, 0x003d00b5, 0x825a0056, 0x68222050, 0x15210a88, 0x05d74432, 0x078f3320, 0x2f0bb268, 0x23060737, 0x37173523, 0x37170727, + 0x27222315, 0x16250782, 0x37322133, 0x20868437, 0x12306800, 0xd9670920, 0x130d2e0b, 0x0e130f10, 0x0e090a0d, 0x0a0f130e, 0x830e870d, 0x1da23b09, + 0x1c1b0807, 0x19a0a019, 0x07081b1c, 0x131d1e1d, 0x1b0b011a, 0x2abb1d13, 0x9a67ab2a, 0x672a2008, 0x0e820eb4, 0x2b09b767, 0x47061d63, 0x75752315, + 0x06471422, 0x13233f83, 0x552a051d, 0x2d310a22, 0x22010000, 0x15150606, 0x35230614, 0x23262634, 0x270d8323, 0x33363433, 0x15163233, 0x2406887b, + 0x36323521, 0x05705736, 0xc0013527, 0x0d111d12, 0x2f048208, 0x121d1156, 0x56080d2b, 0x18c00d08, 0x40011726, 0x0c240e82, 0x80011509, 0x55220782, + 0x1d830d09, 0x08292482, 0x16080d0d, 0x40182617, 0x3316842b, 0x02002b0c, 0x55005500, 0xab01ab01, 0x29000f00, 0x32130000, 0x1c7e6518, 0x1537272e, + 0x15233533, 0x26260733, 0x142214cb, 0x51420282, 0x056b4205, 0x2035202d, 0x2b550a0b, 0x0e553780, 0x88150122, 0x2008821c, 0x851a822b, 0x22122b23, + 0x8037550e, 0x0b0a552b, 0x05450400, 0x00c02806, 0x00140008, 0x822c0020, 0x07ed44fc, 0x200b9173, 0x0add5433, 0x01220b8b, 0xf344eb00, 0xc0fe2505, + 0x090d0d09, 0x4d20db82, 0x20061357, 0xae41184c, 0xb3c02107, 0x2205f044, 0x73080d4d, 0x0f860ea7, 0x2026ff82, 0xe0011500, 0xff82eb01, 0x80824620, + 0x1720ff8e, 0x232ff089, 0x27070622, 0x27072737, 0x15233533, 0x82173533, 0x05c150aa, 0xa9431620, 0x3435240d, 0x43000126, 0x15320887, 0x2b547621, + 0x0e553780, 0x21131321, 0x1e1e0e0e, 0xfe82281f, 0x1e1e2826, 0x0b090e1e, 0x220abc43, 0x4155010b, 0x08200b30, 0x26062441, 0x1e0e0a0b, 0x82291f1f, + 0x83292041, 0x220e2832, 0x21311d12, 0x822b2c05, 0x052c2600, 0x121d3121, 0x6f581822, 0x00052e0a, 0x37000013, 0x15251123, 0x06222123, 0x20a58315, + 0x08a98233, 0x95263429, 0xc0150155, 0x19110001, 0x6b2a6bab, 0x15014019, 0x1219956b, 0xc06b6bc0, 0x03001912, 0x2b004000, 0xd501f501, 0x62000700, + 0x3227050d, 0x14111516, 0x18212306, 0x210d0642, 0xf7440115, 0x01232805, 0x19191280, 0x82c0fe12, 0x19112341, 0x43821119, 0x0e950125, 0x490e1212, + 0x12210554, 0x21148319, 0x05835601, 0x13d5fe26, 0x130dc00d, 0x26084365, 0x000500eb, 0x8211000b, 0x00273066, 0x002f002b, 0x13000033, 0x35231523, + 0x82350533, 0x011522ab, 0x82068323, 0x20b382bc, 0x24808223, 0x35262223, 0x06fa4211, 0x20830720, 0x95290386, 0x016a2a40, 0xfe406a40, 0x200883ea, + 0x18098216, 0x21099642, 0x00848055, 0x40c00128, 0x2b6b6b6b, 0x0783fe40, 0x6b2b4022, 0x089ac018, 0x2a2b1223, 0x21018216, 0x80820200, 0xc001552e, + 0x0f009501, 0x00001b00, 0x23060701, 0x35227d82, 0x6f843523, 0x82071721, 0x077e450c, 0x5dc00130, 0x4040160d, 0xd5121980, 0x408e0d16, 0x0282402a, + 0x83000131, 0x40408012, 0xc3121911, 0x402b4040, 0x82040040, 0x016b284f, 0x00ac01d5, 0x45070003, 0x2f53074e, 0x27252605, 0x17371737, 0x22058403, + 0x82c0d501, 0xa1fe2700, 0x5a2d1e4b, 0x0584791f, 0x2b6b0126, 0x4c802b80, 0x1e221082, 0x1183ddfe, 0x4c931e20, 0xfb861320, 0x4c8a3720, 0x4a82eb20, + 0x8272c021, 0x1e5b2239, 0x94058478, 0x05d6464a, 0xe782d520, 0x2d001a24, 0x55183600, 0x14270a81, 0x22230606, 0x46132626, 0x272406d0, 0x37072726, + 0x2d053a5e, 0x15150606, 0x34352633, 0x17333636, 0x77512337, 0x17ab2605, 0x26181826, 0x3f058517, 0x191215c0, 0x0f0e1013, 0x200f3964, 0x1b452811, + 0x07321310, 0x0a152214, 0x120e281e, 0x80010e12, 0x31082888, 0xc3fe2617, 0x12661119, 0x0607081f, 0x0304796c, 0x1f080e13, 0x110f9012, 0x6a142214, + 0x0e0d1340, 0x00070012, 0x012b0015, 0x00e001d5, 0x00170003, 0x0b490021, 0x00312305, 0xab183700, 0x032c16e3, 0x17331507, 0x33151616, 0x35230735, + 0x35222382, 0x07861733, 0xab181520, 0x912810d1, 0x12ae2b96, 0x15a02b15, 0x2b210082, 0x21008216, 0xab18ea2b, 0x012d0dbe, 0x46356b4b, 0xb5132007, + 0x1615154a, 0x18038240, 0x220a7c72, 0x82100009, 0x37002191, 0x41088742, 0x232f0529, 0x26343537, 0xeb152323, 0x19191280, 0x822a8012, 0xabab2106, + 0x40310882, 0x2a011219, 0x80fe1912, 0x2b951219, 0x9519126a, 0x053d5800, 0xc001b53a, 0x0e000900, 0x4e002300, 0x37010000, 0x27273436, 0x030f2226, + 0x17373315, 0x30058141, 0x33363435, 0x35363632, 0x37272634, 0x26251616, 0x23108226, 0x023e3736, 0x23281082, 0x06230622, 0x26262706, 0x33200e82, + 0x08069a44, 0x020e074d, 0x17161415, 0x0c179201, 0x230d1e0c, 0xc41f160d, 0x1f21c45b, 0x0d091a31, 0x1d10090d, 0x200c0f13, 0xcdfe1411, 0x23171210, + 0x11180b12, 0x12141417, 0x07120501, 0x01050206, 0x18181f10, 0x24181727, 0x10180a12, 0x22010a0c, 0x82240c17, 0x0d4f0842, 0x5ac51e16, 0x211879c4, + 0x09080d12, 0x090e090d, 0x20050d07, 0x09451c0a, 0x1a141118, 0x0c050812, 0x0e07060c, 0x0501070d, 0x01071106, 0x1d110d0f, 0x131b1412, 0x0b0c0408, + 0x04090506, 0x40000300, 0xed011500, 0x1a00d501, 0x29002400, 0x41250000, 0x3521082f, 0x05ff4733, 0x15163226, 0x21352315, 0xfd86f182, 0x07072c08, + 0x35230717, 0x95000137, 0x12191912, 0x2baa2b15, 0x2b191215, 0xd895d6fe, 0x0f06060f, 0x0f061206, 0x712d711e, 0x0111192b, 0x6319122b, 0x802305c4, + 0x8441d62b, 0x25208219, 0x712e713d, 0x77820500, 0xc3014024, 0x81828001, 0x0b000724, 0x7f821500, 0x33130022, 0x9f456882, 0x25232c05, 0x17323637, + 0x07141617, 0x82072707, 0xeb40217a, 0x952c0082, 0x0f400195, 0x10061107, 0x3c100606, 0x01276282, 0x2b552b2b, 0x83182ad5, 0x84dd820f, 0x01003076, + 0x40004400, 0xc001bc01, 0x00001100, 0x4a072701, 0x072205fa, 0xdb4b3717, 0xbc012805, 0x6656662b, 0x8567672b, 0x3b012506, 0x76763b4a, 0x07870482, + 0x40268f82, 0xd9012000, 0x9182d501, 0x2c002025, 0x83370000, 0x053542fc, 0x23204b82, 0x48180383, 0x1727070e, 0x37173727, 0x82172717, 0x432720a3, + 0xef2405db, 0x2b2a0184, 0x2c081441, 0x47af1219, 0x5a2e1e4c, 0x1e22fb1e, 0x24028722, 0x2b5ed655, 0x07184188, 0x11d5fe24, 0x22820b19, 0x3c1e5b22, + 0xaf59228a, 0x00eb2808, 0x001b0013, 0x552b0023, 0xa04d12f7, 0x17372806, 0x27270707, 0x86133737, 0x58c02007, 0x078607ff, 0x2a2b1d2d, 0x3bb0802b, + 0x3b1a1b3b, 0x861b1a3b, 0x11ec5507, 0x6b6b8b24, 0x23867020, 0x869afe21, 0x34878228, 0x010f000f, 0x00d301eb, 0x001f0014, 0x00430028, 0x26340100, + 0x08b25b27, 0x22230624, 0x0e822322, 0x3533172b, 0x27022e34, 0x27171616, 0x05e94236, 0x82070721, 0x26223b19, 0x34343526, 0x01372735, 0x21152707, + 0x033e3435, 0x01173233, 0x060d0f40, 0x6444080e, 0x02013105, 0x0b091001, 0x281a04a7, 0x1a121630, 0x1412f904, 0x08211782, 0x82168249, 0x5c2a0807, + 0x1ea6011e, 0x18aafe4a, 0x112d2e27, 0x5501100b, 0x02112917, 0x18271703, 0x10172717, 0x40ed230f, 0x0e141c12, 0x141f0c03, 0x148209f9, 0x30121322, + 0x39821782, 0xfe1e5c28, 0x044a1e5a, 0x1d821140, 0x0002073e, 0x00150003, 0x01f9012b, 0x000900d5, 0x0013000f, 0x17231300, 0x27173707, 0x13272337, + 0x073b0482, 0x07272717, 0x84a2b717, 0x33848432, 0xdd33a284, 0x42495928, 0x1627221f, 0x7d2b0110, 0xfe2906c3, 0x2f408056, 0x4980fe65, 0x08dc4537, + 0x54829520, 0x39002d3b, 0x00004200, 0x23022e01, 0x07060622, 0x1e331523, 0x36323302, 0x35333736, 0x06004707, 0x36343523, 0x28038233, 0x16161736, + 0x16321515, 0x0b826b15, 0x23153722, 0x332e1a82, 0x94011632, 0x263f2a05, 0x052a3f26, 0x09884141, 0x080d952f, 0x0d0d0856, 0x0d170e08, 0x0d081410, + 0x07a45630, 0x0c2a052e, 0x010c0909, 0x223a2415, 0x2a243a22, 0x4a330686, 0x090d0d09, 0x150d0840, 0x030b150d, 0x13101a02, 0x5720080d, 0x44220622, + 0x1c821515, 0x00030034, 0x0120002b, 0x00d501e0, 0x00430017, 0x3700004a, 0xf918022e, 0x736408f9, 0x15062c05, 0x37171614, 0x27071414, 0x65353436, + 0x142007da, 0x3224d383, 0x22061737, 0x0808785b, 0x021e3221, 0x17273707, 0xfa371737, 0x23213722, 0x3922233a, 0x072d0223, 0x26181e2e, 0xe91c2517, + 0x50012a01, 0x07830792, 0x02030226, 0x0509050c, 0x2b0bce69, 0x40d55050, 0x802a5b1b, 0x22392302, 0x212c3e82, 0x1c0e2237, 0x18261725, 0x53072e1e, + 0x0c202a82, 0xc4423282, 0x2350820b, 0x2c4d3b21, 0x22084186, 0xd5401b87, 0x002a5b50, 0x00340001, 0x02c00100, 0x00350000, 0x26222100, 0x26272726, + 0x17173636, 0x18171716, 0x20108286, 0x38119115, 0x01020e14, 0x303f2215, 0x0603400d, 0x1311080f, 0x0f101e08, 0x15100b0b, 0x21048610, 0x0e83160f, + 0x3e2e1b3b, 0xa220301b, 0x02070f09, 0x4b130606, 0x0f0f0bfb, 0x0be5bb0b, 0xe50b1010, 0x210583c5, 0x058385c5, 0x3e24da24, 0x90821b2e, 0x35003524, + 0x9082cb01, 0x98825820, 0x8b482620, 0x36362805, 0x0e163031, 0x6e222303, 0x17240556, 0x33353636, 0x240b306b, 0x35071735, 0x05124622, 0x37363622, + 0x0628c482, 0x35262223, 0x30273435, 0x8205bd71, 0x16162111, 0x23083582, 0x13010637, 0x15161f08, 0x01081310, 0x180e0701, 0x040d0f13, 0x1f14020a, + 0x40211b08, 0x2a493820, 0x2038492a, 0x38080783, 0x321d5555, 0x1b211626, 0x02162208, 0x0f0c0405, 0x140b1912, 0x03141c1c, 0x0a080e07, 0x200b0a17, + 0x04011915, 0x1f160f0d, 0x1d130b0b, 0x08121d21, 0x0413220a, 0x3b130e14, 0x83408724, 0x55352e07, 0x26163656, 0x3c231d32, 0x03140f13, 0x3437820b, + 0x12151219, 0x160a040e, 0x05080911, 0x1d070309, 0x16331913, 0x20f18211, 0x20e98260, 0x20f182c0, 0x2107823e, 0xe24c0622, 0x34232106, 0xfe46ca82, + 0x99118205, 0x1e142608, 0x3e323302, 0x2ced8202, 0x0ba50126, 0x1d120b0f, 0x22131511, 0x13864115, 0x40312008, 0x31402424, 0x5501101b, 0x117b0b0f, + 0x2416121d, 0x0be60318, 0xa60b0f0f, 0x10100bd0, 0x41b0d00b, 0xd520098c, 0x1b202883, 0x8b223082, 0x47780f0b, 0x0012240a, 0x82290022, 0x213524a5, + 0x46153311, 0x212b07e3, 0x15151632, 0x06062207, 0x64161415, 0x272d0830, 0x17371523, 0xab012737, 0xd6d6aafe, 0x06bd7911, 0x74824020, 0x02829f82, + 0x6e1d112f, 0x1e3d2d79, 0x8000013d, 0x192b00ff, 0x05686112, 0x182b8021, 0x250b154b, 0x3d2d7880, 0x7d923c1f, 0x06141524, 0x184b2123, 0x23152507, + 0x37352111, 0x2a0a3350, 0x36363233, 0x37170707, 0x71233517, 0xd6240982, 0x2a5601d6, 0xe0205c8b, 0x2d217c82, 0x217e8279, 0x7d851912, 0x00ff2b23, + 0x066d7a80, 0x2a089f84, 0x3c1e3c5c, 0x0600792d, 0x15001500, 0xd501d501, 0x13000800, 0x27001d00, 0x39003000, 0x37130000, 0x17323637, 0x05070717, + 0x5b170727, 0x0720065e, 0x37300783, 0x17073523, 0x06072327, 0x16163117, 0x17273333, 0x0c821f82, 0x27011726, 0x17232326, 0x69089682, 0x06161f7b, + 0x1a200618, 0x220b0116, 0x0c18304a, 0x80040614, 0x06150c20, 0x5555651e, 0x0b125b80, 0x0b110509, 0x1d24524e, 0x0c092575, 0x1901230a, 0x4c180c1c, + 0x1e752543, 0x25336701, 0x2c350a0a, 0x2b395122, 0x090b0c4e, 0x0da10c0a, 0x552b3d0b, 0x111e8056, 0x8e0b0912, 0x161d7516, 0x4515140f, 0x142f1501, + 0x751d166f, 0xdf650300, 0x82092008, 0x522108b9, 0x14250000, 0x35230606, 0x35363632, 0x36363425, 0x06221533, 0x07371506, 0x16140606, 0x32161617, + 0x65d18236, 0x2721058e, 0x06896537, 0x16280891, 0x27070616, 0x27263636, 0x01291a86, 0x233a23eb, 0xfe1a2c1a, 0x2207854a, 0x831a6276, 0x44402e00, + 0x07971a41, 0x08160807, 0x088c0f5f, 0x22078208, 0x84930f7c, 0x0f93220f, 0x2b0f8475, 0x0c070da2, 0x080d100f, 0x57070d08, 0x95201083, 0x20203f82, + 0xd6204882, 0x39250786, 0x44411a62, 0x224c8440, 0x82160797, 0x825e2021, 0x07162348, 0x48820808, 0x08214e82, 0x2d488308, 0x07070816, 0x282811a3, + 0x210c1010, 0x48820c21, 0x003b2882, 0x00400002, 0x01c00155, 0x000500c0, 0x3700000e, 0x27352115, 0x37172707, 0x82153317, 0x01403907, 0x6b55c080, + 0x556b6b55, 0xeb6354c9, 0x76962096, 0x559540d6, 0x4f759cc0, 0x220a9b7d, 0x182b001f, 0x2e081b7c, 0x23371737, 0x23153335, 0x07270735, 0x4c331616, + 0x2e210527, 0xd7211902, 0x2c00380c, 0x0f213b4d, 0x22464671, 0x46622b6b, 0x375d1d5e, 0x211911ab, 0x4f744d3b, 0x0121068a, 0x300c82d5, 0x70262a2c, + 0x6a2a463b, 0x5e3b6121, 0x1119332a, 0x233483ab, 0x090c76fe, 0x00212485, 0x30748204, 0x0100022b, 0x002800d5, 0x00440038, 0x25000050, 0x0c414634, + 0x27261735, 0x3435022e, 0x36173736, 0x36362737, 0x021e3233, 0x18071617, 0x22186bdb, 0x18061437, 0x85080c65, 0x08718381, 0x46341d30, 0x1d141e28, + 0x1113192d, 0x82151279, 0x221e3516, 0x021c2e3c, 0x3b225617, 0x2d0c0c2d, 0x3b22223b, 0x2c0c0c2c, 0x2016223b, 0x1f161620, 0x0e720a1f, 0x02f92307, + 0x3c460203, 0x2c270806, 0x24394a29, 0x0d221704, 0x1e223d2f, 0x0c791635, 0x13118209, 0x213a2b19, 0x2b191a07, 0x182c1c1c, 0x1c1c2c18, 0x8496192b, + 0x16162340, 0xd7583620, 0x0a6d7d06, 0x18001128, 0x23010000, 0x044a2327, 0x4f212006, 0x072b0558, 0x33153727, 0xab012315, 0x4f802bab, 0xbc210843, + 0x24008255, 0x192b8001, 0x050b7d12, 0x12d52308, 0x5556eb19, 0x06002b40, 0x35006b00, 0xd5019501, 0x3f003100, 0x57004b00, 0x71006300, 0x26250000, + 0x394c2726, 0x07062307, 0xbc4d022e, 0x17162305, 0x364c0606, 0x33162505, 0x30313632, 0x4109a944, 0x1e240554, 0x17061703, 0x8b0a6551, 0x8a37200b, + 0x3e272717, 0x16163703, 0x4d821415, 0x01263a08, 0x030a0467, 0x16151d0d, 0x26291114, 0x29260b0b, 0x15161411, 0x0a030d1d, 0x0e100604, 0x18182717, + 0x18181d1d, 0x100e1727, 0x10180aa6, 0x18070102, 0x0e011117, 0x0707040e, 0x20038204, 0x05f8411c, 0x86170c21, 0x0421080f, 0x18171101, 0x10020107, + 0xca0b0a18, 0x12030c03, 0x20294737, 0x2a381d20, 0x201d382a, 0x37472920, 0x23148212, 0x11191104, 0x0c215182, 0x825d820c, 0x3620080a, 0x213a2e10, + 0x02030a08, 0x273b2916, 0x07096804, 0x060a0a06, 0x113b0907, 0x06060504, 0x3b110405, 0x6c2d1187, 0x16293b27, 0x080a0302, 0x102e3a21, 0xffcb1807, + 0x0013210a, 0x0d2bf618, 0x1e323523, 0x092d4202, 0x971d2126, 0x213b4d2c, 0x0a596018, 0x971d4e3a, 0x4d3b21d5, 0x20000500, 0x00022b00, 0x06000002, + 0x1f000a00, 0x2f002700, 0x2d089976, 0x23353327, 0x020e1437, 0x032e2307, 0xad543435, 0x07372805, 0x37371717, 0x73232727, 0x24080660, 0x12195695, + 0xaa2a1912, 0x1b12f5aa, 0x08a0081b, 0x19121b1b, 0x21213a2c, 0x68192c3a, 0x0e0d1d1d, 0x400e1d1d, 0x05747314, 0x19115530, 0xa02a2719, 0x16222f1e, + 0x22160505, 0x24831e2f, 0x0d222c82, 0x29840d0e, 0x43067173, 0x602206f9, 0x9282ab01, 0xd6820c20, 0x3636153f, 0x05263435, 0x11173315, 0x172b0107, + 0xfefe1e1e, 0x016b6b55, 0x2e0cac56, 0x0a2e1c1c, 0x200a8280, 0xed4c186b, 0x8221200c, 0x64681834, 0x3205260a, 0x021e1716, 0x05b75b37, 0x26260625, + 0x18362627, 0x340ac998, 0x0906fcfe, 0x211a0401, 0x090a070e, 0x242e1706, 0x010a0106, 0xd39818d5, 0x076f300a, 0x0b1b1806, 0x07070901, 0x27120209, + 0x6f0b0721, 0x112d0a1e, 0x1f001b00, 0x00002300, 0x23353325, 0x20038727, 0x22698221, 0x66070111, 0x2a0806c9, 0x17330137, 0x33351523, 0x19670117, + 0x84591544, 0x55c49915, 0x19114401, 0x1c1e58fe, 0x71ef1119, 0x04adfe1e, 0x2a442e2a, 0x82152bd5, 0x19553301, 0x01bcfe11, 0xee1c1e6c, 0x1e711912, + 0x402b1301, 0xb9672b2b, 0x0024240c, 0x82320028, 0x125c18df, 0x3507230e, 0x654b1533, 0x8233200a, 0x15232382, 0xb45f2317, 0x23152205, 0x67098215, + 0xdc260cbc, 0x16080d15, 0x04840d08, 0x16562b29, 0x202b5516, 0x67401520, 0xd5220dbd, 0xad6b1515, 0x2a092807, 0x0a165616, 0x84562016, 0x01802c8b, + 0x004001cb, 0x0013000f, 0x8240002b, 0x2223248b, 0x18151506, 0x820a4971, 0x8f07206c, 0x2481828d, 0x35331523, 0x18048205, 0x221029cd, 0x83402b01, + 0x82402068, 0x2b13258f, 0x090d752b, 0x08200983, 0x202c1382, 0x2a012b2b, 0x0c60402a, 0x4a402b09, 0x01212282, 0x06074c40, 0x0d085625, 0x84354060, + 0x820a82c0, 0x400b31c5, 0x2015360b, 0x150d0935, 0x20080d20, 0x05000d09, 0x20082b64, 0x24a78203, 0x00300022, 0x82a9823a, 0x6d7d187a, 0x2207290f, + 0x1515030e, 0x2e343521, 0x2a060f44, 0x35023e07, 0x17262634, 0x82151616, 0x230982b0, 0xd5800002, 0x08db5b18, 0x27172308, 0x2e2d1117, 0x55011827, + 0x2c2e2718, 0x11110f4f, 0x1322150f, 0x0e412213, 0x21152b11, 0x2b2b4001, 0x7b18176b, 0xc0200a73, 0x2374261a, 0x55000331, 0xab011500, 0x0900d501, + 0x2d001d00, 0x4d370000, 0x07230590, 0x4c371723, 0x16280879, 0x17371517, 0x27363635, 0x2a0ed555, 0x123131cf, 0x13133d31, 0x4cca313d, 0x17260768, + 0x14808014, 0xcc7aab17, 0x25dc280a, 0x3c273d25, 0x5c12273c, 0x212907f5, 0x2ba51739, 0x3917a52b, 0x4d2582a1, 0x08820536, 0x0001003a, 0x016b002b, + 0x009501c0, 0x01000019, 0x3307020e, 0x33352315, 0x3523032e, 0x32087582, 0x37363617, 0x01153327, 0x232f1884, 0x2b802b05, 0x42342104, 0x40542e25, + 0x1d371213, 0x3c01953b, 0x283e3011, 0x3e242a2a, 0x222b1a2f, 0x3b27283d, 0x46953b14, 0x03220a29, 0x52820f00, 0x13210322, 0x0ba97118, 0xea150134, + 0xa0406a01, 0x161f1f16, 0x01202016, 0x01aafeab, 0x6e46d656, 0x0b002907, 0x55005500, 0x00020002, 0x22061651, 0x5513000f, 0x3628086f, 0x00003d00, + 0x23353313, 0x07200383, 0x35200782, 0x56180382, 0x13200761, 0x530ec44a, 0x0331075c, 0x23063533, 0x15272722, 0x34352633, 0x56565537, 0x84028480, + 0x2d0a8204, 0x1c311d40, 0x1e1d311c, 0x301d1d30, 0x00821513, 0x0a564b32, 0x801e220c, 0x01010f3a, 0xaafe5655, 0x2a565656, 0xd6260382, 0x1d550156, + 0x2c881e30, 0x1516ab2e, 0x2c00ff55, 0x569c0f01, 0x0a0c221e, 0x2008f384, 0x01d50140, 0x001800c0, 0x2500001f, 0x23061415, 0x21151723, 0x22233735, + 0x34353526, 0x15333336, 0x3a0e8223, 0x35332707, 0x01331533, 0x401119d5, 0x1500ff15, 0x19191140, 0x01abab11, 0x826b6b56, 0x40eb3367, 0x2b151912, + 0x1219152b, 0x2b1912ea, 0x6b2b40ea, 0x5a829595, 0x3700552a, 0xc901ab01, 0x2b001500, 0x17225a82, 0x1b482723, 0x37332306, 0x03830733, 0x25231182, + 0x84172327, 0x250f820b, 0x34353632, 0x25822326, 0x49011725, 0x4338171b, 0x382b0558, 0x103c1b17, 0x160d0d16, 0x85f6fe10, 0x8b3c2007, 0x5e95311b, + 0x08090d5e, 0x155e5e0d, 0xd6152b2a, 0x152a2b15, 0x08211082, 0x18108209, 0x180cc164, 0x4c087785, 0x342806b8, 0x2703022e, 0x17371737, 0x200a6546, + 0x05b5784d, 0x421e6024, 0x64181e42, 0xe03512c8, 0x41411e60, 0x0003001e, 0x0140006b, 0x00ab0180, 0x001a000f, 0x1151441e, 0x15330322, 0x2725e682, + 0x15333527, 0x260a8217, 0x122a5501, 0x83121919, 0xb59c2c04, 0x05160eb6, 0xd5162a36, 0x18ab01d5, 0x2b09694f, 0x112b00ff, 0x5656b60e, 0x04002bea, + 0x27080461, 0x0013000f, 0x002c0016, 0x2b10007f, 0x35331533, 0x37330725, 0x26070622, 0x2107407c, 0x06441716, 0x43962005, 0x68370af9, 0x6ad5feab, + 0x18119bd5, 0x11180707, 0x1e0f1b11, 0x311b1c31, 0x7e1b0f1e, 0x20080cfc, 0xc0eaabab, 0x090910b6, 0x101a1110, 0x19282515, 0x15252819, 0x00111a10, + 0x00550001, 0x01f5012b, 0x218f82d5, 0x69822500, 0x24075147, 0x27073317, 0x9a6a1833, 0x37362109, 0x0809ff6e, 0x01222329, 0xab281f47, 0x223d301c, + 0x1d2f3b20, 0x60604b03, 0x3823034a, 0x223a2421, 0x1214413f, 0x16161f06, 0x08162020, 0x4622206d, 0x163405b0, 0x60253b2a, 0x1e352360, 0x25273c22, + 0x12133c62, 0x1f160d0b, 0x1f242482, 0x3f000400, 0xcd207d82, 0x15297d82, 0x43002c00, 0x00006700, 0x05e84d13, 0x06141529, 0x36302331, 0x83263435, + 0x33372177, 0x33201589, 0x23211589, 0x22169523, 0x84363025, 0x22232439, 0x82070706, 0x1e172104, 0x2505f351, 0x33363437, 0x5a821632, 0x8931063b, + 0x0a0b0306, 0x0a082008, 0x8a06030b, 0x0b0a0305, 0x0b092009, 0x2005030a, 0x84188245, 0x0818820c, 0x1c012032, 0x1d120201, 0x03241911, 0x0d0ae017, + 0x3d290601, 0x283e2524, 0x090c1904, 0x01010c09, 0x0e096b01, 0x1e1c0807, 0x11110f0b, 0x1c1e0b0f, 0x090e0708, 0x0a2311a3, 0x8204100c, 0x202f0855, + 0x090fdd18, 0x23213824, 0x09e7263c, 0x03090d0b, 0x04000a0d, 0x2b004000, 0xd5019501, 0x0f000700, 0x2a001700, 0x27130000, 0x17173737, 0x48150707, + 0x272006da, 0x2706ea48, 0x37363417, 0x27153327, 0x24050241, 0x022e1517, 0x05d04897, 0xd8481420, 0x1d3a3706, 0x1d0d0e1d, 0x20950d1d, 0x3c953b1b, + 0x301b1915, 0x26442b1f, 0x1f864101, 0xd848d520, 0x0d8c2206, 0x3328840e, 0x204f2c15, 0x1a3c953a, 0x41232240, 0x112e1033, 0x05005541, 0x02218d83, + 0x2b8d8200, 0x0013000b, 0x0023001b, 0x25000036, 0x200ab859, 0x219ba825, 0x8d620002, 0xa4fe2005, 0x2bd521a4, 0x96202d83, 0x0622a9a9, 0x474f2b00, + 0x180b2006, 0x2508bc7c, 0x37000053, 0x69181614, 0x052008a5, 0x07200b8a, 0x238b0b8a, 0x178b1720, 0x26222328, 0x36343526, 0x49553736, 0x1e172705, + 0x06141502, 0x524d6b06, 0x00012107, 0xc0200987, 0x40200887, 0x4a330890, 0x1f3620d5, 0x101d2e1b, 0x3520233c, 0x27190524, 0x182b1a17, 0x200f0d7c, + 0x0e5a5d5e, 0x78350f87, 0x1d20361f, 0x1e042132, 0x1f301c23, 0x19291b02, 0x001a2b1b, 0x24e88205, 0x01d5012a, 0x23e686d5, 0x004f003f, 0x4c06dd54, + 0xe958077e, 0x07262206, 0x09126632, 0x27210b8b, 0x20188233, 0x06964931, 0x36343123, 0x2b0f8e17, 0x24057e01, 0x3c232035, 0x1b2e1d10, 0xd5208282, + 0x17227682, 0x4e4c1727, 0x86e22006, 0xc00d21ac, 0x04831083, 0x08965e25, 0x83080d0d, 0x6a012a04, 0x231c301f, 0x3221041e, 0x28f5821d, 0x191b2b1a, + 0x0cd31b29, 0x22318309, 0x99400c09, 0x20d48408, 0x20d4842b, 0x24d68213, 0x001f001b, 0x0f047d25, 0x07022e26, 0x15231533, 0x17230382, 0x57333523, + 0xd14505d3, 0x96972110, 0x40270082, 0x3d574040, 0x454b1f1e, 0x6a2b12d9, 0x402b152b, 0x1e3d732b, 0x921e4b1e, 0x08964f74, 0x83093a46, 0x24708374, + 0x15333527, 0x0a6d6517, 0x78827a93, 0x6a964024, 0x00822b2a, 0x55462a20, 0x2b6a2211, 0x827d8280, 0x2b2b2d7e, 0x0a002a2a, 0x6b006b00, 0x95019501, + 0x146c7f18, 0xc07e0020, 0x4227200b, 0xc3420a93, 0x8a35200b, 0x8a032017, 0x42178b0b, 0x178b0bcf, 0x2f961320, 0x20079a42, 0x11e4420c, 0x4210ec42, + 0x109810eb, 0x090deb29, 0x080d0d08, 0x42950d09, 0xb4200644, 0x0d210e85, 0x210f86a2, 0x0886f7fe, 0x5d42a220, 0x9f5e2006, 0x0a7d7220, 0x24001324, + 0x2e423f00, 0x36342412, 0x82151737, 0x14152be7, 0x2e221717, 0x37351702, 0x75483536, 0x23262305, 0xe0503523, 0x14152105, 0x12736e18, 0x1216d738, + 0x06121943, 0x2f3e230f, 0x0650c01b, 0x1e20090d, 0x134b150c, 0x1083172b, 0x36291722, 0x3b11db41, 0x16381fd5, 0x19111642, 0x0f070878, 0x863e2f1b, + 0x0a087829, 0x260c0916, 0x0c0b2910, 0x23240f82, 0x1d2e3921, 0x340a1079, 0x001b000d, 0x00370029, 0x00530045, 0x006f0061, 0x1300007f, 0x059a4635, + 0x20056d6a, 0x07225317, 0x17140625, 0x50173216, 0x33200561, 0x2005c944, 0x06d54c07, 0x08e14918, 0x3637342b, 0x16171732, 0x06060714, 0x822f8217, + 0x06025c30, 0x45792520, 0x4a538d0c, 0xeb200f8a, 0x2c07bc41, 0x06061e9d, 0x1e061206, 0x11060707, 0x08967854, 0x9f41de20, 0x86912006, 0x2323831d, + 0x1e0707ec, 0x06212982, 0x21058206, 0x2a88bbfe, 0x3a835620, 0x22834082, 0xeb4b8e20, 0xab01210a, 0x38202288, 0x07243786, 0x4e070611, 0xaa207887, + 0x20058079, 0x20258209, 0x221f89ff, 0x82cd0106, 0x89758663, 0x2087822c, 0x84608212, 0x2c012127, 0x2322658a, 0x97540b00, 0x09664108, 0x69005d2a, + 0x81007500, 0x99008d00, 0x222b6a41, 0x41262725, 0xa27a0a5c, 0x3a17220d, 0x05ac5305, 0x27262623, 0x05ef7726, 0x460b5446, 0x7f412f6c, 0x9afe211e, + 0x200a7841, 0x08484153, 0x20037332, 0x202e342e, 0x1d0d0803, 0x351d2032, 0x220d1728, 0x4611b843, 0x93411a9d, 0x4155201f, 0x78200b88, 0x0b305a87, + 0x2007080d, 0x04042639, 0x1d312411, 0x600d080b, 0x200d267b, 0x17cf460c, 0x00050029, 0x0120002b, 0x82d501c0, 0x00412907, 0x00750063, 0x1300007b, + 0x2205c577, 0x42232634, 0x152007e6, 0x15260886, 0x33331614, 0x0d681715, 0x72322005, 0x22210560, 0x89158506, 0x3335232b, 0x1c843517, 0x15213f87, + 0x058e4114, 0x32084c55, 0x15333527, 0x15021e14, 0x34342315, 0x023e3435, 0x82343007, 0x40eb2211, 0x07dd4f0a, 0x400b0822, 0x1930c283, 0x152b1512, + 0x0d081912, 0x0725330d, 0x25070909, 0x55220585, 0x1d83e055, 0x92446b20, 0x190a2e05, 0x19125512, 0x400a0c0a, 0x090d0a15, 0x24088255, 0x8b015520, + 0x071b4120, 0x090d2037, 0x12a00d08, 0x75205519, 0x0da01219, 0x4b0d0908, 0x09070709, 0x22048420, 0x410b40a0, 0x043a0843, 0x0f150e0a, 0x1919118b, + 0x150f8b11, 0x0b040a0e, 0x0d110d0b, 0x040b080d, 0x68820205, 0x12be113d, 0x0600200e, 0x55001500, 0xab010002, 0x28000d00, 0x46003a00, 0x66005600, + 0x4d250000, 0x322f06ae, 0x14151516, 0x30330706, 0x3e31023c, 0x55233502, 0x23280590, 0x17161614, 0x27021c30, 0x2106bd48, 0x42653233, 0x79172005, + 0x232705ac, 0x37363435, 0x68373636, 0x17270eeb, 0x34352626, 0x18262237, 0x3707e380, 0x130db501, 0x120e0d13, 0x12151812, 0x2015111d, 0x151f1616, + 0xeb121d11, 0x2305105e, 0x0f0e0e0f, 0x37290382, 0x13561815, 0x6f301410, 0x0ab76217, 0x211b9c2f, 0x060c060d, 0x101b4528, 0x0d13a013, 0x33438235, + 0x130d350e, 0x0a0d0a4b, 0x131f1503, 0x161f1f16, 0x03151f13, 0xab3a0e82, 0x18172717, 0x11051727, 0x29171729, 0x0f180510, 0x3c3c1a2e, 0x0b081e12, + 0xdd4c7110, 0x0de93a0a, 0x181d1f34, 0x080e1401, 0x003c121e, 0x00400002, 0x01bf0140, 0x000f00c0, 0x116f5235, 0x3106032f, 0x27272223, 0x15062326, + 0x14170607, 0x2cfc8233, 0x22071617, 0x22232306, 0x37353435, 0x52108536, 0x22080972, 0x33191911, 0x02073102, 0x01020135, 0x01030121, 0x10020324, + 0x01010602, 0x53068201, 0x07300803, 0x52035403, 0xfe280d7c, 0x7a0701d6, 0x4e010102, 0x032c0382, 0x01020623, 0xc6020106, 0x06c60707, 0x5c249982, + 0xa2013e00, 0x1f2b9982, 0x00002800, 0x27260625, 0x82072626, 0x022e2e05, 0x16373636, 0x36361716, 0x06171617, 0x24098206, 0x03070606, 0x08148326, + 0x01020e3f, 0x1121106c, 0x17122211, 0x22200d1d, 0x232e1406, 0x130d1f16, 0x18301425, 0x1c051518, 0x131a0917, 0x2516026b, 0x1a100316, 0x010f4f1d, + 0x08010707, 0x210c050a, 0x253c4849, 0x010f0102, 0x08028204, 0x2c0f2226, 0x180a262e, 0x1601122d, 0x02192818, 0x0d192215, 0x40000300, 0xd5014000, + 0x1d00eb01, 0x32002900, 0x33130000, 0x20052562, 0x24471835, 0x0619570a, 0x23353323, 0x0a274a13, 0x17071722, 0x22057b6c, 0x18d62a6b, 0x260a2a47, + 0x19191259, 0x476a6a12, 0x893c07bf, 0x8484221e, 0x01551e22, 0x80404095, 0x13191280, 0x19131818, 0x12d6fe12, 0x55012b19, 0x25070768, 0x2b221ed5, + 0x9a531e22, 0x01152205, 0x228d86eb, 0xab4a003e, 0x1813208f, 0x220d617d, 0x18363233, 0x9c0e8f57, 0x06ba26a7, 0x1b2b1a09, 0x07067b1b, 0x8b1e3a22, + 0x2005774e, 0x21b8831f, 0xb8966a6a, 0x7badfe21, 0x09260b0c, 0x381e3a06, 0x3885161f, 0x03003508, 0x55001c00, 0xab01e501, 0x4f004300, 0x00005b00, + 0x22272601, 0x26070615, 0x34272607, 0x22070623, 0x17060631, 0x16163314, 0x36373217, 0x26273437, 0x36372627, 0x17210882, 0x200f8216, 0x2a168217, + 0x06060716, 0x16170607, 0x82311617, 0x35322517, 0x30272636, 0x690b7a52, 0x26080c7d, 0x01302b9b, 0x33330507, 0x30010705, 0x1d2b012b, 0x381c0106, + 0x0d01011b, 0x1112010a, 0x04010202, 0x74370102, 0x82010136, 0x02022808, 0x02091109, 0x820d0a01, 0x011c3121, 0xe6262307, 0x11181811, 0x83171711, + 0x10181810, 0x24080b82, 0x09148e01, 0x070b0c01, 0x010c0b07, 0x7f411409, 0x1b15013f, 0x13120109, 0x09070101, 0x03010201, 0x19010101, 0x20048219, + 0x330c8203, 0x01030805, 0x01121301, 0x01151b09, 0xcc387f48, 0x1a13131a, 0x0029038b, 0x0030000d, 0x01d1012b, 0x14bd4ad5, 0x8f008327, 0x00009b00, + 0xd8891825, 0xb4891822, 0x9769180b, 0xd96c180b, 0x8b478a0c, 0x8340182f, 0x8b23960c, 0x8a072047, 0xa8012d23, 0x11181811, 0x4a181810, 0x0f15150f, + 0x4c280392, 0x0d13130d, 0x0d12120d, 0x4d24079e, 0x0b10100b, 0x482c0392, 0x090e0e09, 0xd80d0d09, 0x17111117, 0x04200383, 0x5b206687, 0xb6200887, + 0x0e220885, 0x65826016, 0x12216983, 0x2008875b, 0x211190b6, 0x12876c01, 0x6f87b220, 0x0b105b24, 0x0c830f0c, 0x850fb621, 0x560f2208, 0x056b4d0d, + 0x03000d22, 0x08369218, 0x13000a39, 0x00001700, 0x33072701, 0x33153307, 0x33273335, 0x17072733, 0x83173123, 0x2325080f, 0x95955501, 0x56955227, + 0x27805295, 0x29713395, 0x56eb6744, 0xd5000156, 0x555580d5, 0xa248d580, 0x0040156b, 0x2b4c8201, 0x02000215, 0x00690000, 0x15163700, 0x20055267, + 0x05986226, 0x26371724, 0x86183726, 0x15251030, 0x37363617, 0x053e4f35, 0x19563320, 0x15072705, 0x37171616, 0x36853434, 0x2608026d, 0x06160727, + 0x86361707, 0x4f062024, 0x50820573, 0xb3272223, 0x05ce5f0d, 0x0e2c0582, 0x0c0e1e0c, 0x1c092b03, 0x111d1211, 0x2b251585, 0x1517240a, 0x250b851b, + 0x2416151b, 0x2d882b0b, 0x091c1129, 0x0f0b032b, 0x880e0c1e, 0x1e0d272d, 0x7c163216, 0x23851611, 0x05271682, 0x15291026, 0x60100e0f, 0x122a072e, + 0x140f0103, 0x052e041a, 0x34851623, 0x0523162a, 0x141a042e, 0x0102010f, 0x08086b18, 0x0f0e1027, 0x25112915, 0x08e85f05, 0x25111639, 0x02000c0c, + 0x15004000, 0xeb01c001, 0x5f002f00, 0x33130000, 0x52152315, 0x23240566, 0x35231523, 0x22070955, 0x18352335, 0x200a9f47, 0x20228833, 0x507a1833, + 0x482d8208, 0x152008df, 0x0c874582, 0x88353321, 0x31418222, 0x104646a5, 0x16202016, 0x16102010, 0x10161f1f, 0x07854545, 0x15830e82, 0x0d8cd620, + 0x01292b90, 0x1f166a55, 0x561f1616, 0x20058356, 0x820c8516, 0x06e0440f, 0x16860985, 0x00292387, 0x002b0001, 0x01d5016b, 0x06ae67ab, 0x17072725, + 0x84071737, 0x37200805, 0x01273717, 0x96561ed5, 0x778320a0, 0x20a05525, 0x53445580, 0x6101551e, 0xa18c611f, 0x296f8420, 0x4c241284, 0x004f1e4d, + 0x2e05f254, 0x00c001eb, 0x00130003, 0x0035001f, 0x18211300, 0x201d8e86, 0x05315737, 0x4e151721, 0x352005af, 0x27050d46, 0xff000140, 0x11d6eb00, + 0x0da48618, 0x1d12962d, 0x0d121811, 0x130d0809, 0x181d1118, 0x3213b286, 0x18261780, 0x85092b1d, 0x080d0d08, 0x1d2b0985, 0x58172618, 0x132d0a09, + 0x00002700, 0x06072725, 0x27272223, 0x33718323, 0x35363221, 0x37222335, 0x15062221, 0x17323315, 0x36363717, 0x3505b964, 0x17420126, 0x0d0e0543, + 0x19722506, 0x11560111, 0x630d8019, 0x0683aafe, 0x43170626, 0x040f1003, 0xf62c1782, 0x0c0c8530, 0x19126b4a, 0xc06b1219, 0x0b260382, 0x05078530, + 0x11830705, 0x21087582, 0x0140005d, 0x00c001a4, 0x003c0020, 0x023a3700, 0x30303736, 0x37023e31, 0x032e3630, 0x06222323, 0xf2820307, 0x82313321, + 0x06372571, 0x07232306, 0x2105c75a, 0x22823437, 0x36365f08, 0x36323333, 0x26363736, 0x191101d4, 0x27110b1b, 0x0103061f, 0x222a170a, 0x010c0873, + 0x49050632, 0xc8090112, 0x2041500d, 0x29040516, 0x04010905, 0x01010404, 0x1e0a0508, 0x04072232, 0x0302eb05, 0x272d1604, 0x1619170e, 0xfe080a0e, + 0x720804c9, 0x3c640806, 0x06048c3d, 0x17030607, 0x0782171c, 0x232a1237, 0x03002315, 0x29002900, 0xd701d801, 0x27001400, 0x00004b00, 0x05836625, + 0x0e070732, 0x16172302, 0x37373616, 0x17272622, 0x37323316, 0x3320a782, 0x062a1c82, 0x16320707, 0x23270516, 0x47410722, 0x82262005, 0x060624ba, + 0x84171716, 0x32332223, 0x202d8217, 0x242c8233, 0x414a0126, 0x32958201, 0x04400204, 0x5013160c, 0x0c21210c, 0x99190e4f, 0x82040340, 0x190c3112, + 0x210d4f0f, 0x134f0d20, 0x0a010b16, 0x0c121b30, 0x2b05895b, 0x3120120d, 0x0c08080c, 0x0d122031, 0x1b2f1187, 0x09090c30, 0x010240a0, 0x03410201, + 0x834f0709, 0x0750291f, 0x030341cd, 0x50070c40, 0x4f2b0d83, 0x30360907, 0x0909400d, 0x83320d41, 0x83312067, 0x0d40330b, 0x21210d30, 0x60000200, + 0xbf014000, 0x2200ab01, 0xe0823d00, 0x06062323, 0x20d38223, 0xd8531836, 0x14152308, 0xbb82021e, 0xe4821620, 0x86023e21, 0x05ae44fe, 0xff601720, + 0x15610809, 0xbf010614, 0x0e0c0118, 0x1b09130c, 0x3a2d1b22, 0x2e391e1f, 0x392e1b1b, 0x0c15151e, 0x1e181e23, 0x0b75040e, 0x1c131c22, 0x09070a09, + 0x070f140e, 0x2a2d0f0c, 0x2a2e2d2a, 0x10098c07, 0x40140e0f, 0x2a3b2328, 0x3a2b1717, 0x2a3a2324, 0x1e140517, 0x34181b13, 0x080a1812, 0x170e0314, + 0x3f40040c, 0x21008240, 0xb2522919, 0x000b2e0a, 0x002d0021, 0x00760041, 0x26343700, 0x05294423, 0x17363222, 0x2622be85, 0xf2560607, 0x27362307, + 0xd57f3526, 0x1827200a, 0x45109840, 0xaf4509ce, 0x32332a05, 0x37363617, 0x36373437, 0x50e78433, 0x35240591, 0x16160727, 0xe5200f87, 0x27076746, + 0x0b1a0848, 0x04081a0b, 0x08260082, 0x04041415, 0x0b831514, 0x840d0921, 0x2c3a211f, 0x86066659, 0x21502907, 0x39222239, 0x120a0821, 0x10291f82, + 0x0210192b, 0x06340202, 0x2a2d850e, 0x2b190e2f, 0x0d0c0910, 0x85ea0a12, 0x2a0d2510, 0x07060607, 0x04255882, 0x02020707, 0x20098307, 0x23568445, + 0xd50d0909, 0x0fa15218, 0x0505f122, 0x2f05314c, 0x10030505, 0x09120d09, 0x4a010e0c, 0x0c010103, 0x0a206982, 0x35080382, 0x0e014209, 0x0d12090c, + 0x06001009, 0x40005600, 0xc001aa01, 0x34002800, 0x6a004200, 0x88007300, 0x30010000, 0x26260706, 0x30232627, 0x23223130, 0x26312630, 0x80830623, + 0x23060622, 0x0e258682, 0x11173106, 0x220f8322, 0x82373636, 0x16162402, 0x86173227, 0x3e07271f, 0x031e0702, 0x0e821617, 0x31262627, 0x16163037, + 0x053d4233, 0x82262721, 0x16363e29, 0x26300731, 0x37020e23, 0x16272634, 0x06061716, 0x2e303713, 0x23263505, 0x31262222, 0x37728230, 0x063e0111, + 0x02020106, 0x0102170c, 0x1d0f0901, 0x020b0817, 0x08011410, 0x8c08be82, 0x06060503, 0x02eb0306, 0x0a140a37, 0x03060b03, 0x02040407, 0x0705071a, + 0x020d0908, 0x03081009, 0x01161912, 0x01111610, 0x13171e02, 0x0c080e1a, 0x06080911, 0x010e120e, 0x1a220f01, 0x110c0f0f, 0x020a0b0c, 0x0b04024a, + 0x0904020b, 0x0705622f, 0x04080909, 0x0e010301, 0x040b080e, 0x01029301, 0x18040702, 0x25010a01, 0x050c1d0d, 0x07040306, 0x2f291a02, 0x29172730, + 0x03125401, 0x150b0306, 0x02050307, 0x032a1508, 0x1c090804, 0x080b820e, 0x19230f36, 0x0e0b07aa, 0x231b1215, 0x0b0a0102, 0x01070822, 0x0c0a040b, + 0x1210120b, 0x01021622, 0x01052c05, 0x077b0908, 0x13020813, 0xfe030107, 0x321f18b9, 0x1f333c3d, 0x08377282, 0xb1fe030b, 0x39000200, 0xc7014000, + 0x6800c001, 0x0000d200, 0x4b032e25, 0x3622051d, 0x78412627, 0x23062205, 0x270a8234, 0x23022e27, 0x06223131, 0x22056041, 0x86221514, 0x0607211c, + 0x2105404b, 0x0982030e, 0x84021e21, 0x3316230c, 0x08821616, 0x30303323, 0x25028231, 0x36373632, 0x05853736, 0x37023e24, 0x43862736, 0x84230621, + 0x85232008, 0x26222125, 0x04856483, 0x31200583, 0x2105d441, 0x78822636, 0x33219084, 0x21548232, 0x4b833426, 0x33023e24, 0x0e833131, 0x16221182, + 0x0e820714, 0x6f823220, 0x020e0724, 0x8d850607, 0x17162408, 0x02c10130, 0x07161711, 0x110c0402, 0x04060804, 0x06040b11, 0x0f020102, 0x25150409, + 0x15251a1a, 0x820f0904, 0x062c080e, 0x04110b04, 0x10050806, 0x0802040c, 0x02111616, 0x11060c06, 0x0302030e, 0x080d0608, 0x0b080f15, 0x1d17171d, + 0x150f080b, 0x08060d08, 0x29081682, 0x0c06110e, 0x0718061b, 0x02030208, 0x15170508, 0x041a170a, 0x09171a04, 0x030d1616, 0x08070203, 0x02010617, + 0x0d040901, 0x55820c21, 0x020b0c22, 0x24080083, 0x04020208, 0x01010f0d, 0x03070c02, 0x15151e12, 0x0603121e, 0x0101020d, 0x02040d0f, 0x02020802, + 0x0a030103, 0x08a1820c, 0x0d210c48, 0xa7010904, 0x140d0b07, 0x08030511, 0x0f0e090b, 0x0e010c09, 0x0a1d190d, 0x0f0f1204, 0x1d0a0412, 0x060e0719, + 0x0f0a0b01, 0x080b090e, 0x14110503, 0x0e070b0d, 0x0408060c, 0x060b0202, 0x06010204, 0x0d0d0705, 0x83820507, 0x0b060424, 0xf6820202, 0x07030c27, + 0x0a060506, 0x2d6e8202, 0x030e0608, 0x07060f03, 0x02020101, 0x0082060a, 0x052e0782, 0x1a190703, 0x0805120b, 0x05030307, 0x89820505, 0x1516042d, + 0x0817150a, 0x0d0d0e03, 0x8208030e, 0x161522e0, 0x83168204, 0x07032b1c, 0x0b120508, 0x0208191a, 0xcc4e0205, 0x01c02b06, 0x000f00c0, 0x002f001f, + 0x7f4a0100, 0x1616210c, 0x200f1a6a, 0x0e655f33, 0x73550121, 0x8f180c56, 0x1722089e, 0x3444be27, 0x21118405, 0x0c8a6b01, 0x61179721, 0x0b8b0a2b, + 0x200c695e, 0x1174564a, 0x030e1727, 0x23060607, 0x065c4206, 0x3e37362d, 0x27343704, 0x07220726, 0x83262306, 0x36372114, 0x26065542, 0x16171632, + 0x58141415, 0x32081047, 0x07060137, 0x08020307, 0x090f0905, 0x0a0e140e, 0x01060a01, 0x0b11110c, 0x04010101, 0x0a0d5802, 0x0a081306, 0x0f01010e, + 0x1e0f3f2e, 0x01040f1f, 0x56030205, 0x913d118f, 0x2a2d280c, 0x010a0c0e, 0x0e09060b, 0x0b0a0709, 0x100b0106, 0x02010c10, 0x3b010102, 0x2a338209, + 0x06050504, 0x071b1406, 0x82050c0c, 0x01042e14, 0x00010004, 0x01400059, 0x00c001a7, 0x28d68229, 0x27321630, 0x23352626, 0x2acc8211, 0x34352622, + 0x35173636, 0x6b020e26, 0x5b080881, 0x33161635, 0x26263035, 0x01056201, 0x420c0a06, 0x16172001, 0x12211521, 0x1626321c, 0x221f3822, 0x2f132137, + 0x01201619, 0x0c050584, 0xf7fe111f, 0x17211f16, 0x050c1c12, 0x22100443, 0x37241b2f, 0x2237211f, 0x42100e86, 0x04000d02, 0x37004000, 0xd501c001, + 0x15000900, 0x27001e00, 0x272a7e82, 0x36361707, 0x17163233, 0x06833407, 0x24058246, 0x17352717, 0x39818206, 0x36351717, 0x27343536, 0xaa011537, + 0x0c6caaaa, 0x20121220, 0x1219690c, 0x03831912, 0x6dab1634, 0x2a1c2402, 0x6d02241c, 0x5e5e7701, 0x0e0e0c3c, 0x1a853b0c, 0x5eb7193e, 0x0c0a3cbd, + 0x76072e1e, 0x1e2e0776, 0xbd3c0a0c, 0x25000600, 0xdb014000, 0x1900c001, 0x31260982, 0x51004500, 0x81825d00, 0x2e173225, 0x84222302, 0x07172af1, + 0x17161637, 0x3e343526, 0x946d1802, 0x0bb44f0b, 0x1f6c0520, 0x1737240d, 0x18363627, 0x2109d86c, 0xd44f0616, 0x0c523a0c, 0x442e070c, 0x2d3b2228, + 0x161d221a, 0x0a140a3b, 0x3b2e1903, 0x0c0c0830, 0x24038208, 0x0c0c0965, 0x27078209, 0x3e254001, 0x253e2626, 0x09270582, 0x1a4a0912, 0x85b21d18, + 0x0d012219, 0x201e824a, 0x390c8208, 0x1f015201, 0x26151d33, 0x38211c32, 0x03192b13, 0x0d0d0205, 0x1526321c, 0x1d830c30, 0x29204482, 0x0c824984, + 0x321e9023, 0x2702841e, 0x2002021d, 0x212d0f33, 0x07872187, 0x00060035, 0x016d002b, 0x006b01d5, 0x00410012, 0x006a0055, 0x5392007e, 0x1526065f, + 0x33331614, 0xee562717, 0x50052006, 0x332906be, 0x36363736, 0x16171637, 0x22088233, 0x82372627, 0x26352105, 0x2005ea42, 0x23078307, 0x26070706, + 0x05200782, 0x15262182, 0x23060714, 0x0d822722, 0x3734352c, 0x07163336, 0x34363736, 0x10833435, 0x4d820720, 0x17141525, 0x83161716, 0x2223230d, + 0x0d850607, 0x37323325, 0x83343536, 0x2236871d, 0x84173637, 0x014b084a, 0x10a4feae, 0xa5101717, 0x117c114b, 0x8dfe1717, 0x01040308, 0x07050d10, + 0x0d040f0b, 0x07180e09, 0x03030607, 0x07060101, 0x0401020a, 0x04070606, 0x070a0710, 0x05080b03, 0x04090526, 0x13430102, 0x100d0809, 0x12060419, + 0x820e080a, 0x0a023807, 0x04030103, 0x07080a06, 0x03040202, 0x09420607, 0x19040613, 0x82080d10, 0x1a032607, 0x041e0e0f, 0x2751820a, 0x02010304, + 0x07090907, 0x42080782, 0x8410186b, 0x2a2a1711, 0x10841117, 0x04011f18, 0x23620705, 0x081e010c, 0x19311119, 0x05050107, 0x2c2a1907, 0x06050412, + 0x07010404, 0x2219421e, 0x09010110, 0x1b2e1349, 0x11030e0e, 0x171b140e, 0x8304011a, 0x1b163207, 0x11095f01, 0x08040603, 0x02010a08, 0x060b0a0d, + 0x28098406, 0x01041051, 0x141b161a, 0x2f07840f, 0x1122141c, 0x01020709, 0x0608080a, 0x0d0a0b06, 0x07200984, 0x280a074a, 0x001b0013, 0x00620024, + 0x118b446e, 0x34072d08, 0x2e173736, 0x27221702, 0x14161737, 0x36030617, 0x36363136, 0x06302326, 0x26222306, 0x06223126, 0x16303316, 0x27071733, + 0x32313632, 0x22211887, 0x05794323, 0x544a3020, 0x16172706, 0x06141516, 0x946a0707, 0x37072505, 0x34353636, 0x0810b444, 0x0809ec24, 0x1c30205b, + 0x391a1cc0, 0x1f01013b, 0x060d0907, 0x11050402, 0x18090a18, 0x03040512, 0x1e070d05, 0x1488462a, 0x0306033b, 0x25325519, 0x01011943, 0x070b120e, + 0x06080a06, 0x0c0c4813, 0x083b2b35, 0x11cb4407, 0x2715d531, 0x3410fb12, 0xa7089a43, 0x010101a1, 0x821a010b, 0x29288205, 0x08010202, 0x7e520208, + 0x068202d0, 0x3027013d, 0x1501181b, 0x0b160c0d, 0x0d111a0a, 0xd040141d, 0x35192e15, 0x14aa1958, 0x450b0e22, 0x1a240cb5, 0x14130000, 0x2b09e05d, + 0x020e2223, 0x23153317, 0x2b372715, 0x210f564a, 0x008255d5, 0x1724ec90, 0x5555402a, 0x0120528f, 0x85081067, 0x2327255a, 0x17353335, 0x539ace93, + 0x15000335, 0xeb014000, 0x2000c001, 0x28002400, 0x15010000, 0x8f233523, 0x73112003, 0x11210927, 0x20668205, 0x18038217, 0x3408eb43, 0xc02b2b2a, + 0x19121219, 0x2b00ffc0, 0x2b2b552b, 0xab2b4001, 0x2c00842b, 0x00ff2bab, 0x19191240, 0x00014012, 0x88008240, 0x00eb22c1, 0x226b831c, 0x82273525, + 0x236f84b2, 0x07153315, 0x67890182, 0xcc443520, 0x06142609, 0x2b6b8001, 0x2267822b, 0x83aa556b, 0xd5aa2569, 0x0d13130d, 0xfb230382, 0x83203545, + 0x35202c69, 0x40aa2645, 0x11191911, 0x840baa40, 0x291d8219, 0x2b000400, 0xd9012b00, 0x6845da01, 0x823d2006, 0x2e2224dd, 0x82063702, 0x0e262203, + 0x05664d03, 0x05023e22, 0x6d0a0a6d, 0x2e6d0b16, 0xd4013a0b, 0x05131b0e, 0x212b1808, 0x4f2d040f, 0x21182d40, 0x2f2c4d3b, 0xfe1d3c51, 0x248682dc, + 0x12120e0d, 0x2092861d, 0x06995a53, 0x0e160138, 0x08132019, 0x182a1d0a, 0x3b290f09, 0x4d2c2344, 0x4125213b, 0x9e872655, 0xb7186b20, 0x306f086e, + 0x41012008, 0x2c20088c, 0x240b8841, 0x35231517, 0x0a944137, 0x28411720, 0x411c820e, 0x2b25058c, 0x2b2b2b80, 0x4103822a, 0x2b210690, 0x8217822b, + 0x2b55250e, 0x552b1515, 0x04820882, 0x552b8022, 0x20059241, 0x2c2d8255, 0x00070055, 0x012b002e, 0x00d501d2, 0xd4371905, 0x0100250c, 0x07232737, + 0x17236982, 0x83273733, 0x820c8203, 0x37332202, 0x20178425, 0x210b8417, 0x19830717, 0x27260125, 0x82274c27, 0x26048200, 0x26264d39, 0x8473264d, + 0xcffe2105, 0x26210b83, 0x200c844d, 0x22238413, 0x82405501, 0x82152000, 0x36402103, 0x0d830482, 0x0a201188, 0x35062142, 0x02400000, 0x00eb0100, + 0x004d0014, 0x32331300, 0x36361716, 0x63823435, 0x06060724, 0x0d831415, 0x2e342525, 0x47303102, 0x15210528, 0x241b8223, 0x06222323, 0x4d098215, + 0x1a870504, 0x080bb442, 0x95363625, 0x050904d6, 0x11140201, 0x14115b5b, 0x09050102, 0x110d6f01, 0x0d100d0d, 0x192b0a0b, 0x1911d611, 0x820b0a2b, + 0x2113820d, 0xce42090c, 0x09220805, 0x0155010c, 0x060b0501, 0x3d0b2515, 0x15250b3d, 0x01050b06, 0x16081601, 0x150d0d15, 0x140c0816, 0x7c675b05, + 0x055b2305, 0x158a0c14, 0x55fafe33, 0x12191912, 0x05060155, 0x00040014, 0x012b0040, 0x2dcf82c0, 0x00170013, 0x002d0027, 0x35230100, 0x25701521, + 0x8211200b, 0x153323dd, 0x3d5b1323, 0x16163108, 0x06061415, 0x17152327, 0x95012737, 0x1500ff15, 0x01205083, 0xfc246d83, 0x1d55aaaa, 0x09998c18, + 0x23161228, 0x80011c0f, 0x6d186b6b, 0x40230bcb, 0x69ebfe40, 0x1e3007bc, 0xa01c311d, 0x1d0f233a, 0x2b000200, 0xeb012700, 0x30088982, 0x0020001c, + 0x16163700, 0x06273736, 0x26272606, 0x37363426, 0x15333636, 0x22152737, 0x06060706, 0x17371614, 0x20632737, 0x1f255653, 0x183d3f1d, 0x26008316, + 0x55551d37, 0x821c4725, 0x80a43100, 0x21638080, 0x1f170a1b, 0x1815040f, 0x363a3716, 0x3f2aaf82, 0x1b415655, 0x4b461c1d, 0x1e826c46, 0x200c836e, + 0x29f28223, 0x1e141507, 0x033e1702, 0x5f823535, 0x73832620, 0x73823620, 0x07162f08, 0x16171606, 0x16321716, 0x1aab0001, 0x25253e2e, 0x561a2e3e, + 0x272a270f, 0x1107110e, 0x07051b26, 0x0b030702, 0x0614240c, 0x40d50103, 0xad182882, 0xc834092a, 0x12011112, 0x2e321611, 0x08010422, 0x142b1405, + 0x0b041813, 0x08804718, 0x0d00c02f, 0x22001900, 0x2f002600, 0x00003300, 0x0b094213, 0x5c172721, 0x343205b3, 0x16323336, 0x15062227, 0x34353315, + 0x11330726, 0x0c8b0123, 0x19558028, 0x55191212, 0xae432080, 0x12e02907, 0x3d195619, 0xab015656, 0x553f0887, 0x116bebfe, 0x6b111919, 0x956b1501, + 0x0e12120e, 0x5d13130d, 0x16161119, 0xff551911, 0x88550100, 0x0300250a, 0x2b001500, 0x20067a41, 0x20918330, 0x06ee7501, 0x16142323, 0x837f8317, + 0x8215208b, 0x033e2608, 0x21152535, 0x20068235, 0x062b6523, 0x372e2182, 0xc0013307, 0xd4fe1119, 0x252b1911, 0x9783801b, 0x04802108, 0xfe111615, + 0x04000195, 0x2b101715, 0x12d61218, 0x9c242b18, 0x4001a050, 0x12191912, 0xc3072d1e, 0x28050c45, 0x130901c3, 0x1803171e, 0x24078218, 0x1812161f, + 0x211b8218, 0xc8626ba1, 0x82eb2008, 0x000f2909, 0x13000019, 0x05232733, 0x23207882, 0x33208382, 0x27210382, 0x066e4427, 0xe68d073e, 0x0b01c013, + 0xaa2aaafe, 0x1382aa56, 0x122b2b2b, 0x40401501, 0x6aea2a2a, 0x406bea6a, 0x2e2f0f82, 0x0002003d, 0x0155006b, 0x00ab0195, 0x8217000b, 0x1523234c, + 0x45831123, 0x23113323, 0x0ab86717, 0x2a2bc023, 0x2030822a, 0x2f0483d5, 0xab012a2b, 0x2b00ff2b, 0x2b00012b, 0x6b955656, 0x0b60ae18, 0x0f000726, + 0x15010000, 0x03823d82, 0x35330122, 0x35294c82, 0x40400123, 0xaafe6b40, 0x8505826b, 0x56012339, 0x3d83aafe, 0x2b207d82, 0xd5207d82, 0x27227d82, + 0x7d824f00, 0x06141523, 0x27c78223, 0x15151632, 0x33161614, 0x22273f82, 0x34353526, 0x18352726, 0x24085e45, 0x06062223, 0x20158505, 0x232b8926, + 0x06061517, 0x3d853382, 0x553a2b88, 0x1515090c, 0x1d120c09, 0x08404011, 0x1313180d, 0x40080d18, 0x121d1140, 0x15936b01, 0x01282d82, 0x0c092b6b, + 0x2b090c56, 0x2b312482, 0x152b080d, 0x06080621, 0x082b1521, 0x1d122b0d, 0x20179651, 0x08338311, 0x00050043, 0x01530033, 0x00c001cd, 0x00070003, + 0x000d000a, 0x01000011, 0x023b0723, 0x23172327, 0x23352315, 0x07233737, 0x39060301, 0x386e2378, 0x20b8a16e, 0x6e3869b8, 0x70c00138, 0xdddd9070, + 0x00707020, 0xac811802, 0x00152208, 0x203b822a, 0x09e74622, 0x2e343524, 0x63440303, 0x32332205, 0x05fd4616, 0x29080682, 0x16000106, 0x101d262c, + 0x1f362917, 0x1729361f, 0x2c261d10, 0x1a302001, 0x0c09090c, 0x04151710, 0x010d0d09, 0x3e311dc0, 0x1d831e41, 0x1e352583, 0x1d313e41, 0x301bc0fe, + 0x0d0d0820, 0x0c1a1808, 0x08090d02, 0x2a7a820d, 0x012b002a, 0x00d501d5, 0x822e001e, 0x042e2b7a, 0x06062223, 0x031e1417, 0x03833233, 0x35023e26, + 0x07262634, 0x3d0ee544, 0x170c9501, 0x2636251c, 0x01294c36, 0x2d2d2517, 0x11110d14, 0x181a2116, 0x0e15252e, 0x4518ab1c, 0x013a0a70, 0x28260d40, + 0x5c341624, 0x2535233b, 0x130d0a18, 0x28160d13, 0x29202037, 0x258a7622, 0x01001526, 0x40002b00, 0xc0228682, 0x84821c00, 0x07072227, 0x23370733, + 0x07cd6c37, 0x82058544, 0x012f0887, 0x261c1e60, 0x40154040, 0x182d1121, 0x1f1f3521, 0x2c2f4e39, 0x1f213b4d, 0x0fc00135, 0x73c0d571, 0x351f1210, + 0x3e3c2121, 0x44282b45, 0x82223f3e, 0x06002122, 0x2406c743, 0x000900d5, 0x62401911, 0x37002c08, 0x21331614, 0x35353632, 0x82272521, 0x15152af2, + 0x17352721, 0x23153307, 0x20038237, 0x08038225, 0x1219552c, 0x19120001, 0x5601aafe, 0x1812ab80, 0x76965501, 0xab8080cb, 0xaafe8080, 0x11558080, + 0x40111919, 0x111980c0, 0x75752b96, 0x00832b55, 0x82020021, 0x01802869, 0x008001eb, 0x82260016, 0x6d2320c6, 0x162b0815, 0x36363233, 0x37173337, + 0x41053717, 0xc0250f4a, 0x312309b2, 0x059a641c, 0x23311c2a, 0x2b2b0709, 0xaafe562a, 0x2608815a, 0x2b011d11, 0x85162619, 0x26162720, 0x2a2a2a19, + 0xc35a4156, 0x1d122208, 0x33778211, 0x016b0080, 0x00950180, 0x000b0005, 0x07270100, 0x17170727, 0x01260584, 0x62621e80, 0x0585801e, 0x1e770127, + 0x801e6161, 0x8212840c, 0x006b2135, 0xad823382, 0x25263584, 0x27372737, 0x05840707, 0x418b288c, 0x1326348f, 0x17071707, 0x05843737, 0x5c8a8920, + 0x9f8f768c, 0x82173721, 0x27272101, 0x5c8b0584, 0x3382408b, 0x2b00ab2a, 0xd5015501, 0x19000d00, 0x232cd382, 0x15150622, 0x35331533, 0x26343533, + 0x0c226d18, 0x11562b28, 0x2a562a19, 0xd94f6719, 0x6b013107, 0x95801219, 0x19128095, 0x19191140, 0x19191211, 0x24088c79, 0x001b00ab, 0x244d821f, + 0x23372337, 0x23038407, 0x23073307, 0x7e700382, 0x82178206, 0x01332716, 0x15550bb5, 0x0384152b, 0x55200982, 0x40230d8c, 0x18551555, 0x431217b3, + 0xd52407c3, 0x30002400, 0xa5826282, 0x07e87618, 0x3a571720, 0x33352208, 0x091a5127, 0x79363621, 0x20820817, 0x95012a08, 0x132b1218, 0x17131818, + 0x27181727, 0x226a4017, 0x3a23243a, 0x40181223, 0x080d0d08, 0x010d0d09, 0x07201540, 0x20075959, 0x20078215, 0x055f6344, 0x806b1522, 0x21051742, + 0x59640744, 0x01002f08, 0x40004000, 0xc001c001, 0x00003d00, 0x72503525, 0x051c5107, 0x36353522, 0x2007f16e, 0x828a8206, 0x1816209a, 0x7d0d66bb, + 0x01210c3e, 0x05125395, 0x12121925, 0x42181319, 0xa1820574, 0x82182621, 0x21138c7e, 0xb682afbc, 0xd6250282, 0x11191911, 0x5da382af, 0xa982050b, + 0x0622188c, 0x18871521, 0x0246a682, 0x00222207, 0x09164d00, 0x17161634, 0x06222315, 0x37330707, 0x27331733, 0x23232626, 0x0a783e35, 0x333d080a, + 0x0d243657, 0x2b200515, 0x2b197819, 0x0c160520, 0x33573624, 0x1b0f6001, 0x150c0c15, 0x21130f1b, 0x0f560214, 0x4040500c, 0x560f0c50, 0x00211402, + 0x00290002, 0x01d70155, 0x001700ab, 0x8369821b, 0x83212052, 0x16062360, 0x65863333, 0x36323323, 0x086e8205, 0x1ed40130, 0xfe080b02, 0x020b08be, + 0x0b0c031e, 0x0e2b1a2f, 0x1a2b0ee4, 0xfe0c0b2f, 0x06cc06bd, 0x076b3001, 0x6b070909, 0x6bc0110a, 0x3b11c06b, 0x5c822a2a, 0x2b00952a, 0xd5016b01, + 0x18000c00, 0xae825c82, 0x1523bb84, 0x18333533, 0x2b0c16d6, 0x0e160529, 0x4205160e, 0x96405640, 0x2908a842, 0x10100c4f, 0x8080a40c, 0xa8420001, + 0x00032107, 0x24071441, 0x0013000f, 0x09774a1f, 0x15150625, 0x82343521, 0x298d185e, 0x05694a0f, 0x01111d29, 0x521d11aa, 0x4c2baaaa, 0x002b07c9, + 0x1d11abab, 0x126b6b12, 0x6b80111d, 0x00210857, 0x06674508, 0x0a00ab30, 0x12000e00, 0x2a001e00, 0x42003600, 0x69845000, 0x85112321, 0x6d272064, + 0x644d073d, 0x0bd94d0a, 0x8b0b644d, 0x6a252017, 0x012e0c72, 0x01d51595, 0xd21d112a, 0x56568080, 0xc6422a56, 0x86092006, 0x8e372007, 0xc2fe250f, + 0x161f1f16, 0x01260382, 0xcafe6b40, 0xb782ab20, 0xab404025, 0x860d6b6b, 0x99402030, 0x1f802308, 0x3882ab16, 0x00210483, 0x08fc4205, 0x1b000f24, + 0xdc842d00, 0x78010021, 0x012c0e6d, 0x32333523, 0x15151616, 0x37060614, 0x82052c6e, 0x343521e9, 0x3405d974, 0x27260617, 0x37173327, 0x15230733, + 0x36373233, 0x27343535, 0x0c7d7826, 0xfdfe2308, 0x100e2424, 0x56100707, 0x06302919, 0x3106090a, 0x16087929, 0x17191e06, 0x0ee01917, 0x0405040e, + 0x0e660504, 0xff26080d, 0x110c8000, 0x11073707, 0x1e174c0d, 0x61060917, 0x1d170a06, 0x0e03113c, 0x18585870, 0x07030350, 0x03030736, 0xbc820200, + 0xeb012b2f, 0x2400e001, 0x00002a00, 0x23263401, 0x23038223, 0x23150622, 0x2b080382, 0x021e3215, 0x020e1415, 0x16141523, 0x36343333, 0x17353736, + 0x07171527, 0xab013715, 0x20551219, 0x551f1616, 0x19161912, 0x0d04040d, 0x122b0682, 0x09161051, 0x565696c0, 0x828001d6, 0x1f1f2616, 0x51121916, + 0xac69180e, 0x1a172d09, 0x60c6020c, 0x1516551b, 0x05006a55, 0xd9857518, 0x6b00042a, 0xeb011500, 0x1700eb01, 0x25071f7c, 0x33112325, 0x834e3315, + 0x638f1807, 0x23352307, 0x3a731737, 0x07272105, 0x20053a73, 0x24078617, 0xd6d66b01, 0xd84c182a, 0x482a2509, 0x1e1e0d0d, 0x40280382, 0x1a3b3b1a, + 0x503b3b1b, 0x1e210e85, 0x7a771980, 0x849e200e, 0x0d1e2625, 0x1b1b3a15, 0x2003823a, 0x82348330, 0x06002103, 0x3308a542, 0x0048003c, 0x00590054, + 0x00710065, 0x06220100, 0x23151506, 0x2608b245, 0x33161614, 0x58231533, 0x35210ba7, 0x08404633, 0x20060d44, 0x06d04532, 0x3435072b, 0x16323336, + 0x2b061415, 0x08b74302, 0x17231522, 0x23213182, 0x20108217, 0x201c8535, 0x06744623, 0x06274782, 0x14750123, 0x82561422, 0x22152703, 0x15221414, + 0x07852020, 0x20281494, 0x120e0d13, 0xca200e12, 0x2705354d, 0x56564a20, 0x20130da0, 0xea200d83, 0x13231884, 0x9fc0010d, 0x20598944, 0x2039846b, + 0x053c6a0d, 0x80200e25, 0x826a5656, 0x8463855c, 0x02003e56, 0x6b004000, 0x9501c001, 0x0b000300, 0x33010000, 0x23272315, 0x33133315, 0x40012335, + 0x2b008280, 0x6c859467, 0x2a2a9501, 0x2a00ff2a, 0x15202382, 0x2406414a, 0x003f0028, 0x222f8248, 0x82020e22, 0x183720fe, 0x22088dad, 0x82020e14, + 0x072721fb, 0x2405a25f, 0x022e3435, 0xce441817, 0x0d007c07, 0x41232321, 0x012a064a, 0x35462715, 0x5556401e, 0x674b1740, 0x18182105, 0x1e320782, + 0x1a1e1436, 0x46282745, 0x341e1e34, 0x12190346, 0xd3181911, 0x1e2d0774, 0x09080d2b, 0x1ec0010d, 0x55284535, 0x077a4b55, 0x16240783, 0x1e191e14, + 0x282f1683, 0xab1e3545, 0x19191116, 0x090c1611, 0x840c0940, 0x08162404, 0x18080d0d, 0x220aa6b5, 0x820c0008, 0x21173dc0, 0x17072115, 0x11212737, + 0x37011133, 0x01fcfe4d, 0x801e4d04, 0x2ad6fe80, 0x2a4d6201, 0xff230a83, 0x84000100, 0x016b35f9, 0x009501eb, 0x000b0007, 0x3700000f, 0x17333733, + 0x07230333, 0x253c0682, 0x15352315, 0x1b781b34, 0x12367034, 0x012c022c, 0x4c6bab1e, 0xb32a014c, 0x2a337c7c, 0x89053541, 0x8d17203b, 0x3337223b, + 0x09c97215, 0xde23438a, 0x822b4040, 0x23478902, 0x402a4040, 0x5b188682, 0x14240727, 0x2d002200, 0xcf65bf82, 0x070a5206, 0x82072321, 0x07272b09, + 0x15060617, 0x17171614, 0xda823733, 0x20050c4b, 0x34138237, 0x311d0001, 0x2004041d, 0x1a1e0909, 0x2d14801d, 0x1eba1409, 0x220c865f, 0x84c41e52, + 0x098a241c, 0x826b0114, 0x140a3109, 0x24102009, 0x153c2413, 0x042e4460, 0x5f1e5904, 0x51220d87, 0x1f85591e, 0x04048a22, 0x01650310, 0x00013a25, + 0x01e2006b, 0x00950195, 0x13000005, 0x37173717, 0x771e6b27, 0x01951e77, 0x43068400, 0x04202e86, 0x2d08ae7a, 0x002f002c, 0x003e0032, 0x37360100, + 0x47180733, 0x27230792, 0x49233533, 0x23210524, 0x27158b15, 0x23151716, 0x23352115, 0x5505814b, 0x01360bd1, 0x440a1d15, 0x15221440, 0x40142214, + 0x2106842b, 0x06211515, 0x11822b84, 0x82151421, 0x0a442d11, 0xaa01c01d, 0x28509ec0, 0x8b2850ee, 0x2307fd48, 0x951d0a59, 0x2605694a, 0x18122b95, + 0x872b1218, 0x0a1d310d, 0x802b2bee, 0x385d5d5d, 0x0d09080d, 0x0d08090d, 0x5e08e851, 0x2e200538, 0x212fb082, 0x15150622, 0x11213533, 0x11353632, + 0x6f052634, 0x23241103, 0x06070622, 0x27069349, 0x80fec001, 0x012b1912, 0x19220482, 0x435e99fe, 0x1bdd3a0b, 0x45282845, 0x0113101b, 0xc0011356, + 0xaaaa1219, 0x1219abfe, 0x19122a01, 0x0a5d5e95, 0x140d7439, 0x1f080d14, 0x123b3b12, 0x0002001f, 0x0195002b, 0x006b01d5, 0x82290019, 0x4e31208a, + 0x072f0543, 0x33152331, 0x33021e31, 0x37363632, 0x4f353331, 0x692a1090, 0x1a2c1e05, 0x051e2c1a, 0x09886c6c, 0xd668d520, 0x1d112a08, 0x26191501, + 0x19261717, 0x2006862a, 0x0c414e55, 0x7c000121, 0xc02205c1, 0x73821100, 0x11233522, 0x15226d82, 0x967e3533, 0x352b0806, 0x2aeb8001, 0x55552b2a, + 0x9501abab, 0x2bebfe2b, 0x402b4040, 0x0100802a, 0x40008000, 0xc0018001, 0x00001d00, 0x15333513, 0x84071537, 0x2aa48203, 0x0e143335, 0x35232302, + 0x82373507, 0x82c02003, 0x5555293c, 0x2b1c311d, 0x1f362917, 0x403a3f82, 0x607b4501, 0x32363235, 0x5e353336, 0x1f1d311c, 0x6e172936, 0x33283228, + 0x56883228, 0x3100cb32, 0x32250000, 0x06273736, 0x36232306, 0x27343536, 0x2e209082, 0x07e84c18, 0x1e501720, 0x17162108, 0x1621ae82, 0x08708215, + 0x0115314e, 0x06301f2b, 0x15170425, 0x02130d69, 0x12085a4b, 0x1422140c, 0x28082618, 0x20263b0d, 0x0b152035, 0x10023520, 0x23401116, 0x1612131d, + 0x0b1b2a10, 0x19112b0a, 0x2215111a, 0x11161b14, 0x35202a21, 0x12271c21, 0x160b0a2b, 0x2b0a1520, 0x270a9851, 0x00230018, 0x15230100, 0x5a186982, + 0x41790a0b, 0x35232208, 0x05ed4433, 0x20010624, 0x00822a8b, 0x6032f082, 0x1f1f3620, 0x60602036, 0x15152115, 0xc0c00121, 0xf9822a2b, 0x63832b20, + 0xc0218982, 0x05764795, 0xfa50ee88, 0x26263305, 0x21352323, 0x17162315, 0x0e231533, 0x17232302, 0x5b822723, 0x37362308, 0x23013523, 0x60162409, + 0x10460001, 0x032b2f07, 0x101f3320, 0x4b903b90, 0xaa042a1c, 0x17136b01, 0x03822b2b, 0x1d301e28, 0x252b9595, 0x55822b1b, 0x40006b28, 0xc0019501, + 0xb7821600, 0x15204b82, 0x8209cc45, 0x33272bac, 0x01333717, 0x6b6b5729, 0x03822a6b, 0x326c5729, 0x01326363, 0x822b2a15, 0x2b2b25b7, 0x9c9cab2a, + 0x0e20418a, 0x23214186, 0x21398835, 0x3782651b, 0x847a6521, 0x2b002135, 0xc0207382, 0x032c3182, 0x23005500, 0xd501f301, 0x0f000c00, 0x2c08b54f, + 0x33161411, 0x35333533, 0x03173507, 0x08848235, 0x2707172b, 0x2b012315, 0x191912ab, 0x966bc012, 0x2f782076, 0x2a3f1f3f, 0x1119d501, 0x1911aafe, + 0x751580aa, 0x79f2fe75, 0x3f1e3f2b, 0x0c3d5b30, 0xba5c1d20, 0x23132411, 0x82152327, 0x33172194, 0x27107d5b, 0x35156b54, 0x40158020, 0x2511285c, + 0x6b2bebfe, 0x36472beb, 0x0010250a, 0x0044002a, 0x10c9b318, 0x34233525, 0x1837023e, 0x2d0b6ee6, 0x032e3736, 0x07062237, 0x1415031e, 0x4848020e, + 0x43c0200a, 0x20370b4d, 0x171a0c04, 0x1f0e1b0d, 0x18182936, 0x0e1f3629, 0x1a170d1b, 0x86b5040c, 0x271d8d07, 0x37220001, 0x22372121, 0x08260585, + 0x132a271f, 0x6d480505, 0x05172706, 0x272a1305, 0x06859d1f, 0x1c8e0820, 0x3222c08c, 0xc0925400, 0x18061721, 0x22092da0, 0x8e363617, 0x262622cb, + 0x67cb8213, 0x162306ad, 0x82061415, 0x0627222d, 0x2dd69706, 0x1e0a0c01, 0x301d1d30, 0x060c0a1e, 0xdf8d0a10, 0x8e100a22, 0x0a22dd82, 0x23960610, + 0x6821e58d, 0x050c5903, 0x12090323, 0x28ec8b08, 0x06011208, 0x12080505, 0x8c1f9409, 0x002a22ef, 0x41ef924c, 0xe4a818b0, 0xa71abb41, 0x0ea641dd, + 0xba08c341, 0x423320d7, 0x23270d6d, 0x1e070622, 0x18320703, 0x20086250, 0x052b6f26, 0x420de241, 0xa0200c93, 0x420d7542, 0xd7d80b93, 0x5b000221, + 0x11370745, 0x00001d00, 0x37270701, 0x07170727, 0x27371707, 0x33171737, 0x63053737, 0x01360ab4, 0x4c19afa6, 0x7a3a1e61, 0x2c25351a, 0x2b0a4408, + 0x80feb50b, 0x17511219, 0xd5013405, 0x622c178f, 0x5c463b1e, 0x1b4b165b, 0xb7d5c026, 0x84191222, 0x0400351c, 0x2b005500, 0xab01c001, 0x21001400, + 0x41003800, 0x15130000, 0x2505655c, 0x23153335, 0x5b703335, 0x23372d05, 0x16353315, 0x34331516, 0x15332726, 0x3e1ef64b, 0x162619d5, 0x802a1417, + 0x22201b3b, 0x2a80fa3a, 0x202b1714, 0x12193b1b, 0x0d081912, 0x8256080d, 0x1e220804, 0x09090c2a, 0x2ca5010c, 0x1c302409, 0x3412311c, 0x43172b80, + 0x30442826, 0x1234800f, 0x43261c31, 0xe24beb17, 0x82032015, 0x05a977ae, 0x2b001622, 0x0023ae82, 0x49312225, 0xb384050e, 0x37331624, 0x9d823632, + 0xc2922520, 0x16231728, 0x26231716, 0xd5832726, 0x01cb0134, 0x161c2a04, 0x1c110924, 0x121d1110, 0x1f1f168b, 0xb68cf4fe, 0x1e173b32, 0x15042b04, + 0xc0802a10, 0x1318251b, 0x111d1101, 0x01252882, 0x1f16161f, 0x28b690e5, 0x2037141c, 0x340f2516, 0x0c704580, 0x00001c27, 0x023e3225, 0x0ab26035, + 0x021e1327, 0x06061415, 0x106e4507, 0x442a4126, 0x2a442828, 0x29101a61, 0x30057e01, 0x482c2c48, 0x5a820530, 0x1e001e2e, 0xc401c401, 0x14000600, + 0x36010000, 0x2125f882, 0x17072517, 0x05b36e15, 0x35352808, 0xa6013717, 0x090c0206, 0xffaafdfe, 0x0db71e00, 0x0d092a09, 0x88011e7b, 0xaa0c1007, + 0x80bb1ec3, 0x090d0d09, 0x4c1e7b2e, 0xc420086a, 0x07320982, 0x00001800, 0x21353313, 0x23353317, 0x35231517, 0x03872733, 0x07013733, 0xfcfed9e7, + 0x04592e96, 0x59404456, 0x042e402e, 0x304d8226, 0x2b55011e, 0x197c2a95, 0x402a402b, 0xfe1e262b, 0x53508378, 0x11240776, 0x27002300, 0xe5829c82, + 0x09db5118, 0x32331725, 0x47350716, 0xab8705fc, 0x07353322, 0x51186782, 0x803609d9, 0x1911ab2b, 0x15352b75, 0x0d2b0d13, 0x2b351513, 0xd555012b, + 0x44581912, 0x192b2e05, 0x2015153c, 0x13130d56, 0x7620560d, 0x804e1856, 0x8225200c, 0x1823206d, 0x4810804e, 0x61820567, 0x24050d72, 0x33153335, + 0x8d4e1801, 0x2b3c240c, 0x842a2b2b, 0x182b2000, 0x220d934e, 0x822a2b80, 0x2c028219, 0x0001002a, 0x01400022, 0x00c001de, 0x27648305, 0x37331707, + 0x6fde6f01, 0x01210282, 0x820082c0, 0x05a1431f, 0x1700d526, 0x33250000, 0x70846a82, 0x20052a48, 0x290f8315, 0x01231533, 0x6b40ab15, 0x0382aa40, + 0x0582ab20, 0x55952b27, 0x2b95952b, 0x20038255, 0x08b5592b, 0x0400d532, 0x13130000, 0x2b271321, 0x55000155, 0xff4001d5, 0x95201b82, 0x60187582, + 0x1b2609d0, 0x2f001f00, 0x27823b00, 0x81563220, 0x1816200c, 0x230bc240, 0x01170103, 0x0fce8518, 0x220b3f67, 0x182115a0, 0x61095663, 0x3e2606bb, + 0xfe1e3801, 0x1992ecc9, 0x2b890120, 0x6b201d82, 0x2707145e, 0x3701f4fe, 0x96c8fe1e, 0x1c88318b, 0x0002002d, 0x01150015, 0x00eb01ec, 0x8229000d, + 0x333525ad, 0x07352315, 0x33300483, 0x07013715, 0x23230606, 0x27272622, 0x17173637, 0x2b062550, 0x17323315, 0x80161617, 0x347f206b, 0x013e0382, + 0x19020d36, 0x1508840f, 0x09116106, 0x0d13450b, 0x0a14120e, 0x0d0c5709, 0x6b20cb01, 0x03837f34, 0x5fcefe35, 0x06071510, 0x02081266, 0x120ee510, + 0x04800e12, 0x5718062c, 0x34080a11, 0x13000003, 0x2b211121, 0x56feaa01, 0xaafeab01, 0x00000700, 0xeb011500, 0x37000002, 0x3f003b00, 0x47004300, + 0x5d005300, 0x07010000, 0x17171406, 0x22262707, 0x25098e07, 0x37373216, 0xa9823436, 0x09911720, 0x03222625, 0x82372707, 0x25372136, 0x032e0786, + 0x023e3215, 0x0e142335, 0x32152702, 0x09823636, 0x0106062d, 0x0d0d4349, 0x0c1b0f1a, 0x831e0d23, 0x0d1a2b08, 0x0d430d23, 0x230d4b0d, 0x0f87440c, + 0x0c0c1e23, 0x2021821b, 0x82118324, 0x17c92c18, 0x1779164b, 0x1701174b, 0x82174c17, 0x3c163308, 0x1e354627, 0x3629172b, 0x1c311d1f, 0x011d122a, + 0x458243f3, 0x1a0f1a23, 0x2053820d, 0x823b8423, 0x8223203a, 0x440d2354, 0x0f85240c, 0x21871e20, 0x4c271183, 0x1764fe0c, 0x821e164c, 0x8280204f, + 0x33078258, 0x2b6bfe16, 0x2746351e, 0x1729361f, 0x311c2a55, 0x121d111d, 0x410af458, 0x2608063b, 0xfe800140, 0xfec00180, 0x00020080, 0x01270015, + 0x00d501f9, 0x002c0010, 0x35263700, 0x17373634, 0x14150606, 0x83173717, 0x262733fe, 0x06060726, 0x06071717, 0x16170707, 0x36373736, 0x13822736, + 0x23233f08, 0x06510722, 0x16171a1e, 0x17230619, 0xfb174b4b, 0x0c190639, 0x6706080c, 0x07040b46, 0x07160884, 0x050c0e76, 0x0e16051e, 0xfc090a61, + 0x522e1d1c, 0x461d1620, 0x221a1c27, 0x164b4b16, 0x29827319, 0xcd302f82, 0x180b0311, 0x04040330, 0x0f1d083a, 0x04100d5b, 0x3358aa82, 0x00ab2705, + 0x25000017, 0xee53023e, 0x15172c0b, 0x37170727, 0x15010727, 0x49172619, 0x172c0525, 0x1e221926, 0x221e5555, 0x2c1e05d7, 0x08e99018, 0x5b051e22, + 0xde821585, 0x15002b2a, 0xeb01d501, 0x32001b00, 0xa2425082, 0x3203351a, 0x3317021e, 0x2223032e, 0x23350706, 0x23353315, 0xaa013636, 0x3416ae42, + 0x2e3d26ac, 0x0621061d, 0x2c493723, 0x20255c34, 0x57223e6a, 0x13b74299, 0x12240130, 0x1710211d, 0x2317252d, 0x206a2b1e, 0xe182231d, 0x95002b26, + 0x6b01ab01, 0x3720e183, 0x8705b54e, 0x230721e5, 0xe282de82, 0xeb20cd95, 0xe0abf691, 0xd4842720, 0xb34b1520, 0x33072605, 0x3233033e, 0x2ae09816, + 0x206a3e03, 0x2c345c25, 0x82233749, 0x2e1d24e6, 0x9530263d, 0x20e42de0, 0x231e2b6a, 0x172d2517, 0x121d2110, 0xcd18de83, 0x172007f3, 0x07524718, + 0x08735818, 0x07333722, 0x0723dc82, 0x41290117, 0xd74114ad, 0x08a04213, 0xa042eb20, 0x27132505, 0x27071737, 0x17275183, 0x35262607, 0x42173734, + 0x2c2d1aa0, 0x174b4b17, 0x16190623, 0x061e1a17, 0x1aa042d6, 0x84890121, 0x1c1b2b29, 0x171d4626, 0x1e2d5221, 0xa142a71c, 0x0155251c, 0x00d5016b, + 0xcf84e083, 0x91483720, 0xad541805, 0x15012109, 0x41057f42, 0x01210bb0, 0x20138584, 0x82fb8d5b, 0x430020e0, 0x17260681, 0x00003300, 0x02543313, + 0x07ac4105, 0x36343528, 0x35331537, 0xe79a0523, 0x1e2b1528, 0x2b1e2222, 0x0683206b, 0x016b2023, 0x23ea9b12, 0x345c25b5, 0x2607b242, 0x22573030, + 0x98cd6a3e, 0x00032ceb, 0x02400000, 0x00ab0100, 0x83270012, 0x5137209d, 0x5e5005ed, 0x01072406, 0x18262637, 0x250ed659, 0x27371737, 0x845e3636, + 0xeb3e080b, 0x23243a22, 0x31281139, 0x844b4b84, 0x28000131, 0x17d5211c, 0x27181826, 0x18271717, 0x3709160c, 0x0606371e, 0x12121980, 0x12121818, + 0x3a24d519, 0x281c2122, 0x32393932, 0x112800ff, 0x27852339, 0x17261824, 0x29820606, 0x0c160924, 0x2b841912, 0x0004003a, 0x01350035, 0x00cb01cb, + 0x00110008, 0x0023001a, 0x23351300, 0x17072715, 0x21052c53, 0x0d820727, 0x33150529, 0x15371707, 0x82333533, 0x2a9a8203, 0x2bc03533, 0x37421e42, + 0x82378001, 0xff2b2206, 0x20068400, 0x20138580, 0x84148540, 0x8580200c, 0x85802013, 0x07002b12, 0x00002b00, 0xeb010002, 0x0b820300, 0x12000c28, + 0x22001600, 0x72822800, 0x2b061561, 0x15072737, 0x21150521, 0x37352626, 0x54087782, 0x14150717, 0x3e171616, 0x07353502, 0x37173727, 0x2a2a6b17, + 0xea2a2a80, 0xaa01d5d5, 0x080156fe, 0x2a690403, 0x26175640, 0x16271819, 0x14172b65, 0x2b011634, 0xeb969696, 0xea2b6b6b, 0x0b160a2b, 0x1046318f, + 0x301b372a, 0x23060623, 0x6b371b30, 0x3315172b, 0x08254a17, 0x0f00d622, 0x00227f82, 0x30560125, 0x1e3b0805, 0x36323302, 0x26031737, 0x26170706, + 0xfec40136, 0x11301e78, 0x4d3b2112, 0x1a3b212c, 0x3f239f30, 0x0d04621b, 0x1e88013c, 0x203c1a30, 0x213b4d2c, 0x01301112, 0x111301b7, 0x82442162, + 0x00c02a53, 0x01400155, 0x000b00ab, 0xa4831819, 0x3513210d, 0x2808075a, 0x01153315, 0x15151000, 0x3b038210, 0x1219153b, 0x1519122a, 0x0f166001, + 0x10161610, 0xf5fe160f, 0x1912606b, 0x6b601219, 0x0ad15a18, 0x4e003724, 0x50826500, 0x2b05644c, 0x16163233, 0x022e3717, 0x15233527, 0x6d05c163, + 0x23210514, 0x22138222, 0x82021e07, 0x3e352bdf, 0x26343503, 0x33352307, 0x87582315, 0x58332006, 0x27210697, 0x05347434, 0x35211a83, 0x05c24433, + 0x01154008, 0x0d1c1c13, 0x110e0712, 0x02220109, 0x2a13160c, 0x02091614, 0x0918170f, 0x0f1c1819, 0x050b140e, 0x18072301, 0x042a0718, 0x1a101713, + 0x35802bf9, 0x2832541a, 0x2b1e3545, 0x31554025, 0x8820643c, 0x08198807, 0x0a130123, 0x0d0b0f10, 0x040d0b05, 0x1314050e, 0x041b1a04, 0x01101614, + 0x09101812, 0x10130903, 0x110c1012, 0x3b61820e, 0x1b020c1a, 0x0e06011a, 0x2616151b, 0x262b80c6, 0x45351e2f, 0x40553128, 0x872d3725, 0x39200685, + 0x27081587, 0x35000d00, 0xc0013500, 0x0a00cb01, 0x22001600, 0x3a002e00, 0x52004600, 0x6a005e00, 0x82007600, 0x9a008e00, 0x11010000, 0x71064a4c, + 0x15200baa, 0x5a0a014e, 0x232108be, 0x0ce06122, 0x238a3720, 0x17203b8b, 0x1120178a, 0x2f8b2396, 0x3b8b5f8b, 0x28000125, 0x821e3545, 0x6bbd20de, + 0x078f07d2, 0x04073624, 0x03830704, 0x19873620, 0x96281188, 0x06050406, 0x06040506, 0x0b200787, 0x07bd4c18, 0x0d130b22, 0x0d1bc918, 0x01231988, + 0x5a80fec0, 0xeb280709, 0x090d0d09, 0x4c0c0c09, 0x07830382, 0x0784b420, 0x51861382, 0x0f845a20, 0xa20c0c22, 0x91206586, 0x07228885, 0x08868401, + 0x20873c20, 0x63206c86, 0x0ee0c918, 0x000c0035, 0x0215002b, 0x00c00100, 0x00170013, 0x001f001b, 0x82270023, 0x002f2213, 0x06474a33, 0x35010025, + 0x4c211123, 0x07830767, 0x35331524, 0xfd552301, 0x83332008, 0x8e132012, 0x5a01200f, 0x27200a1a, 0x2705ac4c, 0xd5000133, 0x2b552a01, 0xab220082, + 0x4d6efe2a, 0x2b2b2306, 0x00862a55, 0x2b2b0123, 0x8402822a, 0x6b012320, 0xa84cfe55, 0xab802306, 0xb14c00ff, 0xd6fe2106, 0x44820888, 0x2a2a2b23, + 0x080f82aa, 0x00020023, 0x01150080, 0x00eb01ab, 0x0040002c, 0x26220100, 0x30312727, 0x31232626, 0x15040e22, 0x37170733, 0x22b08233, 0x69163727, + 0x34240d96, 0x15062726, 0x09be4c18, 0x23260723, 0x320f8222, 0x29198b01, 0x1107110b, 0x1e23130e, 0x35091218, 0x8240222c, 0x0d0b2c63, 0x06151826, + 0x16060405, 0x6102a113, 0x2908059e, 0x0e050706, 0x15010c09, 0x0c24141b, 0x4037210c, 0x3c0c323f, 0x5656561a, 0x1c133980, 0x05150f06, 0xe0050606, + 0xad120ee0, 0xa3500607, 0x0d022605, 0x000e090d, 0x08c96703, 0x17000322, 0x2605484e, 0x22173521, 0x7015020e, 0xbc570a4a, 0xfe952310, 0x2c5c95d6, + 0x2917290b, 0x2b1b1f36, 0x1b2b1a1a, 0x01250584, 0x552b2bc0, 0x8a138218, 0xf6182423, 0x841a2c1a, 0x821b201d, 0x02002d08, 0x5500ab00, 0xab015501, + 0x18000b00, 0x2c0de144, 0x35231517, 0x36363723, 0x17163233, 0x09e04417, 0x322a5629, 0x0c0c1304, 0x44320413, 0xb52809e3, 0x0a885656, 0x880a0e0e, + 0x8f674f82, 0x00162a07, 0x2500001f, 0x35331121, 0x09461823, 0x152c0807, 0x32333533, 0x23353536, 0x07273723, 0x27152335, 0xfeab0107, 0x11ababaa, + 0x56111919, 0x191156aa, 0x1e6a402a, 0x1e372b37, 0x2b000195, 0x2b05e36c, 0x11192b2b, 0x371e6b40, 0x1e379999, 0x6b205c82, 0x2206915f, 0x821b0012, + 0x8b23205c, 0x2058845c, 0x23588837, 0x9696d66b, 0x3506bf7f, 0x1e6b152a, 0x1e382a38, 0x6b000180, 0x80fe1219, 0x12191912, 0x54872a6b, 0x5d000421, + 0xab3c05ff, 0x1e001a00, 0x26002200, 0x14130000, 0x27171616, 0x27071737, 0x022e3537, 0x023e3435, 0x20064d5f, 0x08b48205, 0x35233746, 0x15330733, + 0x27174023, 0x561e2019, 0x25221e56, 0x2918233c, 0x40401f36, 0x011d301e, 0x6b96c095, 0xc0c0966b, 0x2c1a1501, 0x1f1f041e, 0x221e5556, 0x402a0401, + 0x29361f26, 0x301d2b18, 0x2b96961e, 0x00969540, 0x55247683, 0xc001d501, 0x37247689, 0x37363634, 0x2005054a, 0x06f84115, 0x23353327, 0x37262622, + 0x05345015, 0x76982720, 0x2ac0d522, 0xeb207584, 0x95827483, 0x6b3c7491, 0x0096eb40, 0x00400005, 0x01f30115, 0x000b00c0, 0x001f001b, 0x002e0024, + 0x27352500, 0x2107e662, 0xfa783733, 0x3971830e, 0x23071705, 0x27073735, 0x17323637, 0x01141617, 0x00ff55c0, 0x12191912, 0xbc56379e, 0x82c0200b, + 0x262a36f2, 0x12b0266a, 0x09031226, 0xf7031703, 0x12195574, 0x1912d6fe, 0x0a4d5a80, 0x8655ae2a, 0x65266b25, 0x03132512, 0x09252282, 0x2b000200, + 0x05456a00, 0x39002631, 0x35010000, 0x2135023e, 0x17161614, 0x82030e15, 0x237c08f4, 0x3233043e, 0x2317031e, 0x2e343315, 0x26220702, 0x3e373435, + 0x0e303104, 0x01060703, 0x2c4e302b, 0x4e2c56fe, 0x333c1d30, 0x0653801e, 0x232b2b21, 0x2b230808, 0x5306212b, 0x3c331e80, 0x0d191248, 0x1f211a05, + 0x0f0d0814, 0x010c050e, 0x25074015, 0x351f1f35, 0x06400725, 0x3b54371e, 0x21392c2a, 0x10040410, 0x2a2c3921, 0x1e37543b, 0x121119e4, 0x0f0e060c, + 0x1e15080d, 0x0c051b21, 0x0f679c82, 0x00072207, 0x289c8211, 0x35072707, 0x11371737, 0x20088223, 0x08088215, 0xc0013324, 0x67635dc0, 0x5964bc5d, + 0x843c4083, 0x8b01556b, 0x35485d8b, 0xff885d4b, 0x2d7e4700, 0x55802b35, 0x97650500, 0x0547450c, 0x20105664, 0x06234503, 0x07861720, 0xfeab0122, + 0x099afa18, 0x8256d121, 0x82802000, 0x01562403, 0x411219ab, 0x0129057a, 0xfe191200, 0x562a56ea, 0xc20382d6, 0x55c72163, 0x6b200082, 0x55200382, + 0xf524638e, 0xc0551655, 0x63c20382, 0x5e83cc20, 0x63927520, 0x2055f024, 0x0382ca55, 0x3c0a6f41, 0x003c002e, 0x0e220100, 0x022e0702, 0x050e2223, + 0x023e3331, 0x17021e37, 0x33033e33, 0x26078332, 0x07062e30, 0x85070622, 0x26730815, 0x14550126, 0x060f171e, 0x111c1708, 0x11161b11, 0x2b04080c, + 0x0b191606, 0x0616190a, 0x130f042b, 0x13080812, 0x2b040e13, 0x0b070401, 0x121d1510, 0x060b1a10, 0x0b0a1411, 0x0a061113, 0x28c0011b, 0x1f275042, + 0x311e2136, 0x1e323b3b, 0x0b446138, 0x3861440b, 0x18272d14, 0x142c2719, 0x48453720, 0xd5203745, 0x54330e12, 0x38090939, 0x120e3355, 0x82000500, + 0x00023000, 0x1600ab01, 0x2d001f00, 0x43003b00, 0x56250000, 0x37241e1d, 0x23262607, 0x2729b482, 0x32333636, 0x16320716, 0x21108917, 0x15850717, + 0x56eb0121, 0x5e08112d, 0x6c292d2b, 0x296c3e3e, 0x4b84312d, 0x30cf844b, 0x172e2056, 0x3e23233e, 0x56202e17, 0x0e4b4b7b, 0x27161627, 0x1912156b, + 0x0d151219, 0x0d084009, 0x0940080d, 0x0c09150d, 0x2dc0090c, 0x292f2f29, 0x3939322d, 0x2d202547, 0x171b1b17, 0x9f25202d, 0x110e4c4c, 0x00030011, + 0x01c00055, 0x824001a0, 0x001a2bcc, 0x3700002c, 0x35233523, 0x03821733, 0x35363222, 0x2322ca83, 0x3e663315, 0x37332105, 0x12830e88, 0x3233152a, + 0x20209536, 0x2b408b40, 0x4b206c83, 0x60230683, 0x82080d80, 0x402b2808, 0xc00d084b, 0x82602060, 0x08202389, 0x0682200d, 0x56153522, 0x16270883, + 0x000d2015, 0x82400006, 0x82c02073, 0x00172d73, 0x00290025, 0x003e003a, 0x01000042, 0x15347982, 0x15333533, 0x23230614, 0x35352622, 0x33333634, + 0x21151632, 0x85069876, 0x8207200e, 0x8415838f, 0x86352025, 0x82272009, 0x82152037, 0xc0012518, 0x202b2b20, 0x0d27f984, 0x0d084009, 0x8620ebfe, + 0x2617820e, 0x0c0c0995, 0x82555509, 0x2a3e2905, 0x15012a2a, 0x160b400b, 0x9882b983, 0x6b080d25, 0x826b2020, 0x8213200c, 0x8214823c, 0x350582c6, + 0x30101020, 0x00030010, 0x022b002b, 0x00ab0100, 0x00140010, 0xb6430020, 0x35332c09, 0x35213523, 0x21072634, 0x48172135, 0xb7430acf, 0xd6d62f07, + 0x11198001, 0x5601aafe, 0x402b4055, 0x54432b40, 0x802b2a07, 0x56191280, 0x402aeb2b, 0x82028240, 0x00552160, 0x01251b82, 0x000d00d5, 0x2560841d, + 0x15062223, 0x5f6e1403, 0x82112005, 0x181420f0, 0x22080144, 0x18333517, 0x2c0e3ea7, 0x141c4056, 0x141c1c14, 0x40550c0f, 0x094e5676, 0x6a000123, + 0x26168350, 0x52081c14, 0x8275752b, 0x07734164, 0x4300212a, 0x00005b00, 0x15333537, 0x6741c082, 0x2315220a, 0x07427135, 0x23230626, 0x33172622, + 0x84070142, 0x2634212a, 0x06221482, 0x97821515, 0x2a843320, 0x27161422, 0x2c83138b, 0x18822320, 0xcb2a5682, 0x09352a20, 0x40090c0c, 0x09890c09, + 0x0840a026, 0x36080d0d, 0x20089e41, 0x20098235, 0x09a942b7, 0x2b2b2026, 0x0b16d520, 0x21053142, 0x0988080d, 0x20233382, 0x41150d09, 0x098705aa, + 0xb7416b20, 0x0b163908, 0x04000b40, 0x15002b00, 0xeb01c001, 0x16000800, 0x26001a00, 0x21250000, 0x1124d982, 0x03211133, 0x83087648, 0x230722a0, + 0x82f48235, 0x820783a5, 0x800132a9, 0x1911d5fe, 0x402b012a, 0x19191295, 0x1912eb11, 0xd9fb1860, 0x19152a07, 0xfe2b0112, 0x19ab01d5, 0x2f238312, + 0xabd61119, 0x2b2b552b, 0x002a2a2b, 0x00400002, 0x01210482, 0x286b82d5, 0x0100003e, 0x23263435, 0x0e701823, 0x2335250f, 0x07152135, 0x20061d6d, + 0x05f34334, 0x21050656, 0x4a183636, 0x27230b85, 0x1819c001, 0x29073771, 0x95951219, 0x07472a01, 0x48671927, 0x1b0f2805, 0x20551f0a, 0x5d15270e, + 0x19260539, 0x01051e2c, 0x70188000, 0x2a250b2e, 0x17ab2bd6, 0x05dd621e, 0x200a0b29, 0x100e1e55, 0x821d311c, 0x2716222e, 0x2aa28218, 0x010f000f, + 0x00d301d5, 0x82150009, 0x272325a7, 0x35360123, 0x2521ad82, 0x3e2f1907, 0xabab290a, 0x3e01432b, 0x71fe1905, 0x07499618, 0x80011e35, 0x0ac1fe2b, + 0x1912d50a, 0x0a211e53, 0x1200ff0a, 0x421e4619, 0xb5260643, 0x0b004001, 0x88512d00, 0x85152005, 0x153322f6, 0x212d4233, 0x35262a82, 0x208b1523, + 0x02822b20, 0x0940d529, 0x35090c0c, 0x660c202a, 0x098305c4, 0x20362c2c, 0x35804001, 0x552b8035, 0xf441080d, 0x60202211, 0x08dd4f80, 0x1e00c427, + 0x00003100, 0x1da24225, 0x9e892720, 0x3727352a, 0x23270701, 0x247c0135, 0x1921788f, 0x279184a7, 0x88011e6d, 0xc02fa21e, 0x2e217a90, 0x39928359, + 0xfe1e6d24, 0x2ea21e78, 0x00000400, 0x0002c000, 0x0b004001, 0x25001d00, 0xe0502b00, 0x26da8205, 0x15333523, 0x63232533, 0x0a8205fc, 0x70083643, + 0x05220578, 0x24822335, 0xff854b20, 0x602a0132, 0x15200d08, 0x0d201620, 0x20256b93, 0x35150126, 0x2b28fc87, 0x606b080d, 0x6b604b4b, 0x60222082, + 0xf6856060, 0xc0008024, 0x73826b01, 0xf6842120, 0x8520bb43, 0x076b5af9, 0x01223026, 0x362b2000, 0x32061346, 0x09352b20, 0x40090d0d, 0x20400d08, + 0x200d1320, 0x4313130d, 0x73231378, 0x82151560, 0x600d3a1a, 0x15000300, 0xeb011e00, 0x0500c401, 0x1f001400, 0x37250000, 0x23273717, 0x08ea6f27, + 0x01220e82, 0xee7d1707, 0x35220805, 0x01373634, 0x562a0269, 0x1dbdae2b, 0x233a2323, 0xa2113a24, 0x1e78fe1e, 0x172205b5, 0x1c121d11, 0x1c82d315, + 0x11442a23, 0x291c833b, 0x1ea21d23, 0xb61e8801, 0x1a821c14, 0x05231622, 0x384c6182, 0x00142d07, 0x001c0018, 0x00240020, 0x27070100, 0x11200189, + 0x20061845, 0x06a64623, 0x07823520, 0x35213527, 0x23d50121, 0x84018324, 0x19232b04, 0x11560111, 0x9696ea19, 0x008296c0, 0x01aafe26, 0x24c00156, + 0xfe2c008a, 0x191912ab, 0x2a808012, 0x402a2b2b, 0x40337582, 0xcb01c000, 0x0b004001, 0x1b001700, 0x2b002700, 0x44010000, 0x5e8205e6, 0x27331528, + 0x23061415, 0x0b821523, 0x07163226, 0x25331523, 0x01240f8e, 0x2a202015, 0x6a2c0282, 0x202b0c14, 0x20140c4b, 0x40012b2b, 0x802e0b8b, 0x2b803535, + 0x130d150b, 0x0d13802b, 0x08871515, 0x0004002d, 0x012b0040, 0x008001c0, 0x84070003, 0x0100217d, 0x2a05d754, 0x35330733, 0x17371723, 0x83372737, + 0x071724fd, 0x83eb2b01, 0x95952600, 0x1e3738f3, 0x2b028237, 0x38381e38, 0x802b2b01, 0xaa2aaa2b, 0x15850f83, 0x02003724, 0x53828c00, 0xc0017636, + 0x30002400, 0x3e370000, 0x36363702, 0x22232626, 0x27070606, 0x25052452, 0x07061616, 0x0282020e, 0x34231523, 0x0b1c7934, 0x08ec2208, 0x070a1819, + 0x15190a02, 0x040e1912, 0x2f200737, 0x0d34251e, 0x0c040907, 0x0714180c, 0x3e010303, 0x05df4e49, 0x19122308, 0x16170fee, 0x1a1a0b0d, 0x0c170f10, + 0x17271618, 0x240d151e, 0x17131127, 0x0a040d13, 0x250c0f12, 0x3d731187, 0x00042206, 0x20e38415, 0x22df84d5, 0x8236002d, 0x2a4a1893, 0x8a33200a, + 0x3327240b, 0x82373632, 0x6ec418ef, 0x1713290d, 0x23372707, 0x95273335, 0xc4185286, 0x6b271d71, 0x221e5555, 0x5f225959, 0x192008ff, 0x23060760, + 0x950a0c6b, 0x0973c418, 0x83150121, 0x222a2427, 0x41000100, 0xd5200583, 0x0025a782, 0x27373301, 0x06ab5d23, 0x17072332, 0x35331533, 0x01233533, + 0x40406b15, 0x96962a6b, 0x01260686, 0x2a40402b, 0x0582802a, 0x8055552e, 0x2b000500, 0xd5012d00, 0x0200d501, 0x082f0b82, 0x2d001600, 0x07130000, + 0x37152135, 0x46371527, 0x37200503, 0x08050246, 0x23170660, 0x35022e15, 0x023e3435, 0x021e3233, 0x06141515, 0x55950706, 0xea554001, 0x4b16d555, + 0x164b3434, 0x2d2d4325, 0x80d52543, 0x2126442b, 0x2c2c4d3b, 0x26213b4d, 0x95012b44, 0x2a55552a, 0x812b5540, 0x080d0d08, 0x09090b02, 0x0468970b, + 0xc00f1813, 0x0a12170d, 0x0d17120a, 0x12180fc0, 0x7f180005, 0x0f2609c7, 0x17001300, 0xb0481d00, 0x3221340a, 0x34113536, 0x35210326, 0x35230721, + 0x37270733, 0x4c173727, 0x112c0c65, 0x5601aafe, 0xe080802b, 0x1e37371e, 0x260f054c, 0x2bc0d5d5, 0x82381e2b, 0x0cb34818, 0x24001022, 0xb3486382, + 0x1735240d, 0x43153707, 0x61480534, 0x2b01250a, 0x011911ab, 0x2a05d25e, 0x2a607696, 0x55090d2a, 0x820c0c09, 0x480d2004, 0x15260bb9, 0x176b7575, + 0x9c491758, 0x016a1809, 0x0586520c, 0x20143c4d, 0x06124417, 0x280c6c71, 0x552b2be7, 0x2b562a2a, 0x0d51712b, 0xd6d5fe26, 0xabab6b6b, 0x37205aa7, + 0x03835a82, 0xa7235a8c, 0x84408080, 0x235a8f02, 0x2b2a2b2b, 0x45052166, 0x222d0937, 0x33250000, 0x23353335, 0x07013713, 0x093b4517, 0x15142723, + 0x09df4914, 0x04bc012a, 0x1e94d92b, 0x371e78fe, 0x20073d45, 0x05be4244, 0x8001032b, 0xf3fe5655, 0x1e88011e, 0x073c4537, 0x0301442b, 0x12191912, + 0x00011912, 0x08386b03, 0x49002428, 0x00007100, 0x46183337, 0x272308d2, 0x18020e23, 0x18086462, 0x2b0b3cad, 0x16163213, 0x26343315, 0x22312326, + 0x17209184, 0x26056f7f, 0x35363233, 0x56372734, 0x17230596, 0x84270722, 0x32332909, 0x07141516, 0x31333617, 0x22503683, 0x33272105, 0x2a08d259, + 0x0f097ed5, 0x0d13130d, 0x5955090f, 0x1c2805bf, 0x13182716, 0x111d1218, 0x36240282, 0x2a121d11, 0x3f059948, 0x0b320f12, 0x0e0d130f, 0x15480112, + 0x721d111c, 0x0b411114, 0x0d0e120f, 0x0a2f0213, 0x1c311d09, 0x31242583, 0x1410390e, 0x12233282, 0x830bc01d, 0x180a2e2a, 0x301d1627, 0x1e2c191e, + 0x21072c05, 0x054a5014, 0x82000121, 0x30308507, 0x530f2817, 0x0e0b1202, 0x050e1212, 0x23057804, 0x253b8217, 0x026c0cc0, 0x91830c12, 0x4d050523, + 0x227b8501, 0x820a181d, 0x22028219, 0x50000600, 0xc22f0572, 0x1b000d00, 0x37002900, 0x4d004a00, 0x85370000, 0x463720f4, 0x252105dc, 0x55f01807, + 0x2526210a, 0x17201485, 0x17262285, 0x26353636, 0x21862726, 0x67732720, 0x16142205, 0x06127617, 0x07363627, 0x199c1737, 0x32008210, 0x16161519, + 0x19191001, 0x19191a1a, 0xfe1f1e20, 0x821f19cc, 0x250f8300, 0x021615fb, 0x24841514, 0x1f164308, 0x0a1f1616, 0x0e2b4808, 0x482b0e64, 0x24590a08, + 0x101ac624, 0x28141427, 0x34151a0e, 0xe7341c1b, 0x21431a19, 0x1a194322, 0x292a4e20, 0x2019074e, 0x4e2a294e, 0x43191a20, 0xc9432122, 0x1b1c3415, + 0x2f821534, 0x28151337, 0x1f164b0e, 0x150c161f, 0x2a2ad807, 0x9f1507d8, 0x07006b6b, 0x07c25000, 0x17000f22, 0x20086952, 0x111a4429, 0x37170725, + 0x82270717, 0x82332001, 0x83332009, 0x210385ca, 0xf8423723, 0x2ac3310c, 0x2a6d1e4f, 0x241b1e40, 0x27401224, 0x23402d40, 0x22240382, 0x25255240, + 0x240d0943, 0x1e4e2b6e, 0x2327826c, 0x401b2548, 0x25200084, 0x200add4f, 0x25968203, 0x15211300, 0x03821121, 0x28056e5f, 0x0180fe80, 0xd6fe2bc0, + 0x8d4b182b, 0x0517470a, 0x35202888, 0x30882c8c, 0x472ad521, 0xd520084a, 0x21064a47, 0x348c000f, 0x3c833891, 0xfe2ad524, 0x01832aaa, 0x000f0022, + 0x85075e64, 0x00103d71, 0x00190015, 0x0021001d, 0x00290025, 0x0033002e, 0x00470044, 0x3700004d, 0x17233533, 0x132e0382, 0x37331523, 0x26343315, + 0x14233501, 0x15862716, 0x35201d83, 0x0f830b82, 0x35270725, 0x83131533, 0x01172304, 0x2e821707, 0xa0183520, 0x200808d6, 0x37173527, 0x33272335, + 0x2b2b4015, 0x802b2b55, 0x2b802a2a, 0x2bc4fe19, 0x2b2b1919, 0xaa2a2aab, 0x8200822b, 0x12993d17, 0x2b12e72b, 0x1e78fe04, 0x2a2b193b, 0x2b192b99, + 0x3c44e63b, 0xeb992a44, 0x012bd52a, 0x2b242082, 0x80fe1912, 0x55220482, 0x4482802b, 0x2a2b2b23, 0x2a0c822b, 0x1200ff2b, 0x01592b19, 0x823b1e88, + 0x2a992631, 0xa23b192b, 0x23368244, 0x0600992b, 0x4508287d, 0x23240547, 0x2f002700, 0x200a0742, 0x069c5533, 0x2634112b, 0x21112103, 0x23153305, + 0x20cd8233, 0x20bc8235, 0x200b8207, 0x200b8207, 0x460b8215, 0x56240734, 0x191156aa, 0x2505e34e, 0xababd5fe, 0x008220e0, 0xabab8b23, 0x22068235, + 0x55c00120, 0x012009bb, 0xfe2f9082, 0x450001d5, 0x561b2020, 0x551b201a, 0x1800201a, 0x2809faa9, 0x000c0008, 0x00140010, 0x2b888218, 0x37112111, + 0x15313715, 0x17333737, 0x03836d83, 0x71833320, 0xfed52008, 0x446b9556, 0xe6114011, 0x2b562a2a, 0x2b2bd62b, 0x00ff2b01, 0x2b400001, 0x8a20402b, + 0x8255cb8a, 0x350e8200, 0x01400055, 0x00c00180, 0x37000017, 0x17372707, 0x16163607, 0x09843517, 0x2311273c, 0x07022e35, 0x56561ec9, 0x2810221e, + 0x1e220f27, 0x221e5556, 0x2d24072b, 0x0a84b316, 0x0f040431, 0x1f228b0e, 0x211e5555, 0x1c55d2fe, 0x82050a1f, 0x82802051, 0x85ab2051, 0x17252a51, + 0x17072737, 0x07060626, 0x28098435, 0x35331137, 0x0117023e, 0x2052ac37, 0x057a4404, 0x0000022c, 0x0024000f, 0x002c0028, 0x22700100, 0x35073e0e, + 0x34262633, 0x06222337, 0x21371115, 0x35353632, 0x07230606, 0x37333523, 0x01213521, 0x05534555, 0x3405c944, 0x090dc1d5, 0x1912d702, 0x112b0155, + 0x12210d19, 0x55abab6a, 0x21b682ff, 0x7055c001, 0x2b59320a, 0x081b2111, 0x80fe1119, 0xc0121955, 0x2b800c0a, 0x0be36d15, 0x00001125, 0x82372737, + 0x05274165, 0x17141528, 0x89270717, 0x3962671e, 0x67192406, 0x8240771e, 0x6d23290d, 0x55551e21, 0x236d211e, 0x63821183, 0x40006b28, 0xc001ac01, + 0x37621b00, 0x1842611d, 0x0f62c420, 0x130d280a, 0x04800d13, 0x4919062c, 0x10200a8f, 0x26085782, 0x37352715, 0x15233533, 0x33152307, 0x35331517, + 0x3a804001, 0x5c39805b, 0xab80956b, 0x4243401b, 0x80426880, 0x8280354b, 0x82ab2035, 0x8295208d, 0x22cd828d, 0x87112325, 0x021e28ca, 0x27260717, + 0x602a1501, 0x1c29055b, 0x1f0f2c29, 0x0140243d, 0x28cb852e, 0x2d39222e, 0x2520091f, 0x20ce8631, 0x22408555, 0x41113337, 0x152805e1, 0x07020e14, + 0xeb373617, 0x22253f90, 0x1e55551f, 0x223f8621, 0x6a003026, 0xab3d054a, 0x1400cb01, 0x29002000, 0x00003200, 0x031e3001, 0x06061415, 0x022e2307, + 0x033e3435, 0x42551817, 0x2e072c0a, 0x06072702, 0x35211515, 0x82272734, 0x00012c63, 0x131d1d13, 0x7c06100c, 0x830c1006, 0x4b2b200a, 0x3b080768, + 0x0d100587, 0x01131802, 0x02181356, 0x0105100d, 0x331d0dcb, 0x391b364d, 0x32101032, 0x4d361b39, 0xb60d1d33, 0x12191912, 0xba191911, 0x1d3a2f0d, + 0x7e170d10, 0x100d177e, 0x0d2f3a1d, 0x08066543, 0xcc01cc21, 0x21000a00, 0x42002c00, 0x00004e00, 0x07030e13, 0x1f363727, 0x023e3002, 0x26033e37, + 0x82262627, 0x030e2381, 0x18821731, 0x3637172e, 0x14072727, 0x040e0706, 0x033e3031, 0x2005fa59, 0x0b465d16, 0x10c43e08, 0x010c141b, 0x1710564d, + 0x281a2a1c, 0x2723112b, 0x02040412, 0x352a1c06, 0x1d11233e, 0x13e40c15, 0x021a2629, 0x05115621, 0x090ab905, 0x22251f07, 0x0a070315, 0x1808080c, + 0x111d120d, 0x08bf7c55, 0x27897920, 0x150ce435, 0x3e23111d, 0x061c2a35, 0x12040402, 0x2b112327, 0x892a1a28, 0x0d443267, 0x0c080818, 0x1503070a, + 0x071f2522, 0x1d110a09, 0x82f283ae, 0x18002003, 0x2009fb41, 0x22d98228, 0x4833023e, 0x0729069d, 0x34352315, 0x023e3736, 0x067a4b35, 0x06060725, + 0x82172323, 0x07173cf8, 0x362405d7, 0x223a241f, 0x2b1e301c, 0x20141014, 0x18271713, 0x04172415, 0x65101802, 0x013c0617, 0x1c301f55, 0x20233a23, + 0x82052435, 0x03171082, 0x15241803, 0x12172618, 0x140f1421, 0x8d054a42, 0x18012079, 0x2209ad41, 0x82331517, 0x72272073, 0x1624086a, 0x33161617, + 0xc509d863, 0x00ab287a, 0x01550140, 0x820800c0, 0x23d384f4, 0xeb231127, 0x2a229885, 0xdc426e01, 0xd2fe2105, 0x4028a382, 0x6b015500, 0x0d008001, + 0xfd852882, 0x16323327, 0x35231515, 0x05c14292, 0x1912ae25, 0x4515012b, 0x1923050b, 0x82c0c012, 0x82952032, 0x85c02032, 0x5a012032, 0x23200589, + 0x2105d550, 0x33986e01, 0x78454020, 0x88122006, 0x8615208f, 0x22232467, 0x82803526, 0x1e562399, 0x6b82aa22, 0x9f870382, 0x12198326, 0x12198080, + 0x20066445, 0x82cd82c0, 0x4301203d, 0x72860678, 0x36323324, 0x3e8f0135, 0x3e8b8585, 0x83059f61, 0x473520e3, 0x35370668, 0x33272734, 0x6a2b79f9, + 0x306a0d2b, 0x792b8001, 0xa2a26b30, 0x826b0c12, 0x82c0206d, 0x018023df, 0x2e8200ab, 0x33350126, 0x07352315, 0x34250382, 0x01233737, 0x872f9407, + 0x001a26db, 0x23110100, 0x064f4211, 0x37151527, 0x37270717, 0x053d6f17, 0x82161621, 0x26172563, 0x17261818, 0x22054b41, 0x82233a23, 0x05cb6a02, + 0x1a821482, 0x18825920, 0x221e5623, 0x8a198459, 0x235682f4, 0x11331113, 0x20070346, 0x05c36715, 0x2107b642, 0x55ab2b80, 0xe0470420, 0x47082008, + 0x00260655, 0x07271125, 0xe7823311, 0x15232724, 0x03823733, 0x03821720, 0xd5012408, 0xd66ad5d5, 0x2a2b2b80, 0x2b2b2a2a, 0x2b01402b, 0xd5fe5555, + 0x2b2bc0c0, 0x2b152b6b, 0x00000300, 0x5f024000, 0x192605f6, 0x00002900, 0x8b5c2213, 0x06866106, 0x2105d648, 0x204b1537, 0x43152005, 0xc0200565, + 0x20060a61, 0x2d078628, 0x452a5114, 0x2f2f2666, 0x213a2526, 0xd77a3a21, 0x37228b05, 0x7451e6fe, 0x2ef14562, 0x2d2d4812, 0x0d2e1248, 0x2a2a4836, + 0x08003648, 0x6008904f, 0x00210f71, 0x0f675501, 0x4e0ed34e, 0x07200702, 0x83060a4e, 0x9501260f, 0x2baa2b15, 0x4e4b1815, 0xfe122608, 0xd52a01d6, + 0x06164e2b, 0x1f4eab20, 0x2aab2108, 0xed550082, 0x2b012807, 0xaafe1912, 0x832b56d6, 0x84802000, 0x03002305, 0x62468000, 0x00212f06, 0x0033002a, + 0x36360100, 0x27263435, 0x68542335, 0x05165905, 0x35331523, 0x20038233, 0x281b8532, 0x15163233, 0x23230614, 0x84908217, 0x6c012a0a, 0x1c240b09, + 0x402b2a2b, 0x2502822b, 0x26182b2a, 0x45491617, 0x6b562305, 0xa4826b6b, 0x0b090128, 0x2e1e101c, 0x74822d07, 0x2ad62a22, 0x2b2c0582, 0x17182617, + 0x12196d27, 0x56801912, 0x89820583, 0x1500402a, 0x0002c001, 0x1e000c00, 0x00278b82, 0x14152725, 0x6b161717, 0x072005b3, 0x27210786, 0x06b25726, + 0x246d1720, 0x11012b0b, 0x0ca60dd1, 0x0c850c24, 0x0685c10c, 0x120ca73b, 0x0d191284, 0x0f0f0b4e, 0x10100b0b, 0x122bd140, 0x0d0da60c, 0x0d230d84, + 0x23068456, 0x190ca70c, 0x0c232282, 0x850b108d, 0x02002d23, 0x40001500, 0xd501eb01, 0x1a000800, 0x0babd518, 0x23272323, 0x05255822, 0x36322139, + 0x26343535, 0x12192b40, 0x95fe6b01, 0x2b958001, 0x1919116b, 0x832b0111, 0xfe802ae4, 0x2b1912eb, 0x192a4001, 0x24088211, 0x12c01219, 0x20548219, + 0x37548228, 0x00c201d8, 0x00480012, 0x22060100, 0x27072727, 0x37362626, 0x16363637, 0x1428de82, 0x07141637, 0x26260606, 0x06211782, 0x21ee8414, + 0x08980717, 0x82363621, 0x26300827, 0x01070626, 0x06120760, 0x0c0e975f, 0x5b0c0909, 0x0c21210c, 0x0c09066e, 0x11140b0c, 0x7750020b, 0x12060606, + 0x620f6306, 0x11060707, 0x63106207, 0x07850f86, 0x3285b220, 0x0d20203d, 0x06062201, 0x0d0d965f, 0x5a0d2021, 0x0d08080d, 0x2712066d, 0x0a0c240c, + 0x83080505, 0x82122044, 0x10632236, 0x224a8262, 0x82620606, 0x0611264c, 0x0f620707, 0x22528263, 0x84b20606, 0x090c3334, 0x01000b08, 0x80002b00, + 0x8001d501, 0x00001600, 0x87672725, 0x3c721807, 0x14153609, 0xb7000117, 0x018bb51e, 0x086e8b56, 0x1f1f160a, 0x041f1616, 0x241182c7, 0x046e2b2b, + 0x270c8220, 0x0a0b161f, 0x40000200, 0x2206ad7e, 0x82200008, 0x84372049, 0x07332b4a, 0x21112117, 0x34353315, 0xcb5f2326, 0x32213407, 0x23353536, + 0x6a6a6b01, 0xc4c4371e, 0xd6fe4837, 0x5f2b2a01, 0x4a7a0591, 0x952b2e05, 0x381e6b6b, 0x0148382a, 0x122a2a2a, 0x201a8719, 0xc399182a, 0x00eb2808, + 0x002e001e, 0x184e003e, 0x2013fba9, 0x2a6b8221, 0x26272726, 0x22232726, 0x66220326, 0x152409c8, 0x21060614, 0x83500f8e, 0x47332007, 0xc02006a1, + 0x08b20b19, 0x0140ab31, 0x101e1316, 0x06160d3a, 0x5506053c, 0x4a111d12, 0x122305dc, 0x1819011d, 0x200ac948, 0x0ad24aa7, 0x05750137, 0x04071506, + 0xfe400704, 0x22173dc0, 0x040e0416, 0xfe060c12, 0x0b1b4ba4, 0x00220b97, 0xb0710008, 0x00d53705, 0x001b0003, 0x00340030, 0x003c0038, 0x00500040, + 0x35232500, 0x65443733, 0x14072e16, 0x15232306, 0x35231533, 0x33333634, 0x05d24335, 0x8307ae5f, 0x2003830e, 0x0ebf5c17, 0x2075012b, 0x2b403620, + 0x11402b80, 0x05965619, 0x0df11923, 0xd67b1809, 0x20452109, 0x85260086, 0x0935090c, 0x04820d0d, 0x40e00c23, 0x058c448b, 0x2309e85f, 0x150d09a0, + 0x07e17b18, 0x2b20ab24, 0x03822a20, 0x075bab20, 0x08546808, 0x0b00d526, 0x25001500, 0x0ea8cd18, 0x07273735, 0x31170606, 0x37251616, 0x06020f27, + 0x17020f06, 0x4915033f, 0xa93a0788, 0x0d611060, 0x1704030d, 0x16360401, 0x0dcb2a40, 0x3d100211, 0x7d194022, 0x7055eb6a, 0x1a4f3a06, 0x17031a3e, + 0x5d0d0d0d, 0x5540153e, 0x0d14033d, 0x561a515f, 0x004b2743, 0x246d8202, 0x01eb012b, 0x207782ab, 0x05214219, 0x52163221, 0x072305d1, 0x84173733, + 0x23072403, 0x49232727, 0x402f08f6, 0x591c9680, 0xb61aa63d, 0x4a0b2b0a, 0x49800196, 0x360806c7, 0x3f216b2e, 0xd58d1e60, 0x090015d5, 0x40002b00, + 0xd5010002, 0x51001000, 0x59005500, 0x61005d00, 0x69006500, 0x00007900, 0x33161401, 0x033e3732, 0x020e3031, 0x52370607, 0x152106b7, 0x20738533, + 0x05354735, 0x43180720, 0xe167109c, 0xfc421805, 0x33352408, 0x82363635, 0x01262524, 0x35173527, 0x17230386, 0x7c373507, 0x37210671, 0x0ebb4217, + 0x0d800135, 0x04060908, 0x0e050707, 0x06031113, 0x1c311d15, 0x82151d23, 0x110d2c13, 0x0a0b121d, 0x11801219, 0x82111919, 0x821286cc, 0x1c152715, + 0xfe301d24, 0x00842bcd, 0x2006c666, 0x0acd42c0, 0x096b013b, 0x1103070d, 0x07040e12, 0x61060308, 0x211d311c, 0x6b1e0c35, 0x090c0c09, 0x2126822b, + 0x8d43ae04, 0x08402509, 0x2b080d0d, 0x2405fd42, 0x350c1e6b, 0x2d7e8221, 0x3c2b8bfe, 0x3d2a2f2b, 0x3c2b2e2b, 0x0b82e72a, 0x3c2a2e22, 0x3d220b82, + 0x3b43712a, 0x82112007, 0x002d0830, 0x001e0006, 0x01d5011e, 0x000900d5, 0x00150011, 0x003a0021, 0x37000058, 0x37363233, 0x23262615, 0x35230523, + 0x01372733, 0x15332707, 0x08c65223, 0x23221d84, 0x20823435, 0x36323522, 0x23210782, 0x05b44335, 0x16160732, 0x31303027, 0x33363634, 0x15062215, + 0x33331614, 0x15201883, 0x23212b83, 0x35198223, 0x2c15152b, 0x152c1414, 0xae2e0115, 0x011efb6e, 0x43141e88, 0x0269e703, 0x20ea3307, 0x10182716, + 0x14101717, 0x0a0b1320, 0x13e7251e, 0x0e831321, 0x22142137, 0x11192014, 0x0506a021, 0x0a050540, 0xfe1efb40, 0x408d1e78, 0x06c76820, 0x30306a34, + 0x20172817, 0x17101018, 0x14201320, 0x0e0a1a0f, 0x42823c3a, 0x1015202b, 0x1f111b10, 0x151c2313, 0x6cee1816, 0x24e98308, 0x0019000d, 0x05ad5132, + 0x2523e787, 0x4d352115, 0x37200b80, 0x2620b384, 0xdf8ed882, 0x18840720, 0xad442320, 0x89e78a08, 0xfeaa23dc, 0xd49740d6, 0xc9833520, 0xdb8ad882, + 0x3621d785, 0x20d19c40, 0x22c68330, 0x89142014, 0x020022d8, 0x05ec7100, 0x1300d528, 0x00001700, 0x93181101, 0x2c080b4c, 0x33153335, 0x23071632, + 0x6b013311, 0x09aa090d, 0x2a090d0d, 0x0d092a56, 0x0180802b, 0x09abfe95, 0x01090c0c, 0x2a0d0955, 0xfe1e0d2a, 0x214ac8d5, 0x4aa500ff, 0x95a11520, + 0x49a294a6, 0x93c8ab20, 0x49c88020, 0x49c85520, 0x18002b21, 0x290927ea, 0x001b000f, 0x00530043, 0xfa440100, 0x087f5705, 0x18220721, 0x3609397d, + 0x26263537, 0x07062223, 0x23373636, 0x14150606, 0x26261716, 0x83161527, 0x06372c2b, 0x36330706, 0x26343536, 0x6a161627, 0xfd18104a, 0x12230c6a, + 0x82121919, 0x1fc33103, 0x3d22496d, 0x090a0217, 0x1a14092d, 0x1d300d16, 0xb823108f, 0x87233a23, 0x18012002, 0x200c0661, 0x82418480, 0x978c2045, + 0x204c883b, 0x20448aea, 0x05034623, 0x01d50126, 0x001400ed, 0x2205065e, 0x472c0028, 0x002706a9, 0x26342301, 0x82070726, 0xe0d818d9, 0x2303220a, + 0x26d68237, 0x33253335, 0x61112315, 0x23210569, 0x20078635, 0x37138637, 0x1240ab01, 0x0c400e1c, 0xab12190e, 0x11191911, 0x0e0c1872, 0x2a80fe40, + 0x5d6c0088, 0x0fc02a05, 0x1b060816, 0xfe0d1605, 0x07354cc7, 0x0aabfe2f, 0xf90d1505, 0xd6fe2b2b, 0x802b802b, 0x5603822a, 0x475806a8, 0x00d52905, + 0x0070003d, 0x2500007b, 0x0be49a18, 0x022e2223, 0x210f8323, 0xef5b3215, 0xec9a1805, 0x8f272014, 0x2235241c, 0x4f272726, 0x17220505, 0x408c2622, + 0x06173722, 0x06285283, 0x8e012723, 0x0d0e130f, 0x3619c318, 0x9b18e520, 0x0a320e39, 0x0f130e0d, 0x2b080e0a, 0xa6f6102d, 0x03141e21, 0x21840306, + 0x0e216282, 0x2e1c8309, 0x0e0b1e82, 0x0610130e, 0x6b130509, 0x8b070807, 0x182a2002, 0x2015249b, 0x2f168b20, 0xa104082a, 0xcd5e2712, 0x014a261a, + 0x2b060807, 0x9c311b85, 0x09060171, 0x00480207, 0x002b0005, 0x02eb012b, 0x3c098200, 0x000f000a, 0x001b0015, 0x07272500, 0x37171527, 0x17152327, + 0x21152715, 0x27353527, 0x830f8207, 0x35300803, 0x93374a01, 0x36615555, 0x01555580, 0x406b6aaa, 0x36368b40, 0x3116da60, 0x761d2d21, 0x821c4d49, + 0xc88d5b1c, 0x552b156b, 0x402b162b, 0x00552b2b, 0x00205982, 0x3005a573, 0x00130007, 0x06220100, 0x26010107, 0x23260726, 0x06726722, 0x00011737, + 0x0131844b, 0x31000100, 0x26210484, 0x2a7b2126, 0x63353563, 0x57d4182a, 0x12e82709, 0x221f7c12, 0x4c8c1f22, 0x4c891520, 0xd7671720, 0x274e8b0b, + 0x1c34161b, 0x5c16341c, 0xc826508f, 0x0e0f0f0e, 0x529a205b, 0x36360523, 0x09206833, 0xfe21a18a, 0x264c85f3, 0x25441c3d, 0x891c4425, 0x836c20a4, + 0x143e2fa1, 0x00141616, 0x002b0003, 0x01c0012b, 0xaf6f00d5, 0x01002205, 0x066e6d37, 0x23151722, 0x20072f4c, 0xfb9f1837, 0x23352110, 0x232e1382, + 0x23153315, 0x1e550001, 0x1e372b37, 0x07822255, 0x864c4c21, 0x23108708, 0x2b95ab4d, 0x01200082, 0x4d211c83, 0x891c8e4d, 0x6ad5222d, 0x054a4c16, + 0xd5010038, 0x2e000002, 0x45003900, 0x00006400, 0x36262725, 0x16173737, 0xd1461515, 0x05514b06, 0x6605c344, 0x118b0598, 0x0606372f, 0x34262707, + 0x17163637, 0x17060617, 0x2a0b8423, 0x37051732, 0x27353536, 0x82070626, 0x7922201c, 0x273a0584, 0x06072626, 0x16041f14, 0x06130a01, 0x7b050c08, + 0xeb161f10, 0x080d0d08, 0x05838060, 0x09958027, 0x95090c0c, 0x2f058375, 0x070e0d9b, 0x0607063a, 0x04100612, 0x30120102, 0x112b6382, 0x120c0107, + 0x180d0511, 0x82751004, 0x01062517, 0x66105106, 0x07370882, 0x4d395006, 0x27eb090d, 0x0306190c, 0x70171074, 0x080d1f16, 0x8d150d09, 0x067d2404, + 0x853d090a, 0x096d3436, 0x07330915, 0x06060611, 0x1710128f, 0x0b0402a9, 0x827b290d, 0x071124a1, 0x826d0f55, 0x07200856, 0x33540711, 0x00080d49, + 0x006b0001, 0x00ab0055, 0x000300d5, 0x15333700, 0x40406b23, 0x020080d5, 0x01231683, 0x8240012b, 0x85072016, 0x201c8618, 0x211f8380, 0x1782ebeb, + 0x00002b2c, 0xd501d501, 0x1f001700, 0x0b822700, 0x23022e2d, 0x0e070622, 0x16141502, 0x50333316, 0x26290580, 0x07170707, 0x37273733, 0x20078623, + 0x757f1801, 0x3e5b2813, 0x3e39332b, 0x86b8322b, 0x18012007, 0x2513617f, 0x47391646, 0x05853915, 0x350ae16f, 0x005c001f, 0x06062500, 0x0e27022e, + 0x0e272603, 0x32152302, 0x02851637, 0x22353327, 0x33272626, 0x064b4935, 0x96743720, 0x30072405, 0x8e31021c, 0x2b3f8423, 0x07220606, 0x36343526, + 0x06063736, 0x0136c483, 0x2129188e, 0x04041018, 0x28211811, 0x111a1518, 0x21222507, 0x0282214c, 0x07252234, 0x39061a12, 0x14201339, 0x1b160c0c, + 0x465c3511, 0x1c8c0128, 0x3a851420, 0x01040a3d, 0x28181804, 0x1e02021a, 0x0c128834, 0x030c0c03, 0x030b0d03, 0x0c0f120c, 0x84142b02, 0x022b2400, + 0x822b870c, 0x1d102b48, 0x2504031a, 0x0d335a43, 0x19880d11, 0x33850f20, 0x0304072e, 0x2f1c2620, 0x11080720, 0x1f332007, 0x24088f47, 0x000500eb, + 0xb2591809, 0x07232708, 0x15330321, 0x17541723, 0x01073e05, 0x402b9580, 0xc0aa0155, 0x3c432b2b, 0x1ed33c1e, 0x55011e3c, 0xc001c06a, 0x1e3d0a56, + 0x2f02823d, 0x0001001e, 0x014000b5, 0x00ab004b, 0x25000007, 0x21068b44, 0xcf6b4b01, 0x6b8c2006, 0x022205a4, 0x24825a00, 0x2b01a622, 0x15236882, + 0x6c010000, 0x22280d33, 0x37170706, 0x00012626, 0x230c126c, 0x0e271630, 0x01214583, 0x09f36b2b, 0x0e118022, 0xb2825083, 0x55004027, 0xeb01eb01, + 0x05236200, 0x4f004322, 0x27124e48, 0x15333523, 0x17352315, 0x2a06cd4d, 0x26373435, 0x33372327, 0x82233734, 0x18072071, 0x20087441, 0x21098821, + 0x82480606, 0x8001210b, 0x0cb25e18, 0x0916163a, 0x0d0d1302, 0x19360813, 0x0659167d, 0x04100b66, 0x16080d2c, 0x00010d08, 0x11240684, 0x130ded22, + 0x13222083, 0x388aeb01, 0x55801d28, 0x6a15156b, 0x1c830605, 0x160a0c26, 0x15164034, 0x0de05219, 0x06088e23, 0xfd61182b, 0x02d52a0e, 0x00120000, + 0x0045001e, 0x2ed78269, 0x31030e14, 0x032e3023, 0x33363435, 0x64071632, 0x372d0a6d, 0x1e373636, 0x0e141502, 0x2e222302, 0x241f8202, 0x17163736, + 0x3a8d1806, 0x1726210a, 0x82090871, 0x61312029, 0x362508b5, 0x27263435, 0x323e8230, 0x35011616, 0x07090a06, 0x0a09072a, 0x16161f06, 0x4912351f, + 0x45260534, 0x23010403, 0xc1631d36, 0x361d2c07, 0x25060223, 0x3e2f1b2f, 0x823e2323, 0x48042006, 0x1d2605ec, 0x05070218, 0xe0550d0b, 0x0b0d2e05, + 0x18020705, 0x0acb011d, 0x141f241f, 0x24048214, 0x1f1f160a, 0x074149b6, 0x160c682b, 0x4a39120a, 0x3b4d2c2a, 0x28568321, 0x12394a2a, 0x4e161913, + 0x8350832f, 0x4e2f2258, 0x2855857d, 0x09123620, 0x1f0c0e15, 0x05765611, 0x0c1f1129, 0x1209150e, 0x50020036, 0xab2506f5, 0x25001300, 0x05b76a00, + 0x280c2752, 0x17073517, 0x23152707, 0x051a6435, 0x15333538, 0x80011737, 0x00ff1219, 0x11191911, 0x19120001, 0x1540d555, 0x03822b40, 0x01220685, + 0xce186020, 0x75250c3a, 0x46252525, 0x86048246, 0x04002307, 0x68825a00, 0x0002a626, 0x17000b00, 0x33207482, 0x25076842, 0x34353617, 0x30422626, + 0x4203200b, 0x266f0cd6, 0x0001290d, 0x80243a22, 0x223a2480, 0x08062442, 0x361f0d28, 0x270f1e15, 0x0f271616, 0xc536151e, 0x28461a1e, 0x1e1a4727, + 0x31305620, 0x20400155, 0x6d50283b, 0x3b28506d, 0x1a42a020, 0x0b012f07, 0x0e1e1418, 0x1e0e1111, 0x1e101814, 0x02821e1a, 0x25252026, 0x40000500, + 0xfc2f9182, 0x1e00c001, 0x30002a00, 0x55004700, 0x18250000, 0x2f0d6ffd, 0x37170717, 0x33171716, 0x17373637, 0x34362737, 0x1520b48c, 0x35221282, + 0x7a453417, 0x23352105, 0x0805147f, 0x1e323322, 0x2e071502, 0x1e232702, 0x32303303, 0x18e40131, 0x0d0a1f15, 0x0d062b06, 0x19161f0a, 0x16190303, + 0x15230e88, 0x51500118, 0x3f080665, 0x1e1632bc, 0x45351eab, 0x1a4e2d28, 0x143a802b, 0x361f2640, 0x20ad1729, 0x2b052235, 0x42332104, 0x15780125, + 0x04090a25, 0x09051f20, 0x0d16250b, 0x0b25150e, 0x20200509, 0x250a0805, 0x300b0815, 0x08ef4618, 0x32742b3e, 0x6b621e26, 0x1e354528, 0x80332127, + 0x17231d2a, 0x931f3629, 0x20362305, 0x1a2f3e24, 0x2c066f49, 0x00d501d5, 0x001d0019, 0x002d0029, 0x643e1931, 0x55212014, 0x272305c2, 0x83231533, + 0x6d352001, 0x17240635, 0x07153335, 0x01270382, 0x12196bab, 0x5519122a, 0x562005d6, 0xd124c582, 0x2b2b2a2a, 0x80250384, 0x6b015680, 0x24128240, + 0x12194011, 0x250783eb, 0x401912eb, 0x1e82956b, 0x0a2b2b2b, 0x20402020, 0x00070020, 0x28768240, 0x000002c0, 0x001f001b, 0x9b42182b, 0x01002408, + 0x44232626, 0x25231765, 0x79211733, 0x985c0b7f, 0x0703240b, 0x82173727, 0x82072002, 0x940125a8, 0xea0b1004, 0x260f6644, 0x16dcd2fe, 0x4204f8fe, + 0xc0200715, 0x77240887, 0xcc1e401e, 0x80300382, 0x40012a2a, 0x090c0c09, 0x0d08ab80, 0x1616080d, 0xab230583, 0x7960406b, 0x0e200617, 0x01210786, + 0x202c8218, 0x2103825e, 0x43426b22, 0x20c68b06, 0xb6d6823d, 0x822720c2, 0x173721be, 0x4025bcad, 0x4c1e1e3c, 0x33b7a41e, 0x1f1f3cfb, 0x09001e4c, + 0x2c002c00, 0xd401d401, 0x0f000700, 0x32063f48, 0x0037002f, 0x0050003f, 0x16233700, 0x26371716, 0x4e273726, 0x3721052a, 0x22078235, 0x4e363617, + 0x1f210643, 0x05554e02, 0x64333721, 0x072105fe, 0x820f8215, 0x8227202a, 0x82352035, 0x60272012, 0x35240ecb, 0x19032b57, 0x0f0b1919, 0x2a121e32, + 0x203a18b4, 0x1e122a18, 0x0319131e, 0x1512032b, 0x91232586, 0x89183a20, 0x4602201d, 0xeb200b0b, 0x96211a85, 0x2039841e, 0x20308652, 0x213f8501, + 0x1685f00d, 0x24856c20, 0x1d8ed620, 0x488b8720, 0x0001002b, 0x01950095, 0x006b016b, 0x074c1810, 0x8b952012, 0xc1bd182b, 0x0cf9680d, 0x18001d21, + 0x560de664, 0x37250fff, 0x15333527, 0xe6641817, 0x8aab200a, 0x2e062358, 0x64182716, 0xff210ee0, 0x261f8a00, 0x442e391d, 0x7700273c, 0x0d22091a, + 0xab821b00, 0x36372f08, 0x23171732, 0x15330727, 0x01333523, 0x15233533, 0x23270733, 0x37321617, 0x0c6b5537, 0x3db40c24, 0x80386b95, 0x2a56012a, + 0x956b3880, 0x1282b43d, 0x016b2908, 0x0c0c6b5e, 0x2b6b96b4, 0x80d6fe80, 0xb4966b2b, 0x006b0c0c, 0x00150004, 0x01eb0195, 0x000f006b, 0x002b0013, + 0x01000043, 0x6f07ba59, 0x07200656, 0x05206282, 0x5a186282, 0x33210adc, 0x06b14b32, 0x17962520, 0x40200126, 0x12191912, 0x40240485, 0x2b56f5fe, + 0x55290e83, 0x19112b55, 0x01561119, 0x86088656, 0x6b012416, 0x83801219, 0x25048220, 0x2b8080ab, 0x2e821119, 0x06932b20, 0x2b22af82, 0xb4484000, + 0x001e2406, 0x4134002a, 0x814d11b8, 0x06063606, 0x35211515, 0x23032634, 0x33021e14, 0x022e2235, 0x16142337, 0x2b098216, 0x17802626, 0x27181727, + 0x18271717, 0xde3f0882, 0x2829451b, 0x12101b45, 0x19125501, 0x46341e2a, 0x29361f28, 0x1d2b5618, 0x1d121e30, 0x47400111, 0x0584053e, 0x130e743c, + 0x1f080e13, 0x123b3b12, 0x283f011f, 0x2a1e3446, 0x1f362918, 0x2b1d301e, 0x9bb21d11, 0x16071330, 0x07061416, 0x34363617, 0x36360726, 0x0f822726, + 0x98070621, 0x1e44229d, 0x2d008216, 0x1c1c1d1e, 0x0e0e1559, 0x080d1e15, 0x9f9a0d08, 0x37161e34, 0x1e16373a, 0x474a471c, 0x363715b8, 0x210c1e15, + 0xa5860c21, 0xeb01e825, 0x41000f00, 0x132c2541, 0x14060627, 0x26371716, 0x17363426, 0x0a840b82, 0xa5983620, 0x1c1e3e25, 0x831c1d1d, 0x1e5221aa, + 0x0c22a684, 0xa5990909, 0x9f842120, 0xab822e82, 0x151e2726, 0x1f153736, 0x594ba682, 0x00d52408, 0x821a0013, 0x182d20a7, 0x2c11b651, 0x35262203, + 0x37061433, 0x27333523, 0x0c725a23, 0x49000121, 0x0787071d, 0x40130d2a, 0x80803313, 0x18147e01, 0x20055c43, 0xd1511818, 0x96360812, 0x120e0e12, + 0x0f152035, 0x311d1b2c, 0x1d311c1c, 0x06002c1b, 0x15005500, 0xeb01ab01, 0x12000300, 0x26002200, 0x44003200, 0x33370000, 0x22372315, 0x16141506, + 0x43581517, 0x25372106, 0x11230f82, 0x5e331614, 0x1122088b, 0x61530721, 0x16072805, 0x23071415, 0x18343526, 0x84086a69, 0x2aeb2c39, 0x1912152a, + 0x0a2a0a0c, 0x596e190c, 0x193409e2, 0x0100ff12, 0x0c092a00, 0x0c17090c, 0x150c7e0c, 0x30301521, 0x3708b582, 0x16ab090c, 0x0c111980, 0x11110514, + 0x110c1306, 0x1901d519, 0x1280fe12, 0x01121919, 0xfe181280, 0xd4000196, 0x1112200d, 0x13170e20, 0x12121615, 0x14221416, 0x1b2b2a1a, 0x1222c882, + 0xc9840d20, 0xe0012b23, 0x76e11801, 0x001f230b, 0xc9820100, 0x11332524, 0x07821323, 0x2006b95e, 0x066a7023, 0x1737172d, 0x80012737, 0xd5fe2b2b, + 0x53962b2b, 0xf520051c, 0x0976e618, 0xab012d2a, 0xaafec0c0, 0x2a565601, 0x4d230182, 0x872d2d1e, 0x6000201b, 0x7c6e097e, 0x00232105, 0x6809a96d, + 0x3525105b, 0x05331523, 0x174f6823, 0x5535e028, 0x200a0120, 0x48685535, 0x20352f13, 0x20352b55, 0x15000300, 0xeb012b00, 0x0982c001, 0x0a000622, + 0x373f6c82, 0x37021f21, 0x33172137, 0xfe3ead01, 0x56573e2a, 0xd8fe3e56, 0x5501de25, 0x95956b6b, 0x5a406b95, 0xd52006b0, 0x26293282, 0x00003700, + 0x36362725, 0x05be4935, 0x33070622, 0x36093d64, 0x27262223, 0x33021e23, 0x17373632, 0x37331701, 0x23353317, 0x82072327, 0x31b48202, 0x1164d501, + 0x3e2f1a13, 0x2f492c23, 0x23052c06, 0x784b2036, 0x272d0805, 0x0b2d103e, 0x1d26422f, 0xfe641536, 0x1b231afd, 0x1a162b14, 0x231b1821, 0x498c751a, + 0x1d361564, 0x1b2e3e24, 0x1e2a4328, 0x3a221c30, 0x38338224, 0x3522212a, 0x6411131e, 0x51710601, 0x48402031, 0x00205673, 0x002b0004, 0x28d38215, + 0x002100d5, 0x00350025, 0x26d5823b, 0x35171632, 0x18232634, 0x320af76c, 0x15150622, 0x33331614, 0x34352626, 0x3327023e, 0x56172315, 0x17200e0f, + 0x26057d46, 0x122b1880, 0x82561119, 0x19112f02, 0x19191156, 0x0707a411, 0x8c362917, 0x8d465656, 0x0e152610, 0x19125b0d, 0x2e24832b, 0xea12192b, + 0x200f1912, 0x29361f11, 0x472b9617, 0x9d280c11, 0x273c442e, 0x15000600, 0xea22a682, 0x4248ea01, 0x193c200a, 0x20093721, 0x06344827, 0x44480720, + 0x48052006, 0x4108062d, 0x37171705, 0x07272737, 0x27262217, 0x15233533, 0x16163533, 0x36363233, 0x020e2737, 0x411b9601, 0x15321c25, 0x1b41258d, + 0x6532151e, 0x041c161e, 0x0116032b, 0x1c042b65, 0x16101e16, 0x214ad9fe, 0x03824a21, 0x53322133, 0x2b80341a, 0x343c6420, 0x2a10415a, 0x0148360d, + 0x212b85b4, 0x2b862910, 0x841e4421, 0x854e204b, 0x8431204a, 0x4a4a3036, 0x2b262fe1, 0x372e3a80, 0x092f492a, 0x82213a25, 0x076e74c4, 0x0b000723, + 0x050d4f00, 0x00002a3c, 0x11211125, 0x35211523, 0x2b153327, 0x37333502, 0x23333523, 0x11352315, 0x3d6f3335, 0x23b08205, 0x27263435, 0x24080e82, + 0xaafeab01, 0x80aa012a, 0xab2a2b2b, 0x2b2b55ab, 0x08abab55, 0x10101508, 0x2b080815, 0xfe55016b, 0xd52b2bab, 0x081c822b, 0xfe2a2a2e, 0x052780d6, + 0x160f0a10, 0x100a0f16, 0x00802705, 0x002b0009, 0x01d5011b, 0x000e00c0, 0x00160012, 0x001e001a, 0x00260022, 0x002e002a, 0x33228186, 0x6a831614, + 0x27353322, 0x07208182, 0x2306904f, 0x23153333, 0x3320918b, 0xf0208687, 0x70207783, 0xab208485, 0x8e847583, 0x87862a20, 0x15151025, 0x82aa2b10, + 0x2220828b, 0x832aab2b, 0x20048290, 0x0ac8512a, 0x15000722, 0x252dfa89, 0x33373636, 0x06171616, 0x26230706, 0x2ae68626, 0x2c20dafe, 0x2b040204, + 0x822b2121, 0x862c2006, 0x169526e0, 0x4e31314e, 0x8c058416, 0x890b204e, 0x3303234e, 0x44862311, 0x2a2aea22, 0x01283886, 0x00d6fe2a, 0x00550001, + 0x2a05fe7a, 0x0100001b, 0x16060607, 0x82071717, 0x16312a04, 0x36373732, 0x27272636, 0x31048237, 0x01222631, 0x0106dd39, 0x67ac090b, 0x04050104, + 0x0c8b050e, 0xc6d1012d, 0x010d1106, 0x0c059011, 0x8a040504, 0x0300210b, 0x24084a64, 0x0023001b, 0x074b4627, 0x1526d882, 0x33163533, 0x06823732, + 0x35023e26, 0x13022e34, 0x3e05f34e, 0x35233707, 0x28000133, 0x211e3545, 0x0a2b253a, 0x2b0a0b0b, 0x1e213a25, 0x40084535, 0x821b1b20, 0xaa403c03, + 0x1ed501aa, 0x29284634, 0x360d3549, 0x2c02022c, 0x49350d36, 0x34462829, 0x8600ff1e, 0x2b502323, 0x79820200, 0xc0014028, 0x1500c001, 0x77882900, + 0x17071724, 0x77821637, 0xda823620, 0x0735352a, 0x26270607, 0x22273737, 0x25080482, 0x07161736, 0x16321707, 0x46260001, 0x14161f35, 0x192a1e2a, + 0x4725223d, 0x6e1c1c1c, 0x0606066e, 0x07573405, 0x09820504, 0x3404052e, 0x01040856, 0x46341dc0, 0x193d2229, 0x14212782, 0x24248216, 0xc6c02547, + 0x24268262, 0x0e094706, 0x4a088705, 0x1b200aae, 0x65055842, 0x06210b40, 0x09295415, 0x2634352e, 0x26220326, 0x023e3435, 0x15021e37, 0x26055d47, + 0x2b155501, 0x49152b2a, 0xaa200530, 0x6d300684, 0x0b041f16, 0x17161115, 0xaa3f1f08, 0x2aab01aa, 0x17280082, 0x18d51827, 0x26171726, 0x27340682, + 0x1fd5fe17, 0x0f0e0915, 0x1b191318, 0x1f150c11, 0x0a002aab, 0x43080a41, 0x1b2c0561, 0x23001f00, 0x33002f00, 0x3b003700, 0x470a2046, 0x0734063f, + 0x27071716, 0x07362715, 0x07362317, 0x17260733, 0x37372726, 0x2b0adc5a, 0x06173517, 0x06332737, 0x17163727, 0x2f0c9670, 0x2f151a97, 0x2c152f20, + 0x0404422f, 0x550f2f42, 0x10240e82, 0x090c0c09, 0x07200382, 0x3e231685, 0x70040f2f, 0x57240da2, 0x422f0f04, 0x26262c82, 0x2f3a1a2f, 0x0d823f15, + 0x30841220, 0x54203482, 0x314f1688, 0x00022306, 0x6c18eb01, 0x33270801, 0x34010000, 0x7d353736, 0x112a0603, 0x36323337, 0x26263535, 0x30442307, + 0x82352005, 0x26172107, 0x0e7c6318, 0x01233535, 0x191c242b, 0x1911eb12, 0x1912c055, 0x5556241c, 0x82954055, 0x0b962200, 0x0819600b, 0x01552b2a, + 0x0c342140, 0x1919110a, 0x2505b06d, 0x4a340d33, 0x0182152b, 0x85040421, 0x33058224, 0x04002b80, 0x55002b00, 0xab010002, 0x19001300, 0x39003000, + 0x2c0fd251, 0x36363435, 0x07273333, 0x37173527, 0x23a88317, 0x15150622, 0x14220383, 0xad843316, 0x24055246, 0x16323336, 0x0b807515, 0x1d311d25, + 0x82ab2a15, 0x18402000, 0x22118640, 0x51552b01, 0x6c2b07f1, 0x2a1c311d, 0x6b2b6a6a, 0x8315c06b, 0x0d152413, 0x7a094008, 0x15200559, 0xad7b0783, + 0x01d52606, 0x001700d5, 0x249c8233, 0x36272607, 0x078b7836, 0x16170722, 0x32057947, 0x26170725, 0x14150606, 0x3737021e, 0x06061716, 0x43060607, + 0x173c0521, 0x315d0137, 0x0f030706, 0x090b110b, 0x3932161b, 0x2010e306, 0x2a241515, 0x521ecafe, 0x15200985, 0x533b1f8d, 0x124e011e, 0x170e0205, + 0x22220b07, 0xe31c2917, 0x151b0904, 0x041c3223, 0x83531e6d, 0x3124240a, 0x8b09041c, 0x1e523020, 0x80000100, 0x80011500, 0x2400ec01, 0x57010000, + 0x1722063d, 0xba410717, 0x08dc5405, 0x26344508, 0x36163727, 0x26343535, 0x23585201, 0x37202037, 0x0c0c2923, 0x1d311d0b, 0x09aa090d, 0x1514190d, + 0x011c1b12, 0x260309ea, 0x3b23233a, 0x13040326, 0x1e301d03, 0x0d0d092a, 0x2d1b2a09, 0x19011f0f, 0x1913cb12, 0x250a1544, 0x00430031, 0x5b612500, + 0x35232105, 0x22055146, 0x61222123, 0x15200552, 0x0fa39018, 0x28872120, 0x2205b15d, 0x6e37023e, 0x01210559, 0x09a650ab, 0x89aafe21, 0x05b8500b, + 0x84560121, 0x12953311, 0x0e05111d, 0x19141419, 0x1d11050e, 0x09090ceb, 0x6918800c, 0x8020070e, 0x40300d8d, 0x0a121c11, 0x171d1310, 0x10131d17, + 0x111c120a, 0x2408e967, 0x002100c0, 0x0f255225, 0x1621ad83, 0x0cf16833, 0x3327262d, 0x6b012315, 0x56111916, 0x49161911, 0x2b220517, 0x08842b80, + 0x5656b924, 0x2b428001, 0x210f8405, 0x00824023, 0x15210985, 0x0aab4415, 0x1d000b27, 0x00002800, 0x089e4437, 0x34033d24, 0x6a432726, 0x06152507, + 0x37151506, 0x343a6582, 0x06222326, 0x17552315, 0x18aa1827, 0x1b251727, 0x12801219, 0x6b251b19, 0xd5832b80, 0x4dc02b21, 0x402a06c1, 0x2e1d402b, + 0x19112e07, 0x06821119, 0xc0401d27, 0x0c0c092b, 0x0caa4609, 0xaa461920, 0x47212009, 0xe4470ce5, 0xabfe2a0a, 0x160a076b, 0x11161010, 0x06c0466b, + 0x0527802c, 0x16100a0f, 0x0a141016, 0xbf828027, 0x470dd047, 0x58830fc4, 0x2508ac47, 0x101015b0, 0x5282b015, 0x4c862a20, 0x15151025, 0x822a2b10, + 0x06003900, 0x14001400, 0xec01ec01, 0x1e000f00, 0x2e002600, 0x3e003600, 0x32010000, 0x0df85618, 0x06221723, 0x07ea4e07, 0x26262724, 0x8e513737, + 0x27252105, 0x2105ad51, 0xc5510703, 0x17052105, 0x21059e51, 0x3c670001, 0x1d123d0a, 0x0b0a1737, 0x0a0b0001, 0x27a83717, 0x112e4813, 0xf9fe3c27, + 0x13482e11, 0x4c3c1027, 0x01211086, 0x21108607, 0x48671501, 0x0f152d0b, 0x0b14060e, 0x140b2929, 0x520f0e06, 0x4490338e, 0x000a0028, 0x012b002b, + 0x967501d5, 0x05797409, 0x23001f25, 0x75002c00, 0x2727064d, 0x15231723, 0x5c332133, 0x3724057c, 0x25071737, 0x27240382, 0x25231533, 0x31080382, + 0x36363207, 0x16142335, 0x96a44716, 0x960ea4c0, 0xfec0adad, 0xadadc056, 0x1e652a2a, 0xe6fe1e2e, 0x432d1e2e, 0x40014040, 0x1d804040, 0x1dd61d31, + 0x0a82ab31, 0x55556b28, 0x1e5140d5, 0x02821e2d, 0x2a9c2d2b, 0x1c402a2a, 0x311d1d31, 0x0cf6411c, 0x230aa148, 0x11331121, 0x2206a148, 0x485600ff, + 0x05200ba1, 0x4020c182, 0xc021c182, 0x09244a00, 0x2908224a, 0x2b113303, 0x23331102, 0x02821133, 0xc02a4188, 0x202a2020, 0x20206b20, 0x498a20e0, + 0xfe2a0123, 0x820383d6, 0x00152747, 0x01e20115, 0x6b7600e1, 0x001c2905, 0x0048002c, 0x13000054, 0x0382ed83, 0x03821720, 0x16163733, 0x26363717, + 0x07062627, 0x15150607, 0x36073636, 0x05164437, 0x17172508, 0x26373716, 0x26271726, 0x07162727, 0x22230606, 0x22153126, 0x34331506, 0x17352326, + 0x36373216, 0x36162736, 0x75083b86, 0x80551606, 0x6b6b4080, 0xe56b6b2b, 0x5b04110c, 0x0e110a0b, 0x0d4a0b21, 0x05371306, 0x1d14af0e, 0x12601014, + 0x0b0c3a0f, 0x120931fd, 0x05030144, 0x0c09121c, 0x19801912, 0x280e6211, 0xd6050b0f, 0x0404170d, 0x180d0c0d, 0x010c0403, 0x2b2a2bc0, 0x04de2bd5, + 0x11970a11, 0x03080a28, 0x130c450b, 0x27030253, 0x141c0a11, 0x1c041a11, 0x0a220a05, 0x1057771f, 0x65821105, 0x7a05152d, 0x19121219, 0x0e0e625b, + 0x8767210b, 0x0d0d2343, 0x6d180017, 0xfe830964, 0x1d001727, 0x00002d00, 0x20f28225, 0x20038235, 0x6c6d1837, 0x2303210e, 0x21145469, 0x00822015, + 0xd6fe8024, 0xc66a1912, 0xd2192505, 0x80402020, 0x26094169, 0x205620f5, 0x891219b5, 0x00ff2320, 0x44182060, 0x002d0937, 0x002b0006, 0x01f5012b, + 0x000900ab, 0x31818219, 0x0044002a, 0x01000064, 0x21232634, 0x16152115, 0x0c532517, 0x36172112, 0x25064547, 0x33151714, 0x0e7b3227, 0x46138305, + 0x142c052c, 0x26371716, 0x37363435, 0x15020e22, 0xf94f0c84, 0x06396705, 0x82361721, 0x022e212a, 0x25056947, 0x14165601, 0x9084d6fe, 0x43080483, + 0xe640401e, 0x0b0b0f0a, 0x10200b10, 0x17101f16, 0x27170d0c, 0x17271817, 0x10170b0e, 0x321d1620, 0x13161626, 0x1d110e16, 0x311d1e30, 0x170f101c, + 0x26151513, 0x12800133, 0x09372b19, 0x080d1010, 0x0e0e08c0, 0x0d350482, 0x087f95c0, 0x0f0f0b0d, 0x6b080d0b, 0x16161fb5, 0x1f0b1610, 0x824a8212, + 0x1f122802, 0x170f170c, 0x82551f16, 0x1d1c2739, 0x0f161233, 0xed501627, 0x27163a05, 0x3213170e, 0x26331c1d, 0x00040015, 0x012b0055, 0x00c001f5, + 0x001b000e, 0x270d8235, 0x16320100, 0x11072717, 0x23066a4e, 0x15062217, 0x3520fe83, 0x2621cc82, 0x05734e27, 0x3320f685, 0x200b1041, 0x1d034127, + 0x160b6b2c, 0x91ab960a, 0x2e1b1412, 0xf583243e, 0xee88fc82, 0x97080041, 0x03552ef7, 0xff807002, 0x1f361600, 0x1a2f3e23, 0x20ed8490, 0x20f7836b, + 0x8ae78a3b, 0x9c3520fd, 0x6d0320f2, 0x024e0894, 0x13002405, 0x46353311, 0x112506d4, 0x35231507, 0x290d8215, 0x2ad62a2b, 0x562a2a56, 0x78820156, + 0x2bd5d53b, 0x2b00012b, 0x2b802a2a, 0x0005002b, 0x01150055, 0x00eb01eb, 0x002c0021, 0x05c8433c, 0x4f320121, 0x1b4208b0, 0x42152005, 0xb14f084e, + 0x08ed7106, 0x1810b84f, 0x350b439f, 0x27262217, 0x32333636, 0x06061716, 0x15168001, 0x1d151219, 0x02821d31, 0x1912152e, 0x0d861219, 0x3629170e, + 0x121e12a3, 0x84210282, 0x851985c2, 0x07275b05, 0x091c1031, 0x0f0f1a0c, 0x1c090c1a, 0x1c061501, 0x852b1911, 0x192b2d1f, 0x1911d611, 0x1f182b12, + 0x6b172936, 0x2b214185, 0x20418b6a, 0x071b592b, 0x0d0f8028, 0x07080807, 0x82180f0d, 0x2f240c0f, 0x47003b00, 0x22058766, 0x1815020e, 0x240b9e50, + 0x17373634, 0x20b58433, 0x2318821e, 0x23270706, 0x2327bc82, 0x17022e22, 0x83233727, 0x3307240d, 0x87271737, 0x27332308, 0x2f831737, 0xc1531a86, + 0x13d72c10, 0x473c2911, 0x231e3516, 0x831b2f3e, 0x1546210b, 0xdb250b85, 0x10202020, 0x82048210, 0x87652005, 0x200e8208, 0x530b8a8a, 0xd52b11eb, + 0x2916351e, 0x1b131147, 0x89233e2f, 0x2b08240a, 0x8316162b, 0x85562003, 0x2b2b2106, 0x00220888, 0x2b6e0003, 0x00ab2c05, 0x001e0013, 0x0100002e, + 0x4d062221, 0x212b063a, 0x35363632, 0x26263435, 0x83270607, 0x322124f1, 0x82251716, 0x15152404, 0x82232626, 0x35072626, 0x80013634, 0x065567ff, + 0x07850120, 0x0a08403c, 0x0d1604ed, 0x120b0001, 0x01ddfe06, 0x0a191200, 0x00ff0c15, 0x190a150c, 0xcb48ab01, 0x32068606, 0x3a0307d1, 0x080a0f0c, + 0x0b121967, 0x05060605, 0x8a19120b, 0x054d4d8f, 0x100a4118, 0x11330527, 0x11232123, 0xd9411833, 0x99fe240c, 0x82011616, 0x844a18d4, 0x12192107, + 0x2b247883, 0x000100ff, 0x562351b8, 0x82560156, 0x8f4e1803, 0x2351bd0c, 0x56012b2b, 0x51940382, 0x2c056543, 0x000e00c0, 0x002a001e, 0x17320100, + 0x0c954435, 0x20058b4a, 0x05244932, 0x6e181720, 0x33260979, 0x15168001, 0xf652abab, 0x421f2005, 0x23230ae1, 0x82351635, 0x15012702, 0x80803106, + 0xec5200ff, 0x8a2a2006, 0x761d2121, 0x35292083, 0x15000500, 0xeb011500, 0x267c8301, 0x001c0018, 0x8238002c, 0x4a7e8280, 0x263305f9, 0x36343526, + 0x15213517, 0x33361517, 0x33271632, 0x18172315, 0x210da987, 0x3b5d0736, 0x23153707, 0x95400115, 0x24556b96, 0xd12f0707, 0x0b96eafe, 0x6b371f0a, + 0x2d612a2a, 0x2776860b, 0x6b0e0701, 0x8080d56b, 0x2d2b9882, 0x2ad80d48, 0x1801176b, 0x91c02b6e, 0x0a5047c1, 0x4209604f, 0x03231016, 0x83333523, + 0x86172085, 0x0c3a4f07, 0x8256bc21, 0x82802000, 0x4f562003, 0xfe250d1e, 0x562a56d5, 0x290382d6, 0x40000600, 0x00022b00, 0xff82c001, 0x2400202b, + 0x4c003800, 0x00005000, 0x224d8237, 0x82333636, 0x721720f6, 0x33290b76, 0x34352626, 0x15333736, 0x050d4123, 0x35202182, 0x82080b4f, 0x26222386, + 0x94182337, 0x08820899, 0x2005b541, 0x292f8207, 0x0f4f18ad, 0x05801424, 0xbd47050b, 0x08512607, 0x56690109, 0x309d8256, 0x2a12196b, 0x1727182a, + 0x2a182717, 0xab19122a, 0x05ab542b, 0x83172b21, 0x80972912, 0x0a569580, 0x9701010b, 0x2507376f, 0x0511210e, 0xd482db0b, 0x1912952f, 0x1826172a, + 0x2a172618, 0x192a6719, 0x210e8812, 0x21522a40, 0x0028270a, 0x00440038, 0xd1820100, 0x2e233523, 0x20ae8302, 0x45a48207, 0x152409b9, 0x35211523, + 0x8205ab4d, 0x0f3b6beb, 0x0bd05b18, 0x1595012d, 0x2409322b, 0x301c1c30, 0x76320924, 0x1523057b, 0x8456012b, 0x15a72109, 0x09856218, 0x9f603520, + 0x40153508, 0x1626192b, 0x2b192616, 0x2b111940, 0x2a401912, 0x1219402a, 0x8a29e082, 0x15142214, 0x22141422, 0x29088215, 0x12120e4a, 0x13130d0e, + 0x80750700, 0x00c02e06, 0x0039002d, 0x00490045, 0x00590055, 0x21be825d, 0x28562627, 0x15232510, 0x33331614, 0x07436f18, 0x35220889, 0x57510534, + 0x8a33200a, 0x3527240b, 0x82271733, 0x233521ea, 0x83051a58, 0x8217200b, 0xe901310f, 0x0e16051f, 0x15090c0c, 0x122a0d09, 0x1219eb19, 0x20061b4c, + 0x05747056, 0x844e4020, 0x0d092305, 0x0382cd0d, 0x0d08092a, 0x1d76480d, 0xd61616d3, 0x7b2b0282, 0x25452525, 0x5c1c0125, 0x8216100d, 0x16082718, + 0x6a561119, 0x964c1912, 0x078f220b, 0x077d51ab, 0xaa260787, 0x2a365656, 0x02832020, 0x002a2a31, 0x00520003, 0x01ae0140, 0x001800c0, 0x66420024, + 0x062307f4, 0x82060707, 0x24e684e1, 0x3e353315, 0x0ba36102, 0x0e230c19, 0x23263422, 0x087e5118, 0x16161731, 0x2a04a901, 0x40252640, 0x07290529, + 0x82150d0c, 0x953b08d0, 0xa314291c, 0x07090907, 0x1f090906, 0x01040c07, 0x05031602, 0x0a03050f, 0x020b0a0a, 0x11160414, 0x0405130d, 0x233f0103, + 0x3a22233b, 0x160b4a24, 0x4019122a, 0x3d2f0d64, 0x84060a48, 0x5c0a3a36, 0x02070a0a, 0x0d050906, 0x080b0807, 0x0d0b0d05, 0x130c0906, 0x1607080b, + 0x054b4c00, 0x0d4dc020, 0x0028360a, 0x35213700, 0x33351721, 0x35233315, 0x15332133, 0x27373723, 0x05447333, 0x21152122, 0x3d06d044, 0x27372323, + 0x80014007, 0x479c80fe, 0xfe474772, 0x154747d6, 0x11ef221e, 0xfe111919, 0x014301d5, 0xef172805, 0x40551e22, 0x822a5580, 0x1ec02200, 0x0ae74222, + 0x00271782, 0x00150004, 0x82e90140, 0x000a367a, 0x00230013, 0x25000032, 0x36262637, 0x06062737, 0x26371614, 0x22088334, 0x4e051716, 0x26220f66, + 0x694e2326, 0x7f01340a, 0x14141d22, 0x1f20221d, 0x0d0d8a1f, 0x0f0f1524, 0x53fbfe15, 0x058405fc, 0x181ba021, 0x3409b370, 0x512122ab, 0x1f222252, + 0x4b4e514c, 0x24122e13, 0x18373715, 0x05874307, 0x37200585, 0x5b0a555d, 0x08260af8, 0x20001800, 0x56782400, 0x0f144c0b, 0x07232736, 0x17333723, + 0x27330727, 0x11192a55, 0xd5fe2b01, 0x00ff5601, 0x08e40d19, 0x4e11592b, 0x23482211, 0x391c5a48, 0xcd0d191b, 0x31f63315, 0x9cc0c031, 0x01004f4f, + 0x6b006b00, 0x80018001, 0x71820800, 0x07331530, 0x33153717, 0xccb78011, 0x012bcc1e, 0x06822b80, 0x0001b732, 0x2e000300, 0xb5014b00, 0x0b00cb01, + 0x3d003900, 0x270de974, 0x26262713, 0x27222323, 0x22260683, 0x06060707, 0x45821717, 0x1517272b, 0x37273533, 0x07171616, 0x18ab8233, 0x20084d5a, + 0x200c8227, 0x07ab63e0, 0x0ec62d08, 0x230d1201, 0x022b1e32, 0x0d110d0f, 0x05010847, 0x4f21431e, 0x2d2a1104, 0x1e200f32, 0x44092012, 0x0d131003, + 0x0973120e, 0xa001092a, 0x0382df83, 0x88f8fe24, 0x3282110c, 0x460d0a2d, 0x3c091a0b, 0x1d641a56, 0x8283700f, 0x081a2831, 0x091a4bb1, 0x82120e12, + 0x4b432e02, 0x0002004b, 0x01150055, 0x00e001cb, 0x06305f0c, 0x2a065842, 0x17352622, 0x22262726, 0x82073107, 0x063724a4, 0x82151506, 0x843720b1, + 0x343430b1, 0x17171637, 0x35332737, 0x27022e22, 0x821119cb, 0x12220871, 0x06381911, 0x09160a0b, 0x05202b74, 0x40223706, 0x2a2a2605, 0x7f2c180a, + 0x04157513, 0x091b1a15, 0x2585b501, 0x11192508, 0x06060c4d, 0x4c654105, 0x12241212, 0x561a4a72, 0x8b6b364b, 0x1a26083c, 0x0bdc0e25, 0x08012acb, + 0x04001313, 0x26085d7c, 0x001f000f, 0x56380026, 0x05201104, 0x09634818, 0x34352625, 0x4b073636, 0x37200505, 0x240f9e66, 0xfed50107, 0x217a8356, + 0x0582aa01, 0x44d9fe21, 0x822d0a4d, 0x2f2f4f16, 0x106b164f, 0x101f201f, 0x8302821f, 0x0dde4606, 0x2a756b20, 0x26ea2c0b, 0xc3262f2f, 0x2424121c, + 0x82121c12, 0x21078402, 0xab860700, 0x0b00d52e, 0x25001900, 0x42003300, 0x7e005200, 0x300d6077, 0x15060607, 0x34353315, 0x23262637, 0x34250622, + 0x08664136, 0x20069360, 0x211e8416, 0x4c432726, 0x1827200d, 0x820a69bc, 0x27062137, 0x20082f4e, 0x07895c17, 0x17160722, 0x2008f651, 0x223d8407, + 0x82141506, 0x412b2013, 0x112b0796, 0x0d600e0c, 0x10070c05, 0x4258011d, 0x66360754, 0x07101d0e, 0x600d050c, 0x2e12980e, 0x122e1a1a, 0x00011412, + 0x3c56ac14, 0x12270808, 0x0a8b111d, 0x1c1c2c1a, 0x11111f27, 0x1c1d261f, 0x150a1a2c, 0x260b090c, 0x3d21283f, 0x213d1515, 0x0b263f28, 0x41d50c09, + 0x3b2b06d2, 0x210d1605, 0x01171a22, 0x87460601, 0x06063612, 0x1a170101, 0x160d2122, 0x0b0b0819, 0x13200808, 0x20132222, 0x0a7e416b, 0x1819063e, + 0x161a2d1b, 0x23141423, 0x1b2d1a16, 0x140a1918, 0x27152713, 0x181d2540, 0x40251d18, 0x133f0a82, 0x00030014, 0x02150000, 0x00eb0101, 0x006f0036, + 0x370000a9, 0x35262637, 0x32333634, 0x5d171616, 0x1720058e, 0x17250c82, 0x2223022e, 0x05545f22, 0x21086b4f, 0x51482226, 0x26053f07, 0x37363627, + 0x27262636, 0x07062226, 0x17363617, 0x0e071616, 0x16070702, 0x06071416, 0x18822706, 0x32070626, 0x32161716, 0x36212582, 0x83088637, 0x07062215, + 0x27348206, 0x27373634, 0x2627022e, 0x16851d84, 0x82020e21, 0x82172043, 0x1406211e, 0x32210882, 0x20358237, 0x2d088416, 0xd737023e, 0x17352c1f, + 0x11100c11, 0x0483140c, 0x04140e2f, 0x0b0b0a0b, 0x15231603, 0x02020302, 0x05664102, 0x2c080882, 0x25170203, 0x01311b16, 0x010b0a29, 0x010c0102, + 0x36161415, 0x370b2943, 0x080f164b, 0x18100609, 0x08060a13, 0x0f1f0806, 0x0a010101, 0x2321820c, 0x0b262b14, 0x082e0b82, 0x1e220f09, 0x11010909, + 0x16160ce8, 0x22821f0f, 0x120a0628, 0x09061118, 0x5f820e09, 0x03090627, 0x14020602, 0x2c4f8215, 0x0a0b0102, 0x0809110f, 0x090f221e, 0x35388208, + 0x142b250c, 0x09121a17, 0x38271ead, 0x0a171119, 0x130e0e13, 0x5982100a, 0x12211426, 0x060b0601, 0x08829885, 0x25160128, 0x312e1a17, 0xa4820524, + 0x75830220, 0x0e120d26, 0x0d121229, 0x0a2a8b82, 0x1103050a, 0x0a141712, 0x5283080f, 0x82101521, 0x14152164, 0x09247782, 0x0f110806, 0x382f9882, + 0x090c4a39, 0x130a0f08, 0x03111218, 0x820a0a05, 0x297a82a0, 0x010b1309, 0x260b0202, 0x5283142b, 0x82090521, 0x08998292, 0x01090524, 0x16140104, + 0x432f0d0b, 0x0005002b, 0x01550015, 0x00ab01eb, 0x00220011, 0x00430033, 0x37000065, 0xec571732, 0x37362105, 0x20067149, 0x0e7f4631, 0x108f2120, + 0x208e2720, 0x2223172d, 0x0e140706, 0x26222302, 0x7e262627, 0x332005f1, 0x3305555e, 0x35331537, 0x20872634, 0x15240c14, 0x140c2415, 0x33280820, + 0x28216e82, 0x05a6423a, 0x121d1126, 0x67011d12, 0x11200684, 0x99201284, 0x080abf42, 0x0c46d228, 0x150b0612, 0x2f171620, 0x0b120710, 0x96191246, + 0x17172c12, 0x1996122c, 0x12111cea, 0x011c1112, 0x0a0a130d, 0x43440d13, 0x200b8b0b, 0x390c8b40, 0x01070c56, 0x160d120d, 0x190a0917, 0x0d315611, + 0x310d0e0e, 0x00191156, 0x00820004, 0x02000231, 0x00350000, 0x005c004f, 0x25000069, 0x43313030, 0xf24307f3, 0x42072005, 0x1a8208f3, 0x2308846c, + 0x32331637, 0x20054c5c, 0x21e58236, 0xc26c2207, 0x30142306, 0xe4821431, 0x15231a83, 0x4a020e14, 0x35210b96, 0x0a994433, 0xd5013531, 0x3a231714, + 0x10090823, 0x3b24243b, 0x82080910, 0x1417210c, 0x16291384, 0x19181128, 0x28111819, 0x36138316, 0x2f3e23e9, 0x243a221b, 0x28243b23, 0x1b060521, + 0x107e3e2f, 0x83100b0b, 0x87802003, 0x12e02308, 0x2b821c32, 0x241d0125, 0x82011d24, 0x321c2208, 0x25118512, 0x06060c0f, 0x11840f0c, 0x2f1b8e35, + 0x4427243d, 0x24010a30, 0x0e18233b, 0x3d240f1d, 0x84951b2f, 0x0f0f2148, 0x07825085, 0x00040031, 0x01000002, 0x00d501fd, 0x0018000c, 0x4547002b, + 0xc48c0d6b, 0x032e3730, 0x020e2223, 0x16060707, 0x36322133, 0x4d420127, 0x20058705, 0x09db6d15, 0xb290a520, 0x04c42208, 0x2d513f28, 0x283f512d, + 0x1a021304, 0x13a20113, 0x65fe0119, 0x1e11200e, 0x32101032, 0x0e20111e, 0x20eb8306, 0x22fd8323, 0x8a0beb06, 0x3ab282a2, 0x3a4d2d21, 0x4d3a2020, + 0x1c13d22d, 0x0e01131c, 0x171b0909, 0x09091b17, 0x6d101f0e, 0x1021078f, 0x24ca821f, 0x012b0000, 0x26cf82d5, 0x0037001e, 0x82500044, 0x182220d8, + 0x6e0a66b5, 0x2e220c6d, 0xc3410302, 0x36352205, 0x05d74136, 0xc2410582, 0x00012e1c, 0x0e0e1e0f, 0x301e1c30, 0x04171c1d, 0x076c6e04, 0x84830783, + 0x4029012b, 0x32561d11, 0x030c170c, 0x14b44104, 0x04d5012e, 0x1d1c1704, 0x301c1e30, 0x0f1e0e0e, 0x210b3b65, 0x318280fe, 0x0101232d, 0x293e1001, + 0x03022a25, 0x830c180c, 0x41962052, 0x00230e06, 0x832b0018, 0x013108e1, 0x001300d5, 0x00a20095, 0x00ba00ae, 0x00d200c6, 0x00ea00de, 0x010201f6, + 0x011a010e, 0x01320126, 0x014a013e, 0x01620156, 0x017a016e, 0x01920186, 0x13d6659e, 0x35022e2b, 0x33163734, 0x34353632, 0x07047227, 0x26270d84, + 0x36072223, 0x61151437, 0x1c82050f, 0x37202588, 0x23095649, 0x17323336, 0x16200d89, 0x37200b86, 0x54830887, 0x82171621, 0x41239349, 0x37201066, + 0x8b0a2943, 0x0b4e430b, 0x238a1720, 0x0b8b178b, 0x178b4797, 0x0b666618, 0x5f972f97, 0x47978397, 0x838b1797, 0x33108353, 0x2f3e232c, 0x05030e1b, + 0x03090604, 0x01010305, 0x07040407, 0x03230382, 0x82061611, 0x04082a13, 0x04060306, 0x0d0d0107, 0x2c0e8304, 0x0a0a0706, 0x04060607, 0x0e040605, + 0x832a820c, 0x8308201c, 0x1701230e, 0x38850311, 0x05020724, 0x12820906, 0x420e0321, 0x50200b96, 0x07215686, 0x8246842b, 0x18552040, 0x20071667, + 0x20118795, 0x202387ab, 0x201a872a, 0x201a8755, 0x1a9e192b, 0x08a07d10, 0x23885088, 0x2c878020, 0x15201a88, 0x358859ab, 0x55443b20, 0x11695407, + 0x2e054143, 0x06032023, 0x04010905, 0x03010408, 0x83070401, 0x16033264, 0x0501010f, 0x08050606, 0x05030202, 0x01010407, 0x83078204, 0x0307251b, + 0x07030101, 0x05220983, 0x17830203, 0x07820720, 0x83080221, 0x0101232b, 0x1a82160f, 0x022a1b83, 0x01090703, 0x03060509, 0x92432320, 0x04a0220c, + 0x8cd58706, 0x18112007, 0x8c0d6268, 0x7a68181b, 0x2017880a, 0x41a68511, 0x0798070f, 0x6f961120, 0x04205393, 0x5b208382, 0x4d063b44, 0x13240ae9, + 0x3c002f00, 0x086d8318, 0x350a4456, 0x022e2203, 0x35303035, 0x36373636, 0x17323333, 0x3017021e, 0xce463114, 0x15b4421b, 0x0f29252b, 0x0d760d06, + 0x23170a06, 0x16024519, 0x230b3545, 0x213b4d2c, 0x2a05b741, 0x1d280301, 0x1f140b0c, 0x41010214, 0xc3870c64, 0x0000063a, 0x00028000, 0x0e008001, + 0x4c003d00, 0x68005a00, 0x00007900, 0x36323313, 0x2d05064e, 0x06070706, 0x17062716, 0x30371616, 0x16823232, 0x27343525, 0x82363534, 0x35262605, + 0x23262736, 0x2a038230, 0x23060722, 0x06222326, 0x82073007, 0x16172228, 0x0d1e4c05, 0x554c0520, 0x4c1c860c, 0x35200749, 0x20057862, 0x06e64417, + 0xdb363608, 0x03130f4a, 0x17230406, 0x06042317, 0x04a91303, 0x0c120302, 0x0d051411, 0x07030213, 0x06020301, 0x0c060110, 0x0101060a, 0x0f0a0604, + 0x020a0101, 0x01010401, 0x0a1e4c36, 0x4caefe21, 0xbe200949, 0x0808404c, 0x11191d3b, 0x0405072b, 0x1219070f, 0x00011911, 0x16270e17, 0x26171e1e, + 0x0913170e, 0x010b0b0a, 0x05040b10, 0x06050101, 0x0201070a, 0x01100706, 0x02010507, 0x09010a0e, 0x0106070d, 0x0a184c37, 0x424c0c20, 0x4c062009, + 0x512c093a, 0x0c19120b, 0x0c0b0d06, 0x00191911, 0x2b0b5141, 0x002a001c, 0x003e003a, 0x25000041, 0x4a2a1341, 0x27280e19, 0x25071737, 0x5a013307, + 0xf220e5a0, 0x280af749, 0x363635ce, 0x6b365601, 0x20bea0dd, 0x0b504d3c, 0x3636152f, 0x00556035, 0x001e0004, 0x01c4011e, 0x27cf82eb, 0x00370010, + 0x25000051, 0x22321982, 0x14250706, 0x3433021e, 0x3237022e, 0x06141516, 0x13421707, 0x27262105, 0x34251d82, 0x07222326, 0x22058335, 0x83151506, + 0x3617240b, 0x41072736, 0x373d06d9, 0x16141531, 0x17333233, 0x32150606, 0x37173736, 0x0b0baa01, 0xfe142d18, 0x45351ed9, 0x08038228, 0x1f169820, + 0x03350d11, 0x11201604, 0x20110e0e, 0x1f0e1016, 0x0d1f1616, 0x430e1211, 0x1eb41907, 0x12850a63, 0x23020139, 0x3b201412, 0x921e3318, 0x0c182d14, + 0x4628160a, 0x46271e34, 0x82a01e35, 0x07192d1f, 0x10161f35, 0x1907061a, 0x091f1610, 0x202b4a82, 0x0b0a0416, 0x39110e44, 0x850e631e, 0x231f2812, + 0x14203a18, 0x181e3312, 0x262e5c8f, 0x19354035, 0x50121967, 0x012005ba, 0x135c8f18, 0x2b00ab2a, 0xdb015501, 0x11000d00, 0x10aa8f18, 0x2707172f, + 0x11562b01, 0x2a562a19, 0x30303c19, 0x20408930, 0x820d8270, 0x82ae208a, 0x0152263c, 0x000900d5, 0x253c8515, 0x13331317, 0x2f472636, 0x25012b0b, + 0x0219144a, 0x02255625, 0x88896419, 0xfe131e2c, 0x130f01f1, 0x1911401e, 0x9d821119, 0x0a3fd918, 0x1f000e22, 0x25107842, 0x36323327, 0xa44c2727, + 0x06072406, 0x52880116, 0xc7210ae9, 0x0860825e, 0x17040724, 0x24141424, 0x02070417, 0x140ec919, 0x1e080e14, 0x123c3c12, 0x131d3f1e, 0x131f1534, + 0x34151f13, 0x65881d13, 0x0e00d524, 0x65913200, 0x82043a21, 0x35362467, 0x84272634, 0x08fc4204, 0x4b171421, 0x768c05f7, 0x1201c33b, 0x01121818, + 0x08121d11, 0x12160407, 0x11111d0a, 0x16120a1d, 0x12080704, 0x82818c1d, 0x150c3621, 0x140c0b08, 0x0e0c0720, 0x20070c0e, 0x080b0c14, 0x1d120c15, + 0x208f8811, 0x208f82c0, 0x2b8f912c, 0x35363632, 0x3431023c, 0x07222326, 0x06270386, 0x14143015, 0x41161415, 0x98310d02, 0x12172618, 0x0a09110e, + 0x090a1111, 0x17120e11, 0x28818c26, 0x0f172717, 0x130d1923, 0x2400820e, 0x23190d13, 0x2110820f, 0x57590300, 0x00eb2906, 0x001f000f, 0x13000041, + 0x200ec143, 0x08355d05, 0x35363227, 0x27263435, 0x061d4116, 0x2006104d, 0x08194d17, 0x27201886, 0x2d0b4759, 0x116b5d01, 0x6b111919, 0x58191912, + 0xf34d0e0d, 0xd6072108, 0x01200c8b, 0x5906505d, 0x40200556, 0x12202e85, 0x87213882, 0x08f56207, 0xd60d0e22, 0x00310c8b, 0x009e0004, 0x02620100, + 0x00050000, 0x0011000b, 0x200d8217, 0x35931827, 0x17072509, 0x27371737, 0x01260585, 0x44431f62, 0x0591621e, 0x1ee20123, 0x26188244, 0x43431e09, + 0x848c621e, 0x84cd2005, 0x885d9411, 0x1707224f, 0x21598313, 0x5e82022f, 0x00012722, 0x62204182, 0x058d3584, 0x84590121, 0x84af2018, 0xbcfe2105, + 0x27200684, 0x44180584, 0x0c220a93, 0xb7821800, 0x21056142, 0x90183307, 0x4b231872, 0x43964b40, 0x4f290835, 0x0c10100c, 0x018080a4, 0x07354300, + 0x4a000726, 0xb5012b00, 0x2510df63, 0x15211300, 0x0d7d1321, 0x215e8206, 0xc3823723, 0x49192520, 0x0a753b3e, 0x5421200b, 0x37290731, 0x35363221, + 0x07263411, 0x37681827, 0x3715210f, 0x2205005d, 0x822b0155, 0x2b512eab, 0x0980080d, 0x80090d0d, 0x012b0d08, 0x065969d5, 0xea22c683, 0x17862a2a, + 0x2b080d23, 0x0600612b, 0xcf82eb20, 0x00043308, 0x00140011, 0x2500001e, 0x27373315, 0x22232737, 0x14031506, 0x35333316, 0x17352737, 0x22262717, + 0x37170707, 0x2b013436, 0x122d6e2d, 0x1812ab80, 0x06821901, 0x5976962b, 0x0612060f, 0x070f2d0f, 0x21188258, 0x6b82808f, 0x1911aa2b, 0x752caa3f, + 0x070f6b75, 0x2b188207, 0x03001206, 0x40004000, 0xf501f501, 0x16286482, 0x00002000, 0x31373537, 0x48726183, 0x07352207, 0x21758227, 0x66882507, + 0xbe949524, 0xec621912, 0x6c943305, 0x9a5a9a5a, 0x0d1e2901, 0x5a160d23, 0x97950c17, 0xea621994, 0x94be2206, 0x241a822b, 0x0c0c1eb1, 0x22188217, + 0x46020023, 0x3008068f, 0x000d00c4, 0x25000012, 0x07170701, 0x33151733, 0x21152317, 0x27330317, 0xc4011707, 0x641e78fe, 0x59272e17, 0x0301d92b, + 0x95556638, 0x013c8242, 0x82128288, 0x372b2311, 0x0f820d01, 0x00050033, 0x012b0055, 0x00d501c0, 0x00290017, 0x00490039, 0x224c8259, 0x43263435, + 0x5e180588, 0x34220b54, 0xc0532726, 0x15152405, 0x85331523, 0x34372204, 0xbd9d182e, 0x32332307, 0x0d8c0736, 0x0d8c1720, 0x47000121, 0x13200554, + 0x2507ae73, 0x09090c68, 0x0082150c, 0x0c0aeb23, 0x2702820a, 0x130d0d13, 0x090d0a55, 0x12210282, 0x880a830e, 0xaaeb2115, 0x2205e243, 0x192d0faa, + 0x2c14460f, 0x11120760, 0x12110c0c, 0x13130d07, 0x230b9633, 0x3e000400, 0x08085172, 0x0b000723, 0x00003100, 0x33352301, 0x17072727, 0x37170715, + 0x15163207, 0x23061415, 0x06060723, 0x2e272223, 0x06af5402, 0x33333626, 0x07161632, 0x24081583, 0xeb010723, 0x0e085656, 0x4d0d0d4d, 0x0d08f80e, + 0x101d080d, 0x09152306, 0x09171108, 0x17122704, 0xab172717, 0x082a8210, 0x15062a2c, 0x01062b0c, 0x1d3e2045, 0x1e551d23, 0x0d1d1d22, 0x0d092a09, + 0x021a153b, 0x11201904, 0x17260c91, 0x13172718, 0x0b550e1d, 0xa970150d, 0x0011230a, 0x3b6d001f, 0x21252108, 0x22058163, 0x45213316, 0x0726063a, + 0x35262221, 0x0f823634, 0xa8821620, 0xc06a0320, 0x2323240a, 0x82170622, 0x330524cb, 0x82372315, 0x95012303, 0x3141d6fe, 0x2a012105, 0xfe260785, + 0x0d0d09d6, 0x85820109, 0x0dde0d36, 0x0c09ab08, 0x08ab090c, 0x5555950d, 0x6969d6fe, 0xc03e3e2b, 0x200bf048, 0x07a15b55, 0x87400121, 0x5e0d2629, + 0x6929402b, 0x08ea532a, 0x0982c020, 0x2a001e22, 0x3b29ae82, 0x15250000, 0x11331123, 0x26958327, 0x26222306, 0x83062327, 0x25ab8306, 0x35333537, + 0x59180333, 0x37250a1b, 0x17152327, 0x2f108a17, 0x2b6beb01, 0x21150646, 0x09241615, 0x1521074b, 0x0c318782, 0x95ab2a0a, 0x0d08090d, 0x0d09080d, + 0x3e643fb8, 0x074a5d82, 0x012a9528, 0x28d5fe55, 0x2f820f0e, 0x13131823, 0x26db8218, 0x6609180f, 0x5ceafe80, 0x5e240692, 0x4b405595, 0x35062063, + 0x15000400, 0x00025200, 0x2800ab01, 0x3b003400, 0x00004700, 0x91180701, 0x23200846, 0x3407fd5d, 0x36161716, 0x16163337, 0x37363637, 0x35272636, + 0x33161433, 0x0b3d5d33, 0x32331327, 0x23151516, 0x0a445d17, 0x29a00124, 0xaa82160c, 0x126b6a39, 0x111a1019, 0x5e072416, 0x13192807, 0x0c04031c, + 0x111a150c, 0x8555fe6b, 0x770d26bd, 0x560d0940, 0x269d8656, 0x0d287501, 0x82561912, 0x196b3737, 0x1e117c12, 0x18020113, 0x05191514, 0x11131d03, + 0x12260b1f, 0xf1834019, 0x0125f983, 0x56080d00, 0x180d8795, 0x2908e19d, 0x000b00d5, 0x001f001b, 0x9e603700, 0x33352105, 0x03200782, 0x260e415b, + 0x33352307, 0x8275402b, 0xff552701, 0x0c0c0900, 0x05830109, 0x80804922, 0x24053e5c, 0x0c550155, 0x21188909, 0x5d822b80, 0x15004026, 0xeb01c001, + 0x13205d82, 0x00315f82, 0x35211501, 0x35331123, 0x11331521, 0x35231507, 0x20038223, 0x39058401, 0x95011521, 0x2b2bd6fe, 0x2b2b2a01, 0x012a8080, + 0x01808000, 0x2beb012a, 0x1082fe2b, 0x56d6012c, 0x80565680, 0x5555d6fe, 0x0f5d8080, 0x0007220a, 0x28b38213, 0x00270023, 0x21152500, 0x219e8211, + 0x41181511, 0x196d0aab, 0x36322406, 0x5e263435, 0xc028088c, 0x552a95fe, 0x12191912, 0x01210382, 0x06914603, 0x80809226, 0xd5808096, 0x2a247682, + 0x194000ff, 0x8706bd5a, 0x82562007, 0x207582e1, 0x20cb8240, 0x20cb82eb, 0x27c9820f, 0x00520046, 0x25000056, 0x620f3f75, 0x27270a42, 0x35233736, + 0x60053a30, 0x232607e6, 0x22232626, 0xaf450706, 0x26332407, 0x82343526, 0x32132221, 0xcc631816, 0x33072308, 0x43182315, 0x6e620c03, 0x0cc73706, + 0x29198313, 0x1a2b3131, 0x0f201102, 0x07591219, 0x20151520, 0xc2825907, 0x078e122a, 0x6b570107, 0x07090907, 0x64230382, 0x62ebd6d6, 0x3526118b, + 0x072a1219, 0xba188e07, 0x0f350b52, 0x0b0a1120, 0x0905012b, 0x0a0a0607, 0x5a090706, 0x0008002b, 0x21e0842b, 0xe08300a0, 0x2c001f2a, 0x39003200, + 0x53004600, 0x0123e69d, 0x52211521, 0x352a0b08, 0x33152325, 0x15073636, 0xdf822633, 0x200c4956, 0x0c495615, 0x860b7549, 0xd5fe28e7, 0xeafe1601, + 0x7f0e126a, 0x012a0531, 0x1483eb55, 0x0157cd36, 0x1287c101, 0xe5920787, 0x2a0a0123, 0x06a043eb, 0x2a950d2a, 0x2a801614, 0x0b0a0a0b, 0x80201288, + 0x4a501b87, 0x82f02008, 0x003325e8, 0x00420038, 0x114b5f18, 0x07273723, 0x05b04117, 0x14150624, 0xab461716, 0x3736290f, 0x15170733, 0x37273733, + 0x2107d047, 0x5f180127, 0x6f320c61, 0x271f5a5a, 0x14210747, 0x18111d12, 0x11181212, 0x0282121d, 0x1c131834, 0x0e28480b, 0x52408640, 0x1d061206, + 0x06061d40, 0x634a9501, 0x1d122608, 0x1e5b5a49, 0x232c8427, 0xb2072114, 0x36823d85, 0x0b290c83, 0x40ee271c, 0x07344085, 0x25368207, 0x00071107, + 0xdb7c0003, 0x00ab3205, 0x0020001b, 0x1300002a, 0x26343521, 0x23172323, 0x29038727, 0x11150622, 0x33331614, 0xab852335, 0x2c081648, 0x19800155, + 0x402a4011, 0x402b2b2a, 0x2a03832b, 0x11191911, 0x2dd6abab, 0x484b2d6e, 0x01250787, 0x1912552b, 0x36008456, 0x00ff1219, 0x132b1912, 0x0f2e6e2d, + 0x0f06060f, 0x1106102e, 0x05000000, 0x9c1b47fa, 0x000000bb, +}; \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/Menu/Components.h b/Amalgam/src/Features/ImGui/Menu/Components.h new file mode 100644 index 0000000..dffe884 --- /dev/null +++ b/Amalgam/src/Features/ImGui/Menu/Components.h @@ -0,0 +1,1622 @@ +#pragma once +#include "../Render.h" +#include "Menu.h" +#include "../MaterialDesign/IconDefinitions.h" +#include "../../Conditions/Conditions.h" +#include "../../Visuals/Materials/Materials.h" +#include +#include + +const char* CurrentCondition = ""; + +enum FText_ +{ + FText_None = 0, + FText_Middle = 1 << 0, + FText_Right = 1 << 1 +}; + +enum FButton_ +{ + FButton_None = 0, + FButton_Left = 1 << 0, + FButton_Right = 1 << 1, + FButton_Fit = 1 << 2, + FButton_SameLine = 1 << 3, + FButton_Large = 1 << 4, + FButton_NoUpper = 1 << 5 +}; + +enum FKeybind_ +{ + FKeybind_None = 0, + FKeybind_AllowNone = 1 << 6, + FKeybind_AllowMenu = 1 << 7 +}; + +enum FToggle_ +{ + FToggle_None = 0, + FToggle_Middle = 1 << 0, + FToggle_PlainColor = 1 << 1 +}; + +enum FSlider_ +{ + FSlider_None = 0, + FSlider_Left = 1 << 0, + FSlider_Right = 1 << 1, + FSlider_Clamp = 1 << 2, // will keep within bounds when using text input + FSlider_Precision = 1 << 3, // allow more precise values outside of step when using text input +}; + +enum FDropdown_ +{ + FDropdown_None = 0, + FDropdown_Left = 1 << 0, + FDropdown_Right = 1 << 1, + FDropdown_Multi = 1 << 2 +}; + +enum FSDropdown_ +{ + FSDropdown_None = 0, + FSDropdown_Custom = 1 << 2, + FSDropdown_AutoUpdate = 1 << 3 +}; + +enum FColorPicker_ +{ + FColorPicker_None = 0, + FColorPicker_Left = 1 << 0, + FColorPicker_Middle = 1 << 1, + FColorPicker_SameLine = 1 << 2, + FColorPicker_Dropdown = 1 << 3 +}; + +namespace ImGui +{ + std::unordered_map mActives; + std::string sCondition = "default"; + bool bDisabled = false, bTransparent = false; + + __inline float fnmodf(float _X, float _Y) + { + // silly fix for negative values + return fmodf(_X, _Y) + (_X < 0 ? _Y : 0); + } + + __inline bool IsColorBright(Color_t color) + { + return color.r + color.g + color.b > 510; + } + + __inline bool IsColorBright(ImColor color) + { + return color.Value.x + color.Value.y + color.Value.z > 2.f; + } + + /* Color_t to ImVec4 */ + __inline ImVec4 ColorToVec(Color_t color) + { + return { float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f, float(color.a) / 255.f }; + } + + /* ImVec4 to Color_t */ + __inline Color_t VecToColor(ImVec4 color) + { + return { + static_cast(color.x * 256.0f > 255 ? 255 : color.x * 256.0f), + static_cast(color.y * 256.0f > 255 ? 255 : color.y * 256.0f), + static_cast(color.z * 256.0f > 255 ? 255 : color.z * 256.0f), + static_cast(color.w * 256.0f > 255 ? 255 : color.w * 256.0f) + }; + } + + + + __inline void DebugDummy(ImVec2 size) + { + const auto restorePos = GetCursorPos(); + + //PushStyleColor(ImGuiCol_Button, { 0.f, 0.f, 0.f, 0.5f }); + //Button("##", { std::max(size.x, 2.f), std::max(size.y, 2.f) }); + //PopStyleColor(); + + SetCursorPos(restorePos); Dummy(size); + } + __inline void DebugShift(ImVec2 size) + { + const auto restorePos = GetCursorPos(); + + //PushStyleColor(ImGuiCol_Button, { 1.f, 1.f, 1.f, 0.5f }); + //Button("##", { std::max(size.x, 2.f), std::max(size.y, 2.f) }); + //PopStyleColor(); + + SetCursorPos({ restorePos.x + size.x, restorePos.y + size.y }); + } + + __inline std::string StripDoubleHash(const char* text) + { + std::string strBegin = text, strEnd = FindRenderedTextEnd(text); + return strBegin.replace(strBegin.end() - strEnd.size(), strBegin.end(), ""); + } + + __inline std::string TruncateText(const char* text, int pixels) + { + std::string original = text; + if (!original.size()) + return ""; + + std::string truncated = ""; int i = 0; + while (CalcTextSize(truncated.c_str()).x < pixels) + { + i++; truncated = original.substr(0, i); + if (i == original.size()) + { + i = 0; break; + } + } + if (i) + truncated += "..."; + + return truncated; + } + + __inline const char* FormatText(const char* fmt, ...) + { + va_list args; + va_start(args, fmt); + + const char* text; + ImFormatStringToTempBufferV(&text, nullptr, fmt, args); + va_end(args); + + return text; + } + + __inline void AddSteppedRect(ImVec2 adjPos, ImVec2 clipmin, ImVec2 clipmax, ImVec2 posmin, ImVec2 posmax, float v_min, float v_max, float step, ImU32 primary, ImU32 secondary) + { + ImDrawList* drawList = GetWindowDrawList(); + drawList->PushClipRect({ adjPos.x + clipmin.x, adjPos.y + clipmin.y }, { adjPos.x + clipmax.x, adjPos.y + clipmax.y }, true); + + int steps = (v_max - v_min) / step; + if (steps < 21) + { + std::vector> steps; + + float min = v_min - fnmodf(v_min + step / 2, step) + step / 2, max = v_max - fnmodf(v_max + step / 2, step) + step / 2; + + if (fabsf(v_min - min) < 0.001f) + steps.push_back({ posmin.x, posmin.x + 2 }); + while (true) + { + min += step; + if (min + step / 2 > v_max) + break; + + float percent = std::clamp((min - v_min) / (v_max - v_min), 0.f, 1.f); + auto position = posmin.x + (posmax.x - posmin.x) * percent; + steps.push_back({ position - 1, position + 1 }); + } + if (fabsf(v_max - max) < 0.001f) + steps.push_back({ posmax.x - 2, posmax.x }); + + if (steps.size()) + { + for (size_t i = 0; i < steps.size(); i++) + { + if (!i) + drawList->AddRectFilled({ adjPos.x + posmin.x, adjPos.y + posmin.y }, { adjPos.x + steps.front().first, adjPos.y + posmax.y }, primary); + else + drawList->AddRectFilled({ adjPos.x + steps[i - 1].second, adjPos.y + posmin.y }, { adjPos.x + steps[i].first, adjPos.y + posmax.y }, primary); + drawList->AddRectFilled({ adjPos.x + steps[i].first, adjPos.y + posmin.y }, { adjPos.x + steps[i].second, adjPos.y + posmax.y }, secondary); + } + drawList->AddRectFilled({ adjPos.x + steps.back().second, adjPos.y + posmin.y }, { adjPos.x + posmax.x, adjPos.y + posmax.y }, primary); + + return drawList->PopClipRect(); + } + } + + drawList->AddRectFilled({ adjPos.x + posmin.x, adjPos.y + posmin.y }, { adjPos.x + posmax.x, adjPos.y + posmax.y }, primary); + + drawList->PopClipRect(); + } + + __inline void HelpMarker(const char* desc) + { + if (IsItemHovered()) + SetTooltip(desc); + } + + __inline void IconImage(const char* icon, bool large = false, ImVec4 color = { 1, 1, 1, -1 }) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + if (color.w > 0.f) + PushStyleColor(ImGuiCol_Text, color); + PushFont(large ? F::Render.IconFontLarge : F::Render.IconFontRegular); + TextUnformatted(icon); + PopFont(); + if (color.w > 0.f) + PopStyleColor(); + + if (bTransparent || bDisabled) + PopStyleVar(); + } + + __inline bool IconButton(const char* icon, bool large = false, ImVec4 color = { 1, 1, 1, -1 }) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + const auto originalPos = GetCursorPos(); + + if (color.w > 0.f) + PushStyleColor(ImGuiCol_Text, color); + PushFont(large ? F::Render.IconFontLarge : F::Render.IconFontRegular); + TextUnformatted(icon); + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + const bool pressed = IsItemClicked(); + PopFont(); + if (color.w > 0.f) + PopStyleColor(); + + // prevent accidental dragging + SetCursorPos(originalPos); + Button("##", GetItemRectSize()); + + if (bTransparent || bDisabled) + PopStyleVar(); + + return bDisabled ? false : pressed; + } + + std::unordered_map lastHeights; + std::vector storedTitles; + __inline bool Section(const char* title, float minHeight = 1.f, bool forceHeight = false) + { + storedTitles.push_back(title); + if (!forceHeight && lastHeights.contains(title) && lastHeights[title] > minHeight) + minHeight = lastHeights[title]; + PushStyleVar(ImGuiStyleVar_CellPadding, { 0, 0 }); + const bool active = BeginChild(title, { GetColumnWidth(), minHeight + 8 }, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_AlwaysUseWindowPadding); + + PushStyleVar(ImGuiStyleVar_ItemSpacing, { 8, 0 }); + if (title[0] != '#') + { + const auto restorePos = GetCursorPos(); + + PushStyleColor(ImGuiCol_Text, F::Render.Accent.Value); + PushFont(F::Render.FontBold); + SetCursorPosY(restorePos.y + 1); + TextUnformatted(StripDoubleHash(title).c_str()); + PopFont(); + PopStyleColor(); + + SetCursorPos(restorePos); DebugDummy({ 0, 16 }); + } + + return active; + } + __inline void EndSection() + { + const char* title = storedTitles.back(); + storedTitles.pop_back(); + if (GetItemRectMax().y - GetWindowPos().y > 0.f) + lastHeights[title] = GetItemRectMax().y - GetWindowPos().y; + + PopStyleVar(); + EndChild(); + PopStyleVar(); + } + + // widgets + __inline bool FTabs(std::vector titles, int* current, const ImVec2 size, const ImVec2 pos, bool vertical = false, std::vector icons = {}) + { + if (icons.size() && icons.size() != titles.size()) + return false; + + const int originalTab = current ? *current : 0; + for (size_t i = 0; i < titles.size(); i++) + { + ImVec2 newPos = pos; + if (!vertical) + newPos = { pos.x + size.x * i, pos.y }; + else + newPos = { pos.x, pos.y + size.y * i }; + SetCursorPos(newPos); + const ImVec2 adjPos = { newPos.x + GetWindowPos().x, newPos.y + GetWindowPos().y }; + + if (i != originalTab) + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + else + { + ImDrawList* drawList = GetWindowDrawList(); + if (!vertical) + drawList->AddRectFilled({ adjPos.x, adjPos.y + size.y - 2 }, { adjPos.x + size.x, adjPos.y + size.y }, F::Render.Accent); + else + drawList->AddRectFilled({ adjPos.x + size.x - 2, adjPos.y }, { adjPos.x + size.x, adjPos.y + size.y }, F::Render.Accent); + } + if (Button(std::format("##{}", titles[i]).c_str(), size) && i != originalTab && current) + { + if (storedTitles.size() == 0) + lastHeights.clear(); + *current = int(i); + } + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + + const auto originalPos = GetCursorPos(); + + const auto stripped = StripDoubleHash(titles[i]); + const auto textSize = CalcTextSize(stripped.c_str()); + SetCursorPos({ newPos.x + (size.x - textSize.x) / 2, newPos.y + (size.y - textSize.y) / 2 }); + if (icons.size()) + SetCursorPosY(GetCursorPosY() + 10); + TextUnformatted(stripped.c_str()); + if (icons.size()) + { + SetCursorPos({ newPos.x + size.x / 2 - 8, newPos.y + size.x / 2 - 14 }); + IconImage(icons[i]); + } + SetCursorPos(originalPos); + + if (i != originalTab) + PopStyleColor(); + } + return current ? (*current != originalTab ? true : false) : false; + } + + __inline bool FBeginPopup(const char* title, int flags = 0) + { + const bool bReturn = BeginPopup(title, flags); + if (bReturn) + PushStyleVar(ImGuiStyleVar_ItemSpacing, { 8, 8 }); + return bReturn; + } + __inline void FEndPopup() + { + PopStyleVar(); + EndPopup(); + } + __inline bool FSelectable(const char* label, ImVec4 color = { 0.2f, 0.6f, 0.85f, 1.f }, bool selected = false, int flags = 0, const ImVec2& size_arg = {}) + { + PushStyleVar(ImGuiStyleVar_SelectableRounding, 3.f); + PushStyleColor(ImGuiCol_HeaderHovered, color); + color.x *= 1.1f; color.y *= 1.1f; color.z *= 1.1f; + PushStyleColor(ImGuiCol_HeaderActive, color); + + const bool bReturn = Selectable(label, selected, flags, size_arg); + + PopStyleColor(2); + PopStyleVar(); + + return bReturn; + } + + __inline void FText(const char* text, int flags = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + const auto windowWidth = GetWindowSize().x; + const auto textWidth = CalcTextSize(text).x; + if (flags & FText_Middle) + SetCursorPosX((windowWidth - textWidth) * 0.5f); + else if (flags & FText_Right) + SetCursorPosX(windowWidth - textWidth - 8); + TextUnformatted(text); + + if (bTransparent || bDisabled) + PopStyleVar(); + } + + __inline bool FButton(const char* label, int flags = 0, int sizeOffset = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + std::string str = label; + if (!(flags & FButton_NoUpper)) + std::transform(str.begin(), str.end(), str.begin(), ::toupper); + label = str.c_str(); // why is this fucjking needed ??? ? + + float sizex = GetWindowSize().x - 2 * GetStyle().WindowPadding.x; + if (flags & FButton_Left || flags & FButton_Right) + sizex = GetWindowSize().x / 2 - GetStyle().WindowPadding.x - 4; + else if (flags & FButton_Fit) + sizex = CalcTextSize(label).x + (flags & FButton_Large ? 28 : 18); + if (flags & FButton_SameLine) + SameLine(); + else if (flags & FButton_Right) + SetCursorPosX(sizex + 20); + + const auto restorePos = GetCursorPos(); + DebugShift({ 0, 8 }); + + PushStyleColor(ImGuiCol_Border, F::Render.Accent.Value); + PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1); + const bool active = Button(label, { sizex + sizeOffset, flags & FButton_Large ? 40.f : 30.f }); + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + PopStyleVar(); + PopStyleColor(); + + SetCursorPos(restorePos); DebugDummy({ sizex + sizeOffset, flags & FButton_Large ? 48.f : 38.f }); + + if (bTransparent || bDisabled) + PopStyleVar(); + + return bDisabled ? false : active; + } + + __inline bool FToggle(const char* label, bool* var, int flags = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + if (flags & FToggle_Middle) + SameLine(GetWindowSize().x / 2 + 4); + + const auto restorePos = GetCursorPos(); + + bool changed = Button(std::format("##{}", label).c_str(), { GetWindowSize().x / 2 + 4 - 2 * GetStyle().WindowPadding.x, 24 }); + if (bDisabled) + changed = false; + if (changed) + *var = !*var; + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + + SetCursorPos({ restorePos.x + 4, restorePos.y + 3 }); + IconImage(*var ? ICON_MD_CHECK_BOX : ICON_MD_CHECK_BOX_OUTLINE_BLANK, true, *var ? (flags & FToggle_PlainColor ? F::Render.Active.Value : F::Render.Accent.Value) : F::Render.Inactive.Value); + + SetCursorPos({ restorePos.x + 24, restorePos.y + 5 }); + if (*var) + PushStyleColor(ImGuiCol_Text, F::Render.Active.Value); + else + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + TextUnformatted(StripDoubleHash(label).c_str()); + PopStyleColor(); + + SetCursorPos(restorePos); DebugDummy({ 0, 24 }); + + if (bTransparent || bDisabled) + PopStyleVar(); + + return changed; + } + + __inline bool FSlider(const char* label, float* var1, float* var2, float v_min, float v_max, float step = 1.f, const char* fmt = "%.0f", int flags = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + float originalVar1 = *var1, originalVar2; + if (var2) + originalVar2 = *var2; + + if (flags & FSlider_Right) + SameLine(GetWindowSize().x / 2 + 4); + + float sizex = GetWindowSize().x, sizexHalf = sizex / 2 + 4; + if (flags & (FSlider_Left | FSlider_Right)) + sizex = sizexHalf; + if (flags & FSlider_Right) + SameLine(sizex); + sizex = sizex - 2 * GetStyle().WindowPadding.x; + sizexHalf = sizexHalf - 2 * GetStyle().WindowPadding.x; + + const auto restorePos = GetCursorPos(); auto adjPos = GetWindowPos(); + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + + if (flags & (FSlider_Left | FSlider_Right)) + SetCursorPos({ restorePos.x + 6, restorePos.y + 3 }); + else + SetCursorPos({ restorePos.x + 6, restorePos.y + 5 }); + TextUnformatted(StripDoubleHash(label).c_str()); + + { + static std::string text, input; std::string index = std::format("{}## Text", label); + if (!mActives[index]) + { + if (var2) + text = FormatText(fmt, *var1, *var2); + else + text = FormatText(fmt, *var1); + } + else + { + SetCursorPos({ -1000, flags & (FSlider_Left | FSlider_Right) ? restorePos.y + 3 : restorePos.y + 5 }); // lol + SetKeyboardFocusHere(); + const bool enter = InputText("##SliderText", &input, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CharsDecimal); text = input; + if (enter) + { + try // prevent the user from being a retard with invalid inputs + { + if (var2) + switch (mActives[index]) + { + case 1: + *var1 = text.length() ? std::stof(text) : 0.f; + *var1 = std::min(*var1, *var2 - step); + if (!(flags & FSlider_Precision)) + *var1 = *var1 - fnmodf(*var1 - step / 2, step) + step / 2; + if (flags & FSlider_Clamp) + *var1 = std::clamp(*var1, v_min, v_max); + break; + case 2: + *var2 = text.length() ? std::stof(text) : 0.f; + *var2 = std::max(*var2, *var1 + step); + if (!(flags & FSlider_Precision)) + *var2 = *var2 - fnmodf(*var2 - step / 2, step) + step / 2; + if (flags & FSlider_Clamp) + *var2 = std::clamp(*var2, v_min, v_max); + } + else + { + *var1 = text.length() ? std::stof(text) : 0.f; + if (!(flags & FSlider_Precision)) + *var1 = *var1 - fnmodf(*var1 - step / 2, step) + step / 2; + if (flags & FSlider_Clamp) + *var1 = std::clamp(*var1, v_min, v_max); + } + } + catch (...) {} + } + if (enter || IsMouseClicked(ImGuiMouseButton_Left) || ImGui::IsKeyPressed(ImGuiKey_Escape)) + mActives[index] = false; + } + const float width = CalcTextSize(text.c_str()).x; + if (flags & (FSlider_Left | FSlider_Right)) + SetCursorPos({ restorePos.x + sizex - width - 6, restorePos.y + 3 }); + else + SetCursorPos({ restorePos.x + sizex - 40, restorePos.y + 5 }); + const auto original = GetCursorPos(); + + TextUnformatted(text.c_str()); + if (!bDisabled) + { + if (!bDisabled && IsItemHovered() && ImGui::IsWindowHovered()) + SetMouseCursor(ImGuiMouseCursor_TextInput); + if (mActives[index]) + GetWindowDrawList()->AddRectFilled({ adjPos.x + original.x, adjPos.y + original.y + 14 }, { adjPos.x + original.x + width, adjPos.y + original.y + 15 }, F::Render.Active); + else if (IsItemClicked()) + { + if (var2) + { + if (GetMousePos().x - adjPos.x - original.x < width / 2) + { + input = std::format("{}", *var1); + mActives[index] = 1; + } + else + { + input = std::format("{}", *var2); + mActives[index] = 2; + } + } + else + { + input = std::format("{}", *var1); + mActives[index] = true; + } + } + } + } + + auto accent = F::Render.Accent, muted = accent, washed = accent, transparent = accent; + muted.Value.w *= 0.8f, washed.Value.w *= 0.4f, transparent.Value.w *= 0.2f; + if (bTransparent || bDisabled) + accent.Value.w /= 2, muted.Value.w /= 2, washed.Value.w /= 2, transparent.Value.w /= 2; + adjPos.x += restorePos.x; adjPos.y += restorePos.y; + ImVec2 mins = { sizex - sizexHalf - 16, 11 }, maxs = { sizex - 54, 13 }; + if (flags & (FSlider_Left | FSlider_Right)) + mins = { 6, 24 }, maxs = { sizex - 6, 26 }; + + ImDrawList* drawList = GetWindowDrawList(); auto mouse = GetMousePos(); + const bool within = adjPos.x + mins.x - 6 < mouse.x && mouse.x < adjPos.x + maxs.x + 5 && + adjPos.y + mins.y - 6 < mouse.y && mouse.y < adjPos.y + maxs.y + 5; + if (!bDisabled && within && ImGui::IsWindowHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + const float mousePerc = (mouse.x - (adjPos.x + mins.x)) / ((adjPos.x + maxs.x) - (adjPos.x + mins.x)) + (step / 2) / (v_max - v_min); + if (var2) + { + float lowerPerc = std::clamp((*var1 - v_min) / (v_max - v_min), 0.f, 1.f), upperPerc = std::clamp((*var2 - v_min) / (v_max - v_min), 0.f, 1.f); + auto lowerPos = mins.x + (maxs.x - mins.x) * lowerPerc, upperPos = mins.x + (maxs.x - mins.x) * upperPerc; + + AddSteppedRect(adjPos, mins, { lowerPos, maxs.y }, mins, maxs, v_min, v_max, step, washed, muted); + AddSteppedRect(adjPos, { lowerPos, mins.y }, { upperPos, maxs.y }, mins, maxs, v_min, v_max, step, accent, washed); + AddSteppedRect(adjPos, { upperPos, mins.y }, maxs, mins, maxs, v_min, v_max, step, washed, muted); + drawList->AddCircleFilled({ adjPos.x + lowerPos, adjPos.y + mins.y + 1 }, 3.f, accent); + drawList->AddCircleFilled({ adjPos.x + upperPos, adjPos.y + mins.y + 1 }, 3.f, accent); + + if (!bDisabled) + { + if (within && !mActives[label] && ImGui::IsWindowHovered()) + { + if (fabsf(mouse.x - (adjPos.x + lowerPos)) < fabsf(mouse.x - (adjPos.x + upperPos))) + { + if (!IsMouseDown(ImGuiMouseButton_Left)) + drawList->AddCircleFilled({ adjPos.x + lowerPos, adjPos.y + mins.y + 1 }, 11.f, transparent); + if (IsMouseClicked(ImGuiMouseButton_Left)) + mActives[label] = 1; + } + else + { + if (!IsMouseDown(ImGuiMouseButton_Left)) + drawList->AddCircleFilled({ adjPos.x + upperPos, adjPos.y + mins.y + 1 }, 11.f, transparent); + if (IsMouseClicked(ImGuiMouseButton_Left)) + mActives[label] = 2; + } + } + else if ((mActives[label] == 1 || mActives[label] == 2) && IsMouseDown(ImGuiMouseButton_Left)) + { + //a + (b - a) * t [lerp] + switch (mActives[label]) + { + case 1: + *var1 = std::min(v_min + (v_max - v_min) * mousePerc, *var2 - step); + *var1 = std::clamp(*var1 - fnmodf(*var1, step), v_min, v_max); + drawList->AddCircleFilled({ adjPos.x + lowerPos, adjPos.y + mins.y + 1 }, 11.f, washed); + break; + case 2: + *var2 = std::max(v_min + (v_max - v_min) * mousePerc, *var1 + step); + *var2 = std::clamp(*var2 - fnmodf(*var2, step), v_min, v_max); + drawList->AddCircleFilled({ adjPos.x + upperPos, adjPos.y + mins.y + 1 }, 11.f, washed); + } + } + else + mActives[label] = false; + } + } + else + { + float percent = std::clamp((*var1 - v_min) / (v_max - v_min), 0.f, 1.f); + + AddSteppedRect(adjPos, mins, { mins.x + (maxs.x - mins.x) * percent, maxs.y }, mins, maxs, v_min, v_max, step, accent, washed); + AddSteppedRect(adjPos, { mins.x + (maxs.x - mins.x) * percent, mins.y }, maxs, mins, maxs, v_min, v_max, step, washed, muted); + drawList->AddCircleFilled({ adjPos.x + mins.x + (maxs.x - mins.x) * percent, adjPos.y + mins.y + 1 }, 3.f, accent); + + if (!bDisabled) + { + if (within && !mActives[label] && ImGui::IsWindowHovered()) + { + if (!IsMouseDown(ImGuiMouseButton_Left)) + drawList->AddCircleFilled({ adjPos.x + mins.x + (maxs.x - mins.x) * percent, adjPos.y + mins.y + 1 }, 11.f, transparent); + if (IsMouseClicked(ImGuiMouseButton_Left)) + mActives[label] = 1; + } + else if (mActives[label] == 1 && IsMouseDown(ImGuiMouseButton_Left)) + { + *var1 = v_min + (v_max - v_min) * mousePerc; + *var1 = std::clamp(*var1 - fnmodf(*var1, step), v_min, v_max); + drawList->AddCircleFilled({ adjPos.x + mins.x + (maxs.x - mins.x) * percent, adjPos.y + mins.y + 1 }, 11.f, washed); + } + else + mActives[label] = false; + } + } + + PopStyleColor(); + SetCursorPos({ restorePos.x + mins.x - 5, restorePos.y + mins.y - 5 }); + Button("##", { maxs.x - mins.x + 10, 12 }); // don't drag it around + SetCursorPos(restorePos); Dummy({ 0, flags & (FSlider_Left | FSlider_Right) ? 32.f : 24.f }); + + bool changed = *var1 != originalVar1; + if (!changed && var2) + changed = *var2 != originalVar2; + + if (bTransparent || bDisabled) + PopStyleVar(); + + return changed; + } + + __inline bool FSlider(const char* label, int* var1, int* var2, int v_min, int v_max, int step = 1, const char* fmt = "%d", int flags = 0) + { + // replace incorrect formats as it will be converted to float + std::string replace = fmt; + + std::string from = "%d", to = "%.0f"; + auto found = replace.find(from); + while (found != std::string::npos) + { + replace.replace(found, from.length(), to); + found = replace.find(from); + } + from = "%i"; + found = replace.find(from); + while (found != std::string::npos) + { + replace.replace(found, from.length(), to); + found = replace.find(from); + } + + fmt = replace.c_str(); + + float redir1 = *var1; float redir2 = var2 ? *var2 : 0; + const bool changed = FSlider(label, &redir1, var2 ? &redir2 : nullptr, v_min, v_max, step, fmt, flags); + *var1 = redir1; if (var2) *var2 = redir2; + return changed; + } + + __inline bool FSlider(const char* label, float* var, float v_min, float v_max, float step = 1.f, const char* fmt = "%.0f", int flags = 0) + { + return FSlider(label, var, nullptr, v_min, v_max, step, fmt, flags); + } + + __inline bool FSlider(const char* label, int* var, int v_min, int v_max, int step = 1, const char* fmt = "%d", int flags = 0) + { + return FSlider(label, var, nullptr, v_min, v_max, step, fmt, flags); + } + + __inline bool FDropdown(const char* label, int* var, std::vector titles, std::vector values = {}, int flags = 0, int colors = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + bool changed = false; + + if (values.size() == 0) + { + for (size_t i = 0; i < titles.size(); i++) + { + if (flags & FDropdown_Multi) + values.push_back(1 << int(i)); + else + values.push_back(int(i)); + } + } + + std::string preview = ""; + if (flags & FDropdown_Multi && *var == 0) + preview = "None"; + else + { + for (size_t i = 0; i < values.size(); i++) + { + if (flags & FDropdown_Multi) + { + if (*var & values[i]) + preview += std::format("{}, ", StripDoubleHash(titles[i]).c_str()); + } + else + { + if (*var == values[i]) + preview = std::format("{}##", StripDoubleHash(titles[i]).c_str()); + } + } + preview.pop_back(); preview.pop_back(); + } + + PushStyleVar(ImGuiStyleVar_FramePadding, { 0.f, 13.5f }); + float sizex = GetWindowSize().x; + if (flags & (FDropdown_Left | FDropdown_Right)) + sizex = sizex / 2 + 4; + if (flags & FDropdown_Right) + SameLine(sizex); + sizex = sizex - 2 * GetStyle().WindowPadding.x - 10 * colors; + PushItemWidth(sizex); + + const auto restorePos = GetCursorPos(); + DebugShift({ 0, 8 }); + + if (bDisabled) + { // lol + Button("##", { sizex, 40 }); + SetCursorPos(restorePos); + DebugShift({ 0, 8 }); + } + + bool active = false; + if (BeginCombo(std::format("##{}", label).c_str(), "", ImGuiComboFlags_CustomPreview | ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_HeightLarge)) + { + active = true; + + DebugDummy({ 0, 8 }); + PushStyleVar(ImGuiStyleVar_ItemSpacing, { 0, 19 }); + for (size_t i = 0; i < titles.size(); i++) + { + const auto stripped = StripDoubleHash(titles[i]); + if (flags & FDropdown_Multi) + { + bool flagActive = *var & values[i]; + + if (Selectable(std::format("##{}", titles[i]).c_str(), flagActive, ImGuiSelectableFlags_DontClosePopups)) + { + if (flagActive) + *var &= ~values[i]; + else + *var |= values[i]; + changed = true; + } + + const auto originalPos = GetCursorPos(); + SetCursorPos({ originalPos.x + 40, originalPos.y - 31 }); + PushStyleColor(ImGuiCol_Text, flagActive ? F::Render.Active.Value : F::Render.Inactive.Value); + TextUnformatted(stripped.c_str()); + PopStyleColor(); + + SetCursorPos({ originalPos.x + 16, originalPos.y - 33 }); + IconImage(flagActive ? ICON_MD_CHECK_BOX : ICON_MD_CHECK_BOX_OUTLINE_BLANK, true, flagActive ? F::Render.Accent.Value : F::Render.Inactive.Value); + SetCursorPos(originalPos); + } + else + { + if (Selectable(std::format("##{}", titles[i]).c_str(), *var == values[i])) + { + *var = values[i]; changed = true; + } + + const auto originalPos = GetCursorPos(); + SetCursorPos({ originalPos.x + 20, originalPos.y - 31 }); + PushStyleColor(ImGuiCol_Text, *var == values[i] ? F::Render.Active.Value : F::Render.Inactive.Value); + TextUnformatted(stripped.c_str()); + PopStyleColor(); + SetCursorPos(originalPos); + } + } + PopStyleVar(); + SetCursorPosY(GetCursorPosY() - 10); Dummy({}); + + EndCombo(); + } + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + if (BeginComboPreview()) + { + const auto originalPos = GetCursorPos(); + + SetCursorPos({ originalPos.x + 12, originalPos.y - 5 }); + PushFont(F::Render.FontSmall); + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + TextUnformatted(StripDoubleHash(label).c_str()); + PopStyleColor(); + PopFont(); + + SetCursorPos({ originalPos.x + 12, originalPos.y + 8 }); + TextUnformatted(TruncateText(preview.c_str(), sizex - 55).c_str()); + + SetCursorPos({ originalPos.x + sizex - 25, originalPos.y - 2 }); + IconImage(active ? ICON_MD_ARROW_DROP_UP : ICON_MD_ARROW_DROP_DOWN, true); + + EndComboPreview(); + } + SetCursorPos(restorePos); DebugDummy({ sizex, 48 }); + + PopItemWidth(); + PopStyleVar(); + + if (bTransparent || bDisabled) + PopStyleVar(); + + return changed; + } + + __inline bool FSDropdown(const char* label, std::string* var, std::vector entries = {}, int flags = 0, int colors = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + bool changed = false; + + if (!entries.size()) + { + PushStyleColor(ImGuiCol_PopupBg, {}); + PushStyleVar(ImGuiStyleVar_WindowPadding, { GetStyle().WindowPadding.x, 0 }); + } + PushStyleVar(ImGuiStyleVar_FramePadding, { 0.f, 13.5f }); + float sizex = GetWindowSize().x; + if (flags & (FDropdown_Left | FDropdown_Right)) + sizex = sizex / 2 + 4; + if (flags & FDropdown_Right) + SameLine(sizex); + sizex = sizex - 2 * GetStyle().WindowPadding.x - 10 * colors; + PushItemWidth(sizex); + + const auto restorePos = GetCursorPos(); + DebugShift({ 0, 8 }); + + if (bDisabled) + { // lol + Button("##", { sizex, 40 }); + SetCursorPos(restorePos); + DebugShift({ 0, 8 }); + } + + static std::string preview = "", input = "", staticif = "\n"; + if (BeginCombo(std::format("##{}", label).c_str(), "", ImGuiComboFlags_CustomPreview | ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_HeightLarge)) + { + if (!mActives[label]) + preview = input = ""; + + mActives[label] = true; + + int tab = U::KeyHandler.Pressed(VK_TAB) ? 1 : 0; + + // this textinput is being used as a temporary measure to prevent the main window drawing over the popup + const auto restorePos = GetCursorPos(); + SetCursorPos({ -1000, entries.size() ? GetScrollY() : -100 }); // lol + if (!IsMouseDown(ImGuiMouseButton_Left)) + SetKeyboardFocusHere(); + const bool enter = InputText("##FSDropdown", &input, ImGuiInputTextFlags_EnterReturnsTrue); + if (input != staticif) + { + preview = input; + staticif = "\n"; + } + SetCursorPos(restorePos); + + std::vector> valid = {}; + std::string current = *var, search = input, display = preview; + std::transform(current.begin(), current.end(), current.begin(), ::tolower); + std::transform(search.begin(), search.end(), search.begin(), ::tolower); + std::transform(display.begin(), display.end(), display.begin(), ::tolower); + for (size_t i = 0; i < entries.size(); i++) + { + std::string entry = entries[i]; + std::transform(entry.begin(), entry.end(), entry.begin(), ::tolower); + + auto found = entry.find(search); + if (found != std::string::npos) + valid.push_back({ entries[i], entry }); + } + + if (valid.size()) + { + DebugDummy({ 0, 8 }); + PushStyleVar(ImGuiStyleVar_ItemSpacing, { 0, 19 }); + + for (size_t i = 0; i < valid.size(); i++) + { + if (enter && !(flags & FSDropdown_Custom)) + { + *var = valid[i].first; changed = true; + CloseCurrentPopup(); break; + } + if (tab == 1) + { + preview = valid[i].first; + staticif = input; + tab = 2; + } + if (tab && display == valid[i].second) + tab = 1; + + if (Selectable(std::format("##{}", valid[i].first).c_str(), current == valid[i].second)) + { + *var = valid[i].first; changed = true; + } + + const auto originalPos = GetCursorPos(); + SetCursorPos({ originalPos.x + 20, originalPos.y - 31 }); + PushStyleColor(ImGuiCol_Text, current == valid[i].second ? F::Render.Active.Value : F::Render.Inactive.Value); + TextUnformatted(valid[i].first.c_str()); + PopStyleColor(); + SetCursorPos(originalPos); + } + + PopStyleVar(); + SetCursorPosY(GetCursorPosY() - 10); Dummy({}); + } + + if ((enter || flags & FSDropdown_AutoUpdate) && (flags & FSDropdown_Custom || !entries.size())) + *var = preview; changed = true; + if (enter) + CloseCurrentPopup(); + + EndCombo(); + } + else + mActives[label] = false; + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_TextInput); + if (BeginComboPreview()) + { + const auto originalPos = GetCursorPos(); + + SetCursorPos({ originalPos.x + 12, originalPos.y - 5 }); + PushFont(F::Render.FontSmall); + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + TextUnformatted(StripDoubleHash(label).c_str()); + PopStyleColor(); + PopFont(); + + SetCursorPos({ originalPos.x + 12, originalPos.y + 8 }); + // would like this to work properly, text looks nicer but overrides window + /* + if (active) + { + PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 }); + PushStyleColor(ImGuiCol_FrameBg, {}); + PushItemWidth(sizex - 12); + if (!IsAnyItemActive()) // silly, but afaik no way to have a one time focus + SetKeyboardFocusHere(); + enter = FInputText("##FSDropdown", &preview, ImGuiInputTextFlags_EnterReturnsTrue); + PopItemWidth(); + PopStyleColor(); + PopStyleVar(); + } + else + TextUnformatted(TruncateText(var->c_str(), sizex - (entries.size() ? 55 : 15)).c_str()); + */ + TextUnformatted(TruncateText(mActives[label] ? preview.c_str() : var->c_str(), sizex - (entries.size() ? 55 : 35)).c_str()); + + if (entries.size()) + { + SetCursorPos({ originalPos.x + sizex - 25, originalPos.y - 2 }); + IconImage(mActives[label] ? ICON_MD_ARROW_DROP_UP : ICON_MD_ARROW_DROP_DOWN, true); + } + + if (mActives[label] || flags & FSDropdown_Custom || !entries.size()) + { + ImVec2 adjPos = GetWindowPos(); adjPos.x += originalPos.x; adjPos.y += originalPos.y; + GetWindowDrawList()->AddRectFilled({ adjPos.x + 12, adjPos.y + 22 }, { adjPos.x + sizex - (entries.size() ? 33 : 13), adjPos.y + 23 }, mActives[label] ? F::Render.Active : F::Render.Inactive); + } + + EndComboPreview(); + } + PopItemWidth(); + PopStyleVar(); + if (!entries.size()) + { + PopStyleColor(); + PopStyleVar(); + } + + SetCursorPos(restorePos); DebugDummy({ sizex, 48 }); + + if (bTransparent || bDisabled) + PopStyleVar(); + + return changed; + } + + __inline bool FVDropdown(const char* label, std::vector* var, std::vector titles, int flags = 0, int colors = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + bool changed = false; + + std::unordered_map::iterator> iterators = {}; + for (auto it = var->begin(); it != var->end(); it++) + iterators[*it] = it; + std::unordered_map integers = {}; + for (size_t i = 0; i < var->size(); i++) + integers[(*var)[i]] = int(i) + 1; + + std::string preview = ""; + if (!var->size()) + preview = "None"; + else + { + for (size_t i = 0; i < var->size(); i++) + preview += std::format("{}, ", (*var)[i].c_str()); + preview.pop_back(); preview.pop_back(); + } + + PushStyleVar(ImGuiStyleVar_FramePadding, { 0.f, 13.5f }); + float sizex = GetWindowSize().x; + if (flags & (FDropdown_Left | FDropdown_Right)) + sizex = sizex / 2 + 4; + if (flags & FDropdown_Right) + SameLine(sizex); + sizex = sizex - 2 * GetStyle().WindowPadding.x - 10 * colors; + PushItemWidth(sizex); + + const auto restorePos = GetCursorPos(); + DebugShift({ 0, 8 }); + + if (bDisabled) + { // lol + Button("##", { sizex, 40 }); + SetCursorPos(restorePos); + DebugShift({ 0, 8 }); + } + + bool active = false; + if (BeginCombo(std::format("##{}", label).c_str(), "", ImGuiComboFlags_CustomPreview | ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_HeightLarge)) + { + active = true; + + DebugDummy({ 0, 8 }); + PushStyleVar(ImGuiStyleVar_ItemSpacing, { 0, 19 }); + for (size_t i = 0; i < titles.size(); i++) + { + auto find = iterators.find(titles[i]); + bool flagActive = find != iterators.end(); + + if (Selectable(std::format("##{}", titles[i]).c_str(), flagActive, ImGuiSelectableFlags_DontClosePopups)) + { + if (flagActive) + var->erase(find->second); + else + var->push_back(titles[i]); + changed = true; + } + + // shift based on number of digits in var size + const auto originalPos = GetCursorPos(); + SetCursorPos({ originalPos.x + 40 + 6 * std::min(int(log10(var->size())), 0), originalPos.y - 31 }); + PushStyleColor(ImGuiCol_Text, flagActive ? F::Render.Active.Value : F::Render.Inactive.Value); + TextUnformatted(titles[i].c_str()); + PopStyleColor(); + + if (flagActive) + { + SetCursorPos({ originalPos.x + 18, originalPos.y - 31 }); + PushStyleColor(ImGuiCol_Text, F::Render.Accent.Value); + TextUnformatted(std::format("{}", integers[titles[i]]).c_str()); + PopStyleColor(); + } + SetCursorPos(originalPos); + } + PopStyleVar(); + SetCursorPosY(GetCursorPosY() - 10); Dummy({}); + + EndCombo(); + } + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + if (BeginComboPreview()) + { + const auto originalPos = GetCursorPos(); + + SetCursorPos({ originalPos.x + 12, originalPos.y - 5 }); + PushFont(F::Render.FontSmall); + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + TextUnformatted(StripDoubleHash(label).c_str()); + PopStyleColor(); + PopFont(); + + SetCursorPos({ originalPos.x + 12, originalPos.y + 8 }); + TextUnformatted(TruncateText(preview.c_str(), sizex - 55).c_str()); + + SetCursorPos({ originalPos.x + sizex - 25, originalPos.y - 2 }); + IconImage(active ? ICON_MD_ARROW_DROP_UP : ICON_MD_ARROW_DROP_DOWN, true); + + EndComboPreview(); + } + SetCursorPos(restorePos); DebugDummy({ sizex, 48 }); + + PopItemWidth(); + PopStyleVar(); + + if (bTransparent || bDisabled) + PopStyleVar(); + + return changed; + } + + __inline bool ColorPicker(const char* label, Color_t* color, bool marker = true, int flags = 0) + { + if (bDisabled) + { // lol + const auto restorePos = GetCursorPos(); + Button("##", flags & FColorPicker_Dropdown ? ImVec2(10, 40) : ImVec2(12, 12)); + SetCursorPos(restorePos); + } + + ImVec4 tempColor = ColorToVec(*color); + + bool changed = false; + PushStyleVar(ImGuiStyleVar_FramePadding, { 2, 2 }); + PushStyleVar(ImGuiStyleVar_ItemSpacing, { 0, 4 }); + PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, { 4, 0 }); + PushStyleColor(ImGuiCol_PopupBg, F::Render.Foreground.Value); + if (ColorEdit4(std::format("##{}", label).c_str(), &tempColor.x, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoBorder | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_Round, flags & FColorPicker_Dropdown ? ImVec2(10, 40) : ImVec2(12, 12))) + { + *color = VecToColor(tempColor); + changed = true; + } + PopStyleColor(); + PopStyleVar(3); + if (!bDisabled && IsItemHovered()) + SetMouseCursor(ImGuiMouseCursor_Hand); + if (marker) + HelpMarker(label); + + return changed; + } + + // if items overlap, use before to have working input, e.g. a middle toggle and a color picker + __inline bool FColorPicker(const char* label, Color_t* color, int offset = 0, int flags = 0) + { + if (bTransparent || bDisabled) + PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); + + bool changed = false; + if (!(flags & FColorPicker_Dropdown)) + { + int pos; + if (flags & FColorPicker_Left) + pos = 14 + (offset * 12); + else if (flags & FColorPicker_Middle) + pos = GetContentRegionMax().x / 2 + 5 - (offset * 12); + else + pos = GetContentRegionMax().x - 20 - (offset * 12); + if (flags & FColorPicker_SameLine) + SameLine(pos); + else + SetCursorPosX(pos); + + const auto restorePos = GetCursorPos(); + DebugShift({ 0, 5 }); + + changed = ColorPicker(label, color, !(flags & (FColorPicker_Left | FColorPicker_Middle))); + if (flags & (FColorPicker_Left | FColorPicker_Middle)) + { + SameLine(); TextUnformatted(label); + SetCursorPos(restorePos); DebugDummy({ 0, 24 }); + } + else + { + SetCursorPos(restorePos); Dummy({ 0, 0 }); + } + } + else + { + SameLine(); DebugShift({ -8, 0 }); + const auto restorePos = GetCursorPos(); DebugShift({ 0, 8 }); + changed = ColorPicker(label, color, false, flags); + SetCursorPos(restorePos); DebugDummy({ 10, 48 }); + } + + if (bTransparent || bDisabled) + PopStyleVar(); + + return changed; + } + + short iKeyPressed = 0; + __inline void KeyHandler() + { + static std::map mOldKeys = {}; + std::map mNewKeys = {}; + + for (short iKey = 0; iKey < 255; iKey++) + mNewKeys[iKey] = GetAsyncKeyState(iKey) & 0x8000; + + iKeyPressed = 0; + for (auto& [iKey, bPressed] : mNewKeys) + { + if (bPressed && (!mOldKeys.contains(iKey) || !mOldKeys[iKey])) + { + iKeyPressed = iKey; + break; + } + } + + mOldKeys = mNewKeys; + } + + __inline std::string VK2STR(const short key) + { + switch (key) + { + case 0x0: return "none"; + case VK_LBUTTON: return "mouse1"; + case VK_RBUTTON: return "mouse2"; + case VK_MBUTTON: return "mouse3"; + case VK_XBUTTON1: return "mouse4"; + case VK_XBUTTON2: return "mouse5"; + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: return "control"; + case VK_NUMPAD0: return "num0"; + case VK_NUMPAD1: return "num1"; + case VK_NUMPAD2: return "num2"; + case VK_NUMPAD3: return "num3"; + case VK_NUMPAD4: return "num4"; + case VK_NUMPAD5: return "num5"; + case VK_NUMPAD6: return "num6"; + case VK_NUMPAD7: return "num7"; + case VK_NUMPAD8: return "num8"; + case VK_NUMPAD9: return "num9"; + case VK_DIVIDE: return "num/"; + case VK_INSERT: return "insert"; + case VK_DELETE: return "delete"; + case VK_PRIOR: return "pgup"; + case VK_NEXT: return "pgdown"; + case VK_HOME: return "home"; + case VK_END: return "end"; + case VK_CLEAR: return "clear"; + case VK_UP: return "up"; + case VK_DOWN: return "down"; + case VK_LEFT: return "left"; + case VK_RIGHT: return "right"; + case VK_ESCAPE: return "escape"; + case VK_F13: return "f13"; + case VK_F14: return "f14"; + case VK_F15: return "f15"; + case VK_F16: return "f16"; + case VK_F17: return "f17"; + case VK_F18: return "f18"; + case VK_F19: return "f19"; + case VK_F20: return "f20"; + case VK_F21: return "f21"; + case VK_F22: return "f22"; + case VK_F23: return "f23"; + case VK_F24: return "f24"; + case VK_LWIN: + case VK_RWIN: return "windows"; + case VK_PAUSE: return "pause"; + case VK_APPS: return "apps"; + } + + std::string str = "unknown"; + + CHAR output[16] = { "\0" }; + if (GetKeyNameTextA(MapVirtualKeyW(key, MAPVK_VK_TO_VSC) << 16, output, 16)) + str = output; + + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end()); + + if (Vars::Debug::Info.Value && FNV1A::Hash(str.c_str()) == FNV1A::HashConst("unknown")) + str = std::format("{:#x}", key); + + return str; + } + __inline bool FKeybind(const char* label, int& output, int flags = 0, int sizeOffset = 0) + { + static bool bCanceled = false; + + const auto id = GetID(label); + PushID(label); + + if (GetActiveID() == id) + { + F::Menu.InKeybind = true; + + //FButton("...", flags | FButton_NoUpper, sizeOffset); + FButton(std::format("{}: ...", label).c_str(), flags | FButton_NoUpper, sizeOffset); + const bool bHovered = IsItemHovered(); + + if (bHovered && IsMouseClicked(ImGuiMouseButton_Left)) + { + bCanceled = true; + ClearActiveID(); + } + else + { + SetActiveID(id, GetCurrentWindow()); + + if (iKeyPressed) + { + switch (iKeyPressed) + { + case VK_LBUTTON: + output = bHovered ? output : iKeyPressed; + break; + case VK_ESCAPE: + if (flags & FKeybind_AllowNone) + { + output = 0x0; + break; + } + [[fallthrough]]; + default: + if (flags & FKeybind_AllowMenu || iKeyPressed != Vars::Menu::MenuPrimaryKey.Value && iKeyPressed != Vars::Menu::MenuSecondaryKey.Value) + output = iKeyPressed; + } + ClearActiveID(); + } + } + + GetCurrentContext()->ActiveIdAllowOverlap = true; + } + //else if (FButton(VK2STR(output).c_str(), flags | FButton_NoUpper) && !bCanceled) + else if (FButton(std::format("{}: {}", label, VK2STR(output)).c_str(), flags | FButton_NoUpper, sizeOffset) && !bCanceled) + SetActiveID(id, GetCurrentWindow()); + + if (bCanceled && !IsMouseDown(ImGuiMouseButton_Left) && !IsMouseReleased(ImGuiMouseButton_Left)) + bCanceled = false; + + PopID(); + + return true; + } + + // dropdown for materials + __inline bool FMDropdown(const char* label, std::vector* var, int flags = 0, int colors = 0) + { + std::vector> vMaterials; + for (auto const& [sName, mat] : F::Materials.mChamMaterials) + { + if (FNV1A::Hash(sName.c_str()) != FNV1A::HashConst("None")) + vMaterials.push_back({ sName, mat }); + } + + std::sort(vMaterials.begin(), vMaterials.end(), [&](const auto& a, const auto& b) -> bool + { + // keep locked materials higher + if (a.second.bLocked && !b.second.bLocked) + return true; + if (!a.second.bLocked && b.second.bLocked) + return false; + + return a.first < b.first; + }); + + std::vector entries = { "Original" }; + for (const auto& pair : vMaterials) + entries.push_back(pair.first.c_str()); + + return FVDropdown(label, var, entries, flags, colors); + } + + // convar wrappers + bool bOldDisabled, bOldTransparent; + + template + __inline std::string GetCondition(ConfigVar& var, bool bForce = false) + { + if (var.m_iFlags & (NOSAVE | NOCOND)) + return "default"; + + if (bForce) + return sCondition; + + std::string parent = sCondition; + while (true) + { + if (FNV1A::Hash(parent.c_str()) == FNV1A::HashConst("default") || var.Map.contains(parent)) + break; + parent = F::Conditions.GetParent(parent); + } + return parent; + } + + template + __inline T GetParentValue(ConfigVar& var, std::string sCond) // oh my god + { + std::string parent = sCond; + while (true) + { + parent = F::Conditions.GetParent(parent); + if (FNV1A::Hash(parent.c_str()) == FNV1A::HashConst("default") || var.Map.contains(parent)) + break; + } + return var.Map[parent]; + } + + template + __inline T FGet(ConfigVar& var, const bool bDisable = false) + { + bOldDisabled = bDisabled, bOldTransparent = bTransparent; + + const auto condition = GetCondition(var); + if (bDisable) + { + if (FNV1A::Hash(sCondition.c_str()) == FNV1A::HashConst("default")) + { + if (Vars::Menu::MenuShowsBinds.Value && var.Map["default"] != var.Value) + { + for (auto& [sCond, tVal] : var.Map) + { + if (FNV1A::Hash(sCond.c_str()) == FNV1A::HashConst("default")) + continue; + + if (tVal == var.Value) + { + bDisabled = true; + return tVal; + } + } + } + } + else + bTransparent = sCondition != condition && !(var.m_iFlags & (NOSAVE | NOCOND)); + } + return var.Map[condition]; + } + + template + __inline void FSet(ConfigVar& var, T val) + { + if (!bDisabled) + { + const auto condition = GetCondition(var, true); + const auto value = GetParentValue(var, condition); + + if (value != val) + var.Map[condition] = val; + else if (FNV1A::Hash(condition.c_str()) != FNV1A::HashConst("default")) + { + for (auto it = var.Map.begin(); it != var.Map.end();) + { + if (it->first == condition) + it = var.Map.erase(it); + else + ++it; + } + } + } + + bDisabled = bOldDisabled, bTransparent = bOldTransparent; + } + + __inline bool FToggle(const char* label, ConfigVar& var, int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FToggle(label, &val, flags); + FSet(var, val); + return bReturn; + } + __inline bool FSlider(const char* label, ConfigVar& var, float v_min, float v_max, float step = 1.f, const char* fmt = "%.0f", int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FSlider(label, &val.Min, &val.Max, v_min, v_max, step, fmt, flags); + FSet(var, val); + return bReturn; + } + __inline bool FSlider(const char* label, ConfigVar& var, int v_min, int v_max, int step = 1, const char* fmt = "%d", int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FSlider(label, &val.Min, &val.Max, v_min, v_max, step, fmt, flags); + FSet(var, val); + return bReturn; + } + __inline bool FSlider(const char* label, ConfigVar& var, float v_min, float v_max, float step = 1.f, const char* fmt = "%.0f", int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FSlider(label, &val, v_min, v_max, step, fmt, flags); + FSet(var, val); + return bReturn; + } + __inline bool FSlider(const char* label, ConfigVar& var, int v_min, int v_max, int step = 1, const char* fmt = "%d", int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FSlider(label, &val, v_min, v_max, step, fmt, flags); + FSet(var, val); + return bReturn; + } + __inline bool FDropdown(const char* label, ConfigVar& var, std::vector titles, std::vector values = {}, int flags = 0, int colors = 0) + { + auto val = FGet(var, true); + const bool bReturn = FDropdown(label, &val, titles, values, flags, colors); + FSet(var, val); + return bReturn; + } + __inline bool FSDropdown(const char* label, ConfigVar& var, std::vector entries = {}, int flags = 0, int colors = 0) + { + auto val = FGet(var, true); + const bool bReturn = FSDropdown(label, &val, entries, flags, colors); + FSet(var, val); + return bReturn; + } + __inline bool FVDropdown(const char* label, ConfigVar>& var, std::vector titles, int flags = 0, int colors = 0) + { + auto val = FGet(var, true); + const bool bReturn = FVDropdown(label, &val, titles, flags, colors); + FSet(var, val); + return bReturn; + } + __inline bool FMDropdown(const char* label, ConfigVar>& var, int flags = 0, int colors = 0) + { + auto val = FGet(var, true); + const bool bReturn = FMDropdown(label, &val, flags, colors); + FSet(var, val); + return bReturn; + } + __inline bool FColorPicker(const char* label, ConfigVar& var, int offset = 0, int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FColorPicker(label, &val, offset, flags); + FSet(var, val); + return bReturn; + } + __inline bool FColorPicker(const char* label, ConfigVar& var, bool start = true, int offset = 0, int flags = 0) + { + auto val = FGet(var, true); + const bool bReturn = FColorPicker(label, start ? &val.StartColor : &val.EndColor, offset, flags); + FSet(var, val); + return bReturn; + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/Menu/Menu.cpp b/Amalgam/src/Features/ImGui/Menu/Menu.cpp new file mode 100644 index 0000000..96d8559 --- /dev/null +++ b/Amalgam/src/Features/ImGui/Menu/Menu.cpp @@ -0,0 +1,2312 @@ +#include "Menu.h" + +#include "Components.h" +#include "../../Configs/Configs.h" +#include "../../Conditions/Conditions.h" +#include "../../Players/PlayerUtils.h" +#include "../../CameraWindow/CameraWindow.h" +#include "../../Backtrack/Backtrack.h" +#include "../../Visuals/Visuals.h" +#include "../../Resolver/Resolver.h" +#include + +/* The main menu */ +void CMenu::DrawMenu() +{ + using namespace ImGui; + + ImVec2 mainWindowPos = {}; + ImVec2 mainWindowSize = {}; + + SetNextWindowSize(ImVec2(750, 500), ImGuiCond_FirstUseEver); + PushStyleVar(ImGuiStyleVar_WindowMinSize, { 750, 500 }); + if (Begin("MainWindow", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar)) + { + const auto windowPos = mainWindowPos = GetWindowPos(); + const auto windowSize = mainWindowSize = GetWindowSize(); + + // Main tabs + FTabs({ "AIMBOT", "VISUALS", "MISC", "LOGS", "SETTINGS" }, &CurrentTab, TabSize, { 0, SubTabSize.y }, true, { ICON_MD_GROUP, ICON_MD_IMAGE, ICON_MD_PUBLIC, ICON_MD_MENU_BOOK, ICON_MD_SETTINGS }); + + // Sub tabs + switch (CurrentTab) + { + case 0: FTabs({ "GENERAL", "HVH" }, &CurrentAimbotTab, SubTabSize, { TabSize.x, 0 }); break; + case 1: FTabs({ "ESP", "CHAMS", "GLOW", "MISC##", "RADAR", "MENU" }, &CurrentVisualsTab, SubTabSize, { TabSize.x, 0 }); break; + case 2: FTabs({ "MISC##" }, nullptr, SubTabSize, { TabSize.x, 0 }); break; + case 3: FTabs({ "LOGS##", "SETTINGS##" }, &CurrentLogsTab, SubTabSize, { TabSize.x, 0 }); break; + case 4: FTabs({ "CONFIG", "CONDITIONS", "PLAYERLIST", "MATERIALS" }, &CurrentConfigTab, SubTabSize, { TabSize.x, 0 }); break; + } + + // Main content + SetCursorPos({ TabSize.x, SubTabSize.y }); + PushStyleVar(ImGuiStyleVar_WindowPadding, { 8.f, 8.f }); + PushStyleColor(ImGuiCol_ChildBg, {}); + if (BeginChild("Content", { windowSize.x - TabSize.x, windowSize.y - SubTabSize.y }, false, ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + PushStyleColor(ImGuiCol_ChildBg, F::Render.Foreground.Value); + PushStyleVar(ImGuiStyleVar_ChildRounding, 3.f); + + switch (CurrentTab) + { + case 0: MenuAimbot(); break; + case 1: MenuVisuals(); break; + case 2: MenuMisc(); break; + case 3: MenuLogs(); break; + case 4: MenuSettings(); break; + } + + PopStyleVar(); + PopStyleColor(); + } EndChild(); + PopStyleColor(); + PopStyleVar(); + + // End + End(); + } + PopStyleVar(); + + // Title Text + if (Vars::Menu::CheatName.Value.length()) + { + PushFont(F::Render.FontTitle); + const auto textSize = CalcTextSize(Vars::Menu::CheatName.Value.c_str()); + SetNextWindowSize({ std::min(textSize.x + 26.f, mainWindowSize.x), 40.f }); + SetNextWindowPos({ mainWindowPos.x, mainWindowPos.y - 48.f }); + PushStyleVar(ImGuiStyleVar_WindowMinSize, { 40.f, 40.f }); + if (Begin("TitleWindow", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) + { + const auto windowPos = GetWindowPos(); + GetWindowDrawList()->AddText(F::Render.FontTitle, F::Render.FontTitle->FontSize, { windowPos.x + 13.f, windowPos.y + 10.f }, F::Render.Accent, Vars::Menu::CheatName.Value.c_str()); + + End(); + } + PopStyleVar(); + PopFont(); + } + + // Condition Text + if (FNV1A::Hash(sCondition.c_str()) != FNV1A::HashConst("default")) + { + const auto textSize = CalcTextSize(std::format("Editing for condition {}", sCondition).c_str()); + SetNextWindowSize({ std::min(textSize.x + 56.f, mainWindowSize.x), 40.f }); + SetNextWindowPos({ mainWindowPos.x, mainWindowPos.y + mainWindowSize.y + 8.f }); + PushStyleVar(ImGuiStyleVar_WindowMinSize, { 40.f, 40.f }); + if (Begin("ConditionWindow", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar)) + { + const auto windowPos = GetWindowPos(); + const auto preSize = CalcTextSize("Editing for condition "); + GetWindowDrawList()->AddText(F::Render.FontRegular, F::Render.FontRegular->FontSize, { windowPos.x + 16.f, windowPos.y + 13.f }, F::Render.Active, "Editing for condition "); + GetWindowDrawList()->AddText(F::Render.FontRegular, F::Render.FontRegular->FontSize, { windowPos.x + 16.f + preSize.x, windowPos.y + 13.f }, F::Render.Accent, sCondition.c_str()); + + SetCursorPos({ textSize.x + 28, 11 }); + if (IconButton(ICON_MD_CANCEL)) + sCondition = "default"; + + End(); + } + PopStyleVar(); + } +} + +#pragma region Tabs +/* Tab: Aimbot */ +void CMenu::MenuAimbot() +{ + using namespace ImGui; + + switch (CurrentAimbotTab) + { + // General + case 0: + if (BeginTable("AimbotTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("General")) + { + FDropdown("Aim type", Vars::Aimbot::General::AimType, { "Off", "Plain", "Smooth", "Silent" }, {}, FDropdown_Left); + FDropdown("Target selection", Vars::Aimbot::General::TargetSelection, { "FOV", "Distance" }, {}, FDropdown_Right); + FDropdown("Target", Vars::Aimbot::General::Target, { "Players", "Sentries", "Dispensers", "Teleporters", "Stickies", "NPCs", "Bombs" }, {}, FDropdown_Multi | FDropdown_Left); + FDropdown("Ignore", Vars::Aimbot::General::Ignore, { "Invulnerable", "Cloaked", "Dead Ringer", "Vaccinator", "Unsimulated Players", "Disguised", "Taunting" }, {}, FDropdown_Multi | FDropdown_Right); + FSlider("Aim FOV", Vars::Aimbot::General::AimFOV, 1.f, 180.f, 1.f, "%.0f", FSlider_Clamp); + bTransparent = FGet(Vars::Aimbot::General::AimType) != 2; + FSlider("Smoothing## Hitscan", Vars::Aimbot::General::Smoothing, 0.f, 100.f, 1.f, "%.0f%%", FSlider_Clamp); + bTransparent = false; + FSlider("Max targets", Vars::Aimbot::General::MaxTargets, 1, 6, 1, "%d", FSlider_Clamp); + bTransparent = !(FGet(Vars::Aimbot::General::Ignore) & 1 << 1); + FSlider("Ignore cloak", Vars::Aimbot::General::IgnoreCloakPercentage, 0, 100, 10, "%d%%", FSlider_Clamp); + bTransparent = !(FGet(Vars::Aimbot::General::Ignore) & 1 << 4); + FSlider("Tick tolerance", Vars::Aimbot::General::TickTolerance, 0, 21, 1, "%d", FSlider_Clamp); + bTransparent = false; + FColorPicker("Aimbot FOV circle", Vars::Colors::FOVCircle); + FToggle("Autoshoot", Vars::Aimbot::General::AutoShoot); + FToggle("FOV Circle", Vars::Aimbot::General::FOVCircle, FToggle_Middle); + FToggle("Force crits", Vars::CritHack::ForceCrits); + FToggle("Avoid random crits", Vars::CritHack::AvoidRandom, FToggle_Middle); + FToggle("Always melee", Vars::CritHack::AlwaysMelee); + FToggle("No spread", Vars::Aimbot::General::NoSpread, FToggle_Middle); + } EndSection(); + if (Section("Backtrack")) + { + FToggle("Enabled", Vars::Backtrack::Enabled); + FToggle("Prefer on shot", Vars::Backtrack::PreferOnShot, FToggle_Middle); + FSlider("Fake latency", Vars::Backtrack::Latency, 0, F::Backtrack.flMaxUnlag * 1000, 5, "%d", FSlider_Clamp); // unreliable above 900 + FSlider("Fake interp", Vars::Backtrack::Interp, 0, F::Backtrack.flMaxUnlag * 1000, 5, "%d", FSlider_Clamp); + FSlider("Window", Vars::Backtrack::Window, 1, 200, 5, "%d", FSlider_Clamp); + } EndSection(); + if (Vars::Debug::Info.Value) + { + if (Section("debug## backtrack")) + { + FSlider("offset", Vars::Backtrack::Offset, -5, 5); + } EndSection(); + } + + /* Column 2 */ + TableNextColumn(); + if (Section("Hitscan")) + { + FDropdown("Hitboxes", Vars::Aimbot::Hitscan::Hitboxes, { "Head", "Body", "Pelvis", "Arms", "Legs" }, { 1 << 0, 1 << 2, 1 << 1, 1 << 3, 1 << 4 }, FDropdown_Multi); + FDropdown("Modifiers## Hitscan", Vars::Aimbot::Hitscan::Modifiers, { "Tapfire", "Wait for heatshot", "Wait for charge", "Scoped only", "Auto scope", "Bodyaim if lethal", "Extinguish team" }, {}, FDropdown_Multi); + FSlider("Point scale", Vars::Aimbot::Hitscan::PointScale, 0.f, 100.f, 5.f, "%.0f%%", FSlider_Clamp | FSlider_Precision); + bTransparent = !(FGet(Vars::Aimbot::Hitscan::Modifiers) & 1 << 0); + FSlider("Tapfire distance", Vars::Aimbot::Hitscan::TapFireDist, 250.f, 1000.f, 50.f, "%.0f", FSlider_Clamp | FSlider_Precision); + bTransparent = false; + } EndSection(); + if (Section("Projectile")) + { + FDropdown("Predict", Vars::Aimbot::Projectile::StrafePrediction, { "Air strafing", "Ground strafing" }, {}, FDropdown_Multi | FDropdown_Left); + FDropdown("Splash", Vars::Aimbot::Projectile::SplashPrediction, { "Off", "Include", "Prefer", "Only" }, {}, FDropdown_Right); + FDropdown("Auto detonate", Vars::Aimbot::Projectile::AutoDetonate, { "Stickies", "Flares" }, {}, FDropdown_Multi | FDropdown_Left); + FDropdown("Auto airblast", Vars::Aimbot::Projectile::AutoAirblast, { "Off", "Legit", "Rage" }, {}, FDropdown_Right); + FDropdown("Modifiers## Projectile", Vars::Aimbot::Projectile::Modifiers, { "Charge shot", "Cancel charge", "Bodyaim if lethal" }, {}, FDropdown_Multi); + FSlider("Max simulation time", Vars::Aimbot::Projectile::PredictionTime, 0.1f, 10.f, 0.1f, "%.1fs"); + bTransparent = !FGet(Vars::Aimbot::Projectile::StrafePrediction); + FSlider("Hit chance", Vars::Aimbot::Projectile::Hitchance, 0.f, 100.f, 5.f, "%.0f%%", FSlider_Clamp | FSlider_Precision); + bTransparent = false; + FSlider("Autodet radius", Vars::Aimbot::Projectile::AutodetRadius, 0.f, 100.f, 5.f, "%.0f%%", FSlider_Clamp | FSlider_Precision); + FSlider("Splash radius", Vars::Aimbot::Projectile::SplashRadius, 0.f, 100.f, 5.f, "%.0f%%", FSlider_Clamp | FSlider_Precision); + bTransparent = !FGet(Vars::Aimbot::Projectile::AutoRelease); + FSlider("Auto release", Vars::Aimbot::Projectile::AutoRelease, 0.f, 100.f, 5.f, "%.0f%%", FSlider_Clamp | FSlider_Precision); + bTransparent = false; + } EndSection(); + if (Vars::Debug::Info.Value) + { + if (Section("debug## projectile")) + { + FSlider("ground samples", Vars::Aimbot::Projectile::iGroundSamples, 3, 66, 1, "%d", FSlider_Left); + FSlider("air samples", Vars::Aimbot::Projectile::iAirSamples, 3, 66, 1, "%d", FSlider_Right); + FSlider("vert shift", Vars::Aimbot::Projectile::VerticalShift, 0.f, 20.f, 0.5f, "%.1f", FSlider_Left); + FSlider("hunterman lerp", Vars::Aimbot::Projectile::HuntermanLerp, 0.f, 100.f, 1.f, "%.0f%%", FSlider_Right); + FSlider("latency offset", Vars::Aimbot::Projectile::LatOff, -1.f, 1.f, 0.1f, "%.1f", FSlider_Left); + FSlider("hull inc", Vars::Aimbot::Projectile::HullInc, 0.f, 3.f, 0.5f, "%.1f", FSlider_Right); + FSlider("drag override", Vars::Aimbot::Projectile::DragOverride, 0.f, 1.f, 0.001f, "%.3f", FSlider_Left); + FSlider("time override", Vars::Aimbot::Projectile::TimeOverride, 0.f, 1.f, 0.001f, "%.3f", FSlider_Right); + FSlider("splash points", Vars::Aimbot::Projectile::SplashPoints, 0, 100, 1, "%d", FSlider_Left); + FSlider("splash count", Vars::Aimbot::Projectile::SplashCount, 1, 5, 1, "%d", FSlider_Right); + } EndSection(); + } + if (Section("Melee")) + { + FToggle("Auto backstab", Vars::Aimbot::Melee::AutoBackstab); + FToggle("Ignore razorback", Vars::Aimbot::Melee::IgnoreRazorback, FToggle_Middle); + FToggle("Swing prediction", Vars::Aimbot::Melee::SwingPrediction); + FToggle("Whip teammates", Vars::Aimbot::Melee::WhipTeam, FToggle_Middle); + } EndSection(); + if (Vars::Debug::Info.Value) + { + if (Section("debug## melee")) + FSlider("swing ticks", Vars::Aimbot::Melee::SwingTicks, 10, 14); + EndSection(); + } + + EndTable(); + } + break; + // HvH + case 1: + if (BeginTable("HvHTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Doubletap")) + { + FToggle("Doubletap", Vars::CL_Move::Doubletap::Doubletap); + FToggle("Warp", Vars::CL_Move::Doubletap::Warp, FToggle_Middle); + FToggle("Recharge ticks", Vars::CL_Move::Doubletap::RechargeTicks); + FToggle("Anti-warp", Vars::CL_Move::Doubletap::AntiWarp, FToggle_Middle); + FSlider("Tick limit", Vars::CL_Move::Doubletap::TickLimit, 2, 22, 1, "%d", FSlider_Clamp); + FSlider("Warp rate", Vars::CL_Move::Doubletap::WarpRate, 2, 22, 1, "%d", FSlider_Clamp); + FSlider("Passive recharge", Vars::CL_Move::Doubletap::PassiveRecharge, 0, 66, 1, "%d", FSlider_Clamp); + } EndSection(); + if (Section("Fakelag")) + { + FDropdown("Fakelag", Vars::CL_Move::Fakelag::Fakelag, { "Off", "Plain", "Random", "Adaptive" }, {}, FSlider_Left); + FDropdown("Options", Vars::CL_Move::Fakelag::Options, { "Only moving", "On unduck", "Not airborne" }, {}, FDropdown_Multi | FSlider_Right); + bTransparent = FGet(Vars::CL_Move::Fakelag::Fakelag) != 1; + FSlider("Plain ticks", Vars::CL_Move::Fakelag::PlainTicks, 1, 22, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = FGet(Vars::CL_Move::Fakelag::Fakelag) != 2; + FSlider("Random ticks", Vars::CL_Move::Fakelag::RandomTicks, 1, 22, 1, "%d - %d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + FToggle("Unchoke on attack", Vars::CL_Move::Fakelag::UnchokeOnAttack); + FToggle("Retain blastjump", Vars::CL_Move::Fakelag::RetainBlastJump, FToggle_Middle); + } EndSection(); + if (Section("Anti Aim")) + { + FToggle("Enabled", Vars::AntiHack::AntiAim::Enabled); + FDropdown("Real pitch", Vars::AntiHack::AntiAim::PitchReal, { "None", "Up", "Down", "Zero" }, {}, FDropdown_Left); + FDropdown("Fake pitch", Vars::AntiHack::AntiAim::PitchFake, { "None", "Up", "Down" }, {}, FDropdown_Right); + FDropdown("Real yaw", Vars::AntiHack::AntiAim::YawReal, { "Forward", "Left", "Right", "Backwards", "Spin", "Edge" }, {}, FDropdown_Left); + FDropdown("Fake yaw", Vars::AntiHack::AntiAim::YawFake, { "Forward", "Left", "Right", "Backwards", "Spin", "Edge" }, {}, FDropdown_Right); + FDropdown("Real offset", Vars::AntiHack::AntiAim::RealYawMode, { "View", "Target" }, {}, FDropdown_Left); + FDropdown("Fake offset", Vars::AntiHack::AntiAim::FakeYawMode, { "View", "Target" }, {}, FDropdown_Right); + FSlider("Real offset## Offset", Vars::AntiHack::AntiAim::RealYawOffset, -180, 180, 5, "%d", FSlider_Left | FSlider_Clamp | FSlider_Precision); + FSlider("Fake offset## Offset", Vars::AntiHack::AntiAim::FakeYawOffset, -180, 180, 5, "%d", FSlider_Right | FSlider_Clamp | FSlider_Precision); + bTransparent = FGet(Vars::AntiHack::AntiAim::YawFake) != 4 && FGet(Vars::AntiHack::AntiAim::YawReal) != 4; + FSlider("Spin Speed", Vars::AntiHack::AntiAim::SpinSpeed, -30.f, 30.f, 1.f, "%.0f", FSlider_Left); + bTransparent = false; + SetCursorPos({ GetWindowSize().x / 2 + 4, GetCursorPosY() - 24 }); + FToggle("Minwalk", Vars::AntiHack::AntiAim::MinWalk); + FToggle("Anti-overlap", Vars::AntiHack::AntiAim::AntiOverlap); + FToggle("Hide pitch on shot", Vars::AntiHack::AntiAim::InvalidShootPitch, FToggle_Middle); + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Resolver")) + { + FToggle("Enabled", Vars::AntiHack::Resolver::Resolver); + bTransparent = !FGet(Vars::AntiHack::Resolver::Resolver); + FToggle("Ignore in-air", Vars::AntiHack::Resolver::IgnoreAirborne, FToggle_Middle); + bTransparent = false; + } EndSection(); + if (Section("Auto Peek")) + { + FToggle("Auto peek", Vars::CL_Move::AutoPeek); + } EndSection(); + if (Section("Speedhack")) + { + FToggle("Speedhack", Vars::CL_Move::SpeedEnabled); + bTransparent = !FGet(Vars::CL_Move::SpeedEnabled); + FSlider("SpeedHack factor", Vars::CL_Move::SpeedFactor, 1, 50, 1); + bTransparent = false; + } EndSection(); + if (Section("Cheater Detection")) + { + const bool transparent = bTransparent = !FGet(Vars::CheaterDetection::Methods); + FDropdown("Detection methods", Vars::CheaterDetection::Methods, { "Invalid pitch", "Packet choking", "Aim flicking", "Duck Speed" }, {}, FDropdown_Multi); + FSlider("Detections required", Vars::CheaterDetection::DetectionsRequired, 10, 50, 1); + + bTransparent = !(FGet(Vars::CheaterDetection::Methods) & 1 << 1) || bTransparent; + FSlider("Minimum choking", Vars::CheaterDetection::MinimumChoking, 4, 22, 1); + bTransparent = transparent; + + bTransparent = !(FGet(Vars::CheaterDetection::Methods) & 1 << 2) || bTransparent; + FSlider("Minimum flick angle", Vars::CheaterDetection::MinimumFlick, 10.f, 30.f, 1.f, "%.0f", FSlider_Left); + FSlider("Maximum noise", Vars::CheaterDetection::MaximumNoise, 1.f, 10.f, 1.f, "%.0f", FSlider_Right); + bTransparent = false; + } EndSection(); + + EndTable(); + } + break; + } +} + +/* Tab: Visuals */ +void CMenu::MenuVisuals() +{ + using namespace ImGui; + + switch (CurrentVisualsTab) + { + // ESP + case 0: + if (BeginTable("VisualsESPTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("ESP")) + { + FDropdown("Draw", Vars::ESP::Draw, { "Enemy", "Team", "Friends", "Local", "NPCs", "Health", "Ammo", "Money", "Bombs", "Spellbook", "Gargoyle" }, {}, FDropdown_Multi); + FDropdown("Player", Vars::ESP::Player, { "Name", "Health bar", "Health text", "Uber bar", "Uber text", "Class icon", "Class text", "Weapon icon", "Weapon text", "Distance", "Box", "Bones", "Priority", "Labels", "Buffs", "Debuffs", "Misc", "Lag compensation", "Ping", "KDR" }, {}, FDropdown_Multi); + FDropdown("Building", Vars::ESP::Building, { "Name", "Health bar", "Health text", "Distance", "Box", "Owner", "Level", "Conditions" }, {}, FDropdown_Multi); + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Colors")) + { + FToggle("Relative colors", Vars::Colors::Relative); + if (FGet(Vars::Colors::Relative)) + { + FColorPicker("Enemy color", Vars::Colors::Enemy, 0, FColorPicker_Left); + FColorPicker("Team color", Vars::Colors::Team, 0, FColorPicker_Middle | FColorPicker_SameLine); + } + else + { + FColorPicker("RED color", Vars::Colors::TeamRed, 0, FColorPicker_Left); + FColorPicker("BLU color", Vars::Colors::TeamBlu, 0, FColorPicker_Middle | FColorPicker_SameLine); + } + + FColorPicker("Health bar top", Vars::Colors::HealthBar, false, 0, FColorPicker_Left); + FColorPicker("Health bar bottom", Vars::Colors::HealthBar, true, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("Uber bar", Vars::Colors::UberBar, 0, FColorPicker_Left); + FColorPicker("Invulnerable color", Vars::Colors::Invulnerable, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("Overheal color", Vars::Colors::Overheal, 0, FColorPicker_Left); + FColorPicker("Cloaked color", Vars::Colors::Cloak, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("Local color", Vars::Colors::Local, 0, FColorPicker_Left); + FColorPicker("Target color", Vars::Colors::Target, 0, FColorPicker_Middle | FColorPicker_SameLine); + + FColorPicker("Healthpack color", Vars::Colors::Health, 0, FColorPicker_Left); + FColorPicker("Ammopack color", Vars::Colors::Ammo, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("NPC color", Vars::Colors::NPC, 0, FColorPicker_Left); + FColorPicker("Bomb color", Vars::Colors::Bomb, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("Money color", Vars::Colors::Money, 0, FColorPicker_Left); + FColorPicker("Halloween color", Vars::Colors::Halloween, 0, FColorPicker_Middle | FColorPicker_SameLine); + + FSlider("Active alpha", Vars::ESP::ActiveAlpha, 0, 255, 5, "%d", FSlider_Clamp); + FSlider("Dormant alpha", Vars::ESP::DormantAlpha, 0, 255, 5, "%d", FSlider_Clamp); + FSlider("Dormant Decay Time", Vars::ESP::DormantTime, 0.015f, 5.0f, 0.1f, "%.1f", FSlider_Left | FSlider_Clamp); + FToggle("Dormant priority only", Vars::ESP::DormantPriority, FToggle_Middle); Dummy({ 0, 8 }); + } EndSection(); + + EndTable(); + } + break; + // Chams + case 1: + if (BeginTable("VisualsChamsTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Friendly")) + { + FToggle("Players", Vars::Chams::Friendly::Players); + FToggle("Ragdolls", Vars::Chams::Friendly::Ragdolls, FToggle_Middle); + FToggle("Buildings", Vars::Chams::Friendly::Buildings); + FToggle("Projectiles", Vars::Chams::Friendly::Projectiles, FToggle_Middle); + + FMDropdown("Visible material", Vars::Chams::Friendly::VisibleMaterial, FDropdown_Left, 1); + FColorPicker("Visible color", Vars::Chams::Friendly::VisibleColor, 0, FColorPicker_Dropdown); + FMDropdown("Occluded material", Vars::Chams::Friendly::OccludedMaterial, FDropdown_Right, 1); + FColorPicker("Occluded color", Vars::Chams::Friendly::OccludedColor, 0, FColorPicker_Dropdown); + } EndSection(); + if (Section("Enemy")) + { + FToggle("Players", Vars::Chams::Enemy::Players); + FToggle("Ragdolls", Vars::Chams::Enemy::Ragdolls, FToggle_Middle); + FToggle("Buildings", Vars::Chams::Enemy::Buildings); + FToggle("Projectiles", Vars::Chams::Enemy::Projectiles, FToggle_Middle); + + FMDropdown("Visible material", Vars::Chams::Enemy::VisibleMaterial, FDropdown_Left, 1); + FColorPicker("Visible color", Vars::Chams::Enemy::VisibleColor, 0, FColorPicker_Dropdown); + FMDropdown("Occluded material", Vars::Chams::Enemy::OccludedMaterial, FDropdown_Right, 1); + FColorPicker("Occluded color", Vars::Chams::Enemy::OccludedColor, 0, FColorPicker_Dropdown); + } EndSection(); + if (Section("World")) + { + FToggle("NPCs", Vars::Chams::World::NPCs); + FToggle("Pickups", Vars::Chams::World::Pickups, FToggle_Middle); + FToggle("Bombs", Vars::Chams::World::Bombs); + FToggle("Halloween", Vars::Chams::World::Halloween, FToggle_Middle); + + FMDropdown("Visible material", Vars::Chams::World::VisibleMaterial, FDropdown_Left, 1); + FColorPicker("Visible color", Vars::Chams::World::VisibleColor, 0, FColorPicker_Dropdown); + FMDropdown("Occluded material", Vars::Chams::World::OccludedMaterial, FDropdown_Right, 1); + FColorPicker("Occluded color", Vars::Chams::World::OccludedColor, 0, FColorPicker_Dropdown); + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Player")) + { + FToggle("Local", Vars::Chams::Player::Local); + FToggle("Friend", Vars::Chams::Player::Friend, FToggle_Middle); + + FMDropdown("Visible material", Vars::Chams::Player::VisibleMaterial, FDropdown_Left, 1); + FColorPicker("Visible color", Vars::Chams::Player::VisibleColor, 0, FColorPicker_Dropdown); + FMDropdown("Occluded material", Vars::Chams::Player::OccludedMaterial, FDropdown_Right, 1); + FColorPicker("Occluded color", Vars::Chams::Player::OccludedColor, 0, FColorPicker_Dropdown); + } EndSection(); + if (Section("Backtrack")) + { + FToggle("Enabled", Vars::Chams::Backtrack::Enabled); + SameLine(GetWindowSize().x / 2 + 4); SetCursorPosY(GetCursorPosY() - 24); + FDropdown("Draw", Vars::Chams::Backtrack::Draw, { "Last", "Last + first", "All" }, {}, FDropdown_Left); + + FMDropdown("Material", Vars::Chams::Backtrack::VisibleMaterial, FDropdown_None, 1); + FColorPicker("Color", Vars::Chams::Backtrack::VisibleColor, 0, FColorPicker_Dropdown); + } EndSection(); + if (Section("Fake Angle")) + { + FToggle("Enabled", Vars::Chams::FakeAngle::Enabled); + + FMDropdown("Material", Vars::Chams::FakeAngle::VisibleMaterial, FDropdown_None, 1); + FColorPicker("Color", Vars::Chams::FakeAngle::VisibleColor, 0, FColorPicker_Dropdown); + } EndSection(); + if (Section("Viewmodel")) + { + FToggle("Weapon", Vars::Chams::Viewmodel::Weapon); + FToggle("Hands", Vars::Chams::Viewmodel::Hands, FToggle_Middle); + + FMDropdown("Material", Vars::Chams::Viewmodel::VisibleMaterial, FDropdown_None, 1); + FColorPicker("Color", Vars::Chams::Viewmodel::VisibleColor, 0, FColorPicker_Dropdown); + } EndSection(); + + EndTable(); + } + break; + // Glow + case 2: + if (BeginTable("VisualsGlowTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Friendly")) + { + FToggle("Players", Vars::Glow::Friendly::Players); + FToggle("Ragdolls", Vars::Glow::Friendly::Ragdolls, FToggle_Middle); + FToggle("Buildings", Vars::Glow::Friendly::Buildings); + FToggle("Projectiles", Vars::Glow::Friendly::Projectiles, FToggle_Middle); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::Friendly::Stencil); + FToggle("Blur", Vars::Glow::Friendly::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::Friendly::Stencil); + FSlider("Stencil scale## Friendly", Vars::Glow::Friendly::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::Friendly::Blur); + FSlider("Blur scale## Friendly", Vars::Glow::Friendly::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + if (Section("Enemy")) + { + FToggle("Players", Vars::Glow::Enemy::Players); + FToggle("Ragdolls", Vars::Glow::Enemy::Ragdolls, FToggle_Middle); + FToggle("Buildings", Vars::Glow::Enemy::Buildings); + FToggle("Projectiles", Vars::Glow::Enemy::Projectiles, FToggle_Middle); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::Enemy::Stencil); + FToggle("Blur", Vars::Glow::Enemy::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::Enemy::Stencil); + FSlider("Stencil scale## Enemy", Vars::Glow::Enemy::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::Enemy::Blur); + FSlider("Blur scale## Enemy", Vars::Glow::Enemy::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + if (Section("World")) + { + FToggle("NPCs", Vars::Glow::World::NPCs); + FToggle("Pickups", Vars::Glow::World::Pickups, FToggle_Middle); + FToggle("Bombs", Vars::Glow::World::Bombs); + FToggle("Halloween", Vars::Glow::World::Halloween, FToggle_Middle); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::World::Stencil); + FToggle("Blur", Vars::Glow::World::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::World::Stencil); + FSlider("Stencil scale## World", Vars::Glow::World::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::World::Blur); + FSlider("Blur scale## World", Vars::Glow::World::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Player")) + { + FToggle("Local", Vars::Glow::Player::Local); + FToggle("Friend", Vars::Glow::Player::Friend, FToggle_Middle); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::Player::Stencil); + FToggle("Blur", Vars::Glow::Player::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::Player::Stencil); + FSlider("Stencil scale## Player", Vars::Glow::Player::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::Player::Blur); + FSlider("Blur scale## Player", Vars::Glow::Player::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + if (Section("Backtrack")) + { + FToggle("Enabled", Vars::Glow::Backtrack::Enabled); + SameLine(GetWindowSize().x / 2 + 4); SetCursorPosY(GetCursorPosY() - 24); + FDropdown("Draw", Vars::Glow::Backtrack::Draw, { "Last", "Last + first", "All" }, {}, FDropdown_Left); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::Backtrack::Stencil); + FToggle("Blur", Vars::Glow::Backtrack::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::Backtrack::Stencil); + FSlider("Stencil scale## Backtrack", Vars::Glow::Backtrack::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::Backtrack::Blur); + FSlider("Blur scale## Backtrack", Vars::Glow::Backtrack::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + if (Section("Fake Angle")) + { + FToggle("Enabled", Vars::Glow::FakeAngle::Enabled); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::FakeAngle::Stencil); + FToggle("Blur", Vars::Glow::FakeAngle::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::FakeAngle::Stencil); + FSlider("Stencil scale## FakeAngle", Vars::Glow::FakeAngle::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::FakeAngle::Blur); + FSlider("Blur scale## FakeAngle", Vars::Glow::FakeAngle::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + if (Section("Viewmodel")) + { + FToggle("Weapon", Vars::Glow::Viewmodel::Weapon); + FToggle("Hands", Vars::Glow::Viewmodel::Hands, FToggle_Middle); + Dummy({ 0, 8 }); + + FToggle("Stencil", Vars::Glow::Viewmodel::Stencil); + FToggle("Blur", Vars::Glow::Viewmodel::Blur, FToggle_Middle); + bTransparent = !FGet(Vars::Glow::Viewmodel::Stencil); + FSlider("Stencil scale## Viewmodel", Vars::Glow::Viewmodel::StencilScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Left); + bTransparent = !FGet(Vars::Glow::Viewmodel::Blur); + FSlider("Blur scale## Viewmodel", Vars::Glow::Viewmodel::BlurScale, 1, 10, 1, "%d", FSlider_Clamp | FSlider_Right); + bTransparent = false; + } EndSection(); + + EndTable(); + } + break; + // Misc + case 3: + if (BeginTable("VisualsMiscTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Removals")) + { + FToggle("Scope", Vars::Visuals::Removals::Scope); + FToggle("Interpolation", Vars::Visuals::Removals::Interpolation, FToggle_Middle); + FToggle("Disguises", Vars::Visuals::Removals::Disguises); + FToggle("Screen overlays", Vars::Visuals::Removals::ScreenOverlays, FToggle_Middle); + FToggle("Taunts", Vars::Visuals::Removals::Taunts); + FToggle("Screen effects", Vars::Visuals::Removals::ScreenEffects, FToggle_Middle); + FToggle("View punch", Vars::Visuals::Removals::ViewPunch); + FToggle("Angle forcing", Vars::Visuals::Removals::AngleForcing, FToggle_Middle); + FToggle("MOTD", Vars::Visuals::Removals::MOTD); + FToggle("Convar queries", Vars::Visuals::Removals::ConvarQueries, FToggle_Middle); + FToggle("Post processing", Vars::Visuals::Removals::PostProcessing); + FToggle("DSP", Vars::Visuals::Removals::DSP, FToggle_Middle); + } EndSection(); + if (Section("UI")) + { + FSlider("Field of view", Vars::Visuals::UI::FieldOfView, 0, 160, 1, "%d"); + FSlider("Zoomed field of view", Vars::Visuals::UI::ZoomFieldOfView, 0, 160, 1, "%d"); + FToggle("Reveal scoreboard", Vars::Visuals::UI::RevealScoreboard); + FToggle("Scoreboard playerlist", Vars::Visuals::UI::ScoreboardPlayerlist, FToggle_Middle); + FToggle("Scoreboard colors", Vars::Visuals::UI::ScoreboardColors); + FToggle("Clean screenshots", Vars::Visuals::UI::CleanScreenshots, FToggle_Middle); + FToggle("Sniper sightlines", Vars::Visuals::UI::SniperSightlines); + FToggle("Pickup timers", Vars::Visuals::UI::PickupTimers, FToggle_Middle); + } EndSection(); + if (Section("Viewmodel")) + { + FToggle("Crosshair aim position", Vars::Visuals::Viewmodel::CrosshairAim); + FToggle("Viewmodel aim position", Vars::Visuals::Viewmodel::ViewmodelAim, FToggle_Middle); + FSlider("Offset X", Vars::Visuals::Viewmodel::OffsetX, -45, 45, 5, "%d", FSlider_Precision); + FSlider("Offset Y", Vars::Visuals::Viewmodel::OffsetY, -45, 45, 5, "%d", FSlider_Precision); + FSlider("Offset Z", Vars::Visuals::Viewmodel::OffsetZ, -45, 45, 5, "%d", FSlider_Precision); + FSlider("Roll", Vars::Visuals::Viewmodel::Roll, -180, 180, 5, "%d", FSlider_Clamp | FSlider_Precision); + FToggle("Sway", Vars::Visuals::Viewmodel::Sway); + bTransparent = !FGet(Vars::Visuals::Viewmodel::Sway); + FSlider("Sway scale", Vars::Visuals::Viewmodel::SwayScale, 0.01f, 5.f, 0.1f, "%.1f", FSlider_Left); + FSlider("Sway interp", Vars::Visuals::Viewmodel::SwayInterp, 0.01f, 1.f, 0.1f, "%.1f", FSlider_Right); + bTransparent = false; + } EndSection(); + if (Section("Tracers")) + { + FSDropdown("Bullet trail", Vars::Visuals::Tracers::ParticleTracer, { "Off", "Machina", "C.A.P.P.E.R", "Short Circuit", "Merasmus ZAP", "Merasmus ZAP 2", "Big Nasty", "Distortion Trail", "Black Ink", "Line", "Beam" }, FSDropdown_Custom | FDropdown_Left); + FSDropdown("Crit trail", Vars::Visuals::Tracers::ParticleTracerCrits, { "Off", "Machina", "C.A.P.P.E.R", "Short Circuit", "Merasmus ZAP", "Merasmus ZAP 2", "Big Nasty", "Distortion Trail", "Black Ink", "Line", "Beam" }, FSDropdown_Custom | FDropdown_Right); + } EndSection(); + if (Section("Ragdolls")) + { + FToggle("No ragdolls", Vars::Visuals::Ragdolls::NoRagdolls); + FToggle("No gibs", Vars::Visuals::Ragdolls::NoGib, FToggle_Middle); + FToggle("Mods", Vars::Visuals::Ragdolls::Enabled); + bTransparent = !FGet(Vars::Visuals::Ragdolls::Enabled); + FToggle("Enemy only", Vars::Visuals::Ragdolls::EnemyOnly, FToggle_Middle); + FDropdown("Ragdoll effects", Vars::Visuals::Ragdolls::Effects, { "Burning", "Electrocuted", "Ash", "Dissolve" }, {}, FDropdown_Multi | FDropdown_Left); + FDropdown("Ragdoll model", Vars::Visuals::Ragdolls::Type, { "None", "Gold", "Ice" }, {}, FDropdown_Right); + FSlider("Ragdoll force", Vars::Visuals::Ragdolls::Force, -10.f, 10.f, 0.5f, "%.1f", FSlider_Precision); + FSlider("Horizontal force", Vars::Visuals::Ragdolls::ForceHorizontal, -10.f, 10.f, 0.5f, "%.1f", FSlider_Precision); + FSlider("Vertical force", Vars::Visuals::Ragdolls::ForceVertical, -10.f, 10.f, 0.5f, "%.1f", FSlider_Precision); + bTransparent = false; + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Bullet")) + { + FColorPicker("Bullet tracer color", Vars::Colors::BulletTracer); + FToggle("Bullet tracers", Vars::Visuals::Bullet::BulletTracer); + } EndSection(); + if (Section("Simulation")) + { + FColorPicker("Prediction line color", Vars::Colors::PredictionColor, 1); FColorPicker("Projectile line color", Vars::Colors::ProjectileColor); + FToggle("Enabled", Vars::Visuals::Simulation::Enabled); + FToggle("Timed", Vars::Visuals::Simulation::Timed, FToggle_Middle); + FToggle("Seperators", Vars::Visuals::Simulation::Separators); + bTransparent = !FGet(Vars::Visuals::Simulation::Separators); + FSlider("Seperator length", Vars::Visuals::Simulation::SeparatorLength, 2, 16, 1, "%d", FSlider_Left); + FSlider("Seperator spacing", Vars::Visuals::Simulation::SeparatorSpacing, 1, 16, 1, "%d", FSlider_Right); + bTransparent = false; + FColorPicker("Clipped line color", Vars::Colors::ClippedColor); + FToggle("Projectile trajectory", Vars::Visuals::Simulation::ProjectileTrajectory); + FToggle("Projectile camera", Vars::Visuals::Simulation::ProjectileCamera, FToggle_Middle); + FToggle("Trajectory on shot", Vars::Visuals::Simulation::TrajectoryOnShot); + FToggle("Swing prediction lines", Vars::Visuals::Simulation::SwingLines, FToggle_Middle); + } EndSection(); + if (Vars::Debug::Info.Value) + { + if (Section("debug")) + { + FToggle("overwrite", Vars::Visuals::Trajectory::Overwrite); + FSlider("off x", Vars::Visuals::Trajectory::OffX, -25.f, 25.f, 0.5f, "%.1f", FSlider_Precision); + FSlider("off y", Vars::Visuals::Trajectory::OffY, -25.f, 25.f, 0.5f, "%.1f", FSlider_Precision); + FSlider("off z", Vars::Visuals::Trajectory::OffZ, -25.f, 25.f, 0.5f, "%.1f", FSlider_Precision); + FToggle("pipes", Vars::Visuals::Trajectory::Pipes); + FSlider("hull", Vars::Visuals::Trajectory::Hull, 0.f, 10.f, 0.5f, "%.1f", FSlider_Precision); + FSlider("speed", Vars::Visuals::Trajectory::Speed, 0.f, 5000.f, 50.f, "%.0f", FSlider_Precision); + FSlider("gravity", Vars::Visuals::Trajectory::Gravity, 0.f, 2.f, 0.1f, "%.1f", FSlider_Precision); + FToggle("no spin", Vars::Visuals::Trajectory::NoSpin); + FSlider("lifetime", Vars::Visuals::Trajectory::LifeTime, 0.f, 10.f, 0.1f, "%.1f", FSlider_Precision); + FSlider("up vel", Vars::Visuals::Trajectory::UpVelocity, 0.f, 1000.f, 50.f, "%.0f", FSlider_Precision); + FSlider("ang vel x", Vars::Visuals::Trajectory::AngVelocityX, -1000.f, 1000.f, 50.f, "%.0f", FSlider_Precision); + FSlider("ang vel y", Vars::Visuals::Trajectory::AngVelocityY, -1000.f, 1000.f, 50.f, "%.0f", FSlider_Precision); + FSlider("ang vel z", Vars::Visuals::Trajectory::AngVelocityZ, -1000.f, 1000.f, 50.f, "%.0f", FSlider_Precision); + FSlider("drag", Vars::Visuals::Trajectory::Drag, 0.f, 2.f, 0.1f, "%.1f", FSlider_Precision); + FSlider("drag x", Vars::Visuals::Trajectory::DragBasisX, 0.f, 0.1f, 0.01f, "%.2f", FSlider_Precision); + FSlider("drag y", Vars::Visuals::Trajectory::DragBasisY, 0.f, 0.1f, 0.01f, "%.2f", FSlider_Precision); + FSlider("drag z", Vars::Visuals::Trajectory::DragBasisZ, 0.f, 0.1f, 0.01f, "%.2f", FSlider_Precision); + FSlider("ang drag x", Vars::Visuals::Trajectory::AngDragBasisX, 0.f, 0.1f, 0.01f, "%.2f", FSlider_Precision); + FSlider("ang drag y", Vars::Visuals::Trajectory::AngDragBasisY, 0.f, 0.1f, 0.01f, "%.2f", FSlider_Precision); + FSlider("ang drag z", Vars::Visuals::Trajectory::AngDragBasisZ, 0.f, 0.1f, 0.01f, "%.2f", FSlider_Precision); + FSlider("max vel", Vars::Visuals::Trajectory::MaxVelocity, 0.f, 4000.f, 50.f, "%.0f", FSlider_Precision); + FSlider("max ang vel", Vars::Visuals::Trajectory::MaxAngularVelocity, 0.f, 7200.f, 50.f, "%.0f", FSlider_Precision); + } EndSection(); + } + if (Section("Hitbox")) + { + FColorPicker("Edge color", Vars::Colors::HitboxEdge, 1); FColorPicker("Face color", Vars::Colors::HitboxFace); + FToggle("Draw Hitboxes", Vars::Visuals::Hitbox::ShowHitboxes); + } EndSection(); + if (Section("Thirdperson")) + { + FToggle("Thirdperson", Vars::Visuals::ThirdPerson::Enabled); + FToggle("Thirdperson crosshair", Vars::Visuals::ThirdPerson::Crosshair, FToggle_Middle); + FSlider("Thirdperson distance", Vars::Visuals::ThirdPerson::Distance, 0.f, 500.f, 5.f, "%.0f", FSlider_Precision); + FSlider("Thirdperson right", Vars::Visuals::ThirdPerson::Right, -500.f, 500.f, 5.f, "%.0f", FSlider_Precision); + FSlider("Thirdperson up", Vars::Visuals::ThirdPerson::Up, -500.f, 500.f, 5.f, "%.0f", FSlider_Precision); + } EndSection(); + if (Section("Out of FOV arrows")) + { + FToggle("Enabled", Vars::Visuals::FOVArrows::Enabled); + FSlider("Offset", Vars::Visuals::FOVArrows::Offset, 0, 500, 25, "%d", FSlider_Precision); + FSlider("Max distance", Vars::Visuals::FOVArrows::MaxDist, 0.f, 5000.f, 50.f, "%.0f", FSlider_Precision); + } EndSection(); + if (Section("World")) + { + FSDropdown("World texture", Vars::Visuals::World::WorldTexture, { "Default", "Dev", "Camo", "Black", "White", "Flat" }, FSDropdown_Custom); + FDropdown("Modulations", Vars::Visuals::World::Modulations, { "World", "Sky", "Prop", "Particle", "Fog" }, { }, FDropdown_Left | FDropdown_Multi); + static std::vector skyNames = { + "Off", "sky_tf2_04", "sky_upward", "sky_dustbowl_01", "sky_goldrush_01", "sky_granary_01", "sky_well_01", "sky_gravel_01", "sky_badlands_01", + "sky_hydro_01", "sky_night_01", "sky_nightfall_01", "sky_trainyard_01", "sky_stormfront_01", "sky_morningsnow_01","sky_alpinestorm_01", + "sky_harvest_01", "sky_harvest_night_01", "sky_halloween", "sky_halloween_night_01", "sky_halloween_night2014_01", "sky_island_01", "sky_rainbow_01" + }; + FSDropdown("Skybox changer", Vars::Visuals::World::SkyboxChanger, skyNames, FSDropdown_Custom | FDropdown_Right); + bTransparent = !(FGet(Vars::Visuals::World::Modulations) & 1 << 0); + FColorPicker("World modulation", Vars::Colors::WorldModulation, 0, FColorPicker_Left); + bTransparent = !(FGet(Vars::Visuals::World::Modulations) & 1 << 1); + FColorPicker("Sky modulation", Vars::Colors::SkyModulation, 0, FColorPicker_Middle | FColorPicker_SameLine); + bTransparent = !(FGet(Vars::Visuals::World::Modulations) & 1 << 2); + FColorPicker("Prop modulation", Vars::Colors::PropModulation, 0, FColorPicker_Left); + bTransparent = !(FGet(Vars::Visuals::World::Modulations) & 1 << 3); + FColorPicker("Particle modulation", Vars::Colors::ParticleModulation, 0, FColorPicker_Middle | FColorPicker_SameLine); + bTransparent = !(FGet(Vars::Visuals::World::Modulations) & 1 << 4); + FColorPicker("Fog modulation", Vars::Colors::FogModulation, 0, FColorPicker_Left); + bTransparent = false; + FToggle("Near prop fade", Vars::Visuals::World::NearPropFade); + FToggle("No prop fade", Vars::Visuals::World::NoPropFade, FToggle_Middle); + } EndSection(); + + EndTable(); + } + break; + // Radar + case 4: + if (BeginTable("VisualsRadarTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Main")) + { + FToggle("Enabled", Vars::Radar::Main::Enabled); + FToggle("Draw out of range", Vars::Radar::Main::AlwaysDraw, FToggle_Middle); + FDropdown("Style", Vars::Radar::Main::Style, { "Circle", "Rectangle" }); + FSlider("Range", Vars::Radar::Main::Range, 50, 3000, 50, "%d", FSlider_Precision); + FSlider("Background alpha", Vars::Radar::Main::BackAlpha, 0, 255, 1, "%d", FSlider_Clamp); + FSlider("Line alpha", Vars::Radar::Main::LineAlpha, 0, 255, 1, "%d", FSlider_Clamp); + } EndSection(); + if (Section("Player")) + { + FToggle("Enabled", Vars::Radar::Players::Enabled); + FToggle("Background", Vars::Radar::Players::Background, FToggle_Middle); + FDropdown("Draw", Vars::Radar::Players::Draw, { "Local", "Enemy", "Team", "Friends", "Cloaked" }, {}, FDropdown_Multi | FDropdown_Left); + FDropdown("Icon", Vars::Radar::Players::IconType, { "Icons", "Portraits", "Avatar" }, {}, FDropdown_Right); + FSlider("Icon size## Player", Vars::Radar::Players::IconSize, 12, 30, 2); + FToggle("Health bar", Vars::Radar::Players::Health); + FToggle("Height indicator", Vars::Radar::Players::Height, FToggle_Middle); + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Building")) + { + FToggle("Enabled", Vars::Radar::Buildings::Enabled); + FToggle("Background", Vars::Radar::Buildings::Background, FToggle_Middle); + FDropdown("Draw", Vars::Radar::Buildings::Draw, { "Local", "Enemy", "Team", "Friends" }, {}, FDropdown_Multi); + FSlider("Icon size## Building", Vars::Radar::Buildings::IconSize, 12, 30, 2); + FToggle("Health bar", Vars::Radar::Buildings::Health); + } EndSection(); + if (Section("World")) + { + FToggle("Enabled", Vars::Radar::World::Enabled); + FToggle("Background", Vars::Radar::World::Background, FToggle_Middle); + FDropdown("Draw", Vars::Radar::World::Draw, { "Health", "Ammo", "Money", "Bombs", "Halloween" }, {}, FDropdown_Multi); + FSlider("Icon size## World", Vars::Radar::World::IconSize, 12, 30, 2); + } EndSection(); + + EndTable(); + } + break; + // Menu + case 5: + { + if (BeginTable("MenuTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("General")) + { + FColorPicker("Accent color", Vars::Menu::Theme::Accent, 0, FColorPicker_Left); + FColorPicker("Foremost color", Vars::Menu::Theme::Foremost, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("Background color", Vars::Menu::Theme::Background, 0, FColorPicker_Left); + FColorPicker("Foreground color", Vars::Menu::Theme::Foreground, 0, FColorPicker_Middle | FColorPicker_SameLine); + FColorPicker("Active color", Vars::Menu::Theme::Active, 0, FColorPicker_Left); + FColorPicker("Inactive color", Vars::Menu::Theme::Inactive, 0, FColorPicker_Middle | FColorPicker_SameLine); + + FSDropdown("Cheat title", Vars::Menu::CheatName, {}, FSDropdown_AutoUpdate | FDropdown_Left); + FSDropdown("Chat info prefix", Vars::Menu::CheatPrefix, {}, FDropdown_Right); + FKeybind("Menu primary key", Vars::Menu::MenuPrimaryKey.Map["default"], FButton_Left | FKeybind_AllowMenu); + FKeybind("Menu secondary key", Vars::Menu::MenuSecondaryKey.Map["default"], FButton_Right | FButton_SameLine | FKeybind_AllowMenu); + if (Vars::Menu::MenuPrimaryKey.Map["default"] == VK_LBUTTON) + Vars::Menu::MenuPrimaryKey.Map["default"] = VK_INSERT; + if (Vars::Menu::MenuSecondaryKey.Map["default"] == VK_LBUTTON) + Vars::Menu::MenuSecondaryKey.Map["default"] = VK_F3; + } EndSection(); + if (Section("Indicators")) + { + FDropdown("Indicators", Vars::Menu::Indicators, { "Ticks", "Crit hack", "Spectators", "Ping", "Conditions", "Seed prediction" }, {}, FDropdown_Multi); + if (FSlider("DPI", Vars::Menu::DPI, 0.8f, 1.8f, 0.2f, "%.1f", FSlider_Precision)) + H::Fonts.Reload(Vars::Menu::DPI.Map["default"]); + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + + EndTable(); + } + } + } +} + +/* Tab: Misc */ +void CMenu::MenuMisc() +{ + using namespace ImGui; + + if (BeginTable("MiscTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Movement")) + { + FDropdown("Autostrafe", Vars::Misc::Movement::AutoStrafe, { "Off", "Legit", "Directional" }); + bTransparent = FGet(Vars::Misc::Movement::AutoStrafe) != 2; + FSlider("Autostrafe turn scale", Vars::Misc::Movement::AutoStrafeTurnScale, 0.f, 1.f, 0.1f, "%.1f", FSlider_Clamp | FSlider_Precision); + bTransparent = false; + FToggle("Bunnyhop", Vars::Misc::Movement::Bunnyhop); + FToggle("Auto jumpbug", Vars::Misc::Movement::AutoJumpbug, FToggle_Middle); // this is unreliable without setups, do not depend on it! + FToggle("Auto rocketjump", Vars::Misc::Movement::AutoRocketJump); + FToggle("Auto ctap", Vars::Misc::Movement::AutoCTap, FToggle_Middle); + FToggle("Fast stop", Vars::Misc::Movement::FastStop); + FToggle("Fast accelerate", Vars::Misc::Movement::FastAccel, FToggle_Middle); + FToggle("Fast strafe", Vars::Misc::Movement::FastStrafe); + FToggle("No push", Vars::Misc::Movement::NoPush, FToggle_Middle); + FToggle("Crouch speed", Vars::Misc::Movement::CrouchSpeed); + } EndSection(); + if (Vars::Debug::Info.Value) + { + if (Section("debug")) + { + FSlider("timing offset", Vars::Misc::Movement::TimingOffset, -1, 1); + FSlider("apply timing offset above", Vars::Misc::Movement::ApplyAbove, 0, 8); + } EndSection(); + } + if (Section("Exploits")) + { + FToggle("Cheats bypass", Vars::Misc::Exploits::CheatsBypass); + FToggle("Pure bypass", Vars::Misc::Exploits::BypassPure, FToggle_Middle); + FToggle("Ping reducer", Vars::Misc::Exploits::PingReducer); + bTransparent = !FGet(Vars::Misc::Exploits::PingReducer); + FSlider("cl_cmdrate", Vars::Misc::Exploits::PingTarget, 1, 66, 1, "%d", FSlider_Right | FSlider_Clamp); + bTransparent = false; + SetCursorPosY(GetCursorPosY() - 8); + FToggle("Equip region unlock", Vars::Misc::Exploits::EquipRegionUnlock); + } EndSection(); + if (Vars::Debug::Info.Value) + { + if (Section("Convar spoofer")) + { + static std::string sName = "", sValue = ""; + + FSDropdown("Convar", &sName, {}, FDropdown_Left); + FSDropdown("Value", &sValue, {}, FDropdown_Right); + if (FButton("Send")) + { + if (auto pNetChan = static_cast(I::EngineClient->GetNetChannelInfo())) + { + SDK::Output("Convar", std::format("Sent {} as {}", sName, sValue).c_str(), VecToColor(F::Render.Accent)); + NET_SetConVar cmd(sName.c_str(), sValue.c_str()); // this doesn't crash, but doesn't do anything either + pNetChan->SendNetMsg(cmd); + + //sName = ""; + //sValue = ""; + } + } + } EndSection(); + } + if (Section("Automation")) + { + FToggle("Anti-backstab", Vars::Misc::Automation::AntiBackstab); + FToggle("Anti-AFK", Vars::Misc::Automation::AntiAFK, FToggle_Middle); + FToggle("Anti autobalance", Vars::Misc::Automation::AntiAutobalance); + FToggle("Auto accept item drops", Vars::Misc::Automation::AcceptItemDrops, FToggle_Middle); + FToggle("Taunt control", Vars::Misc::Automation::TauntControl); + FToggle("Kart control", Vars::Misc::Automation::KartControl, FToggle_Middle); + FToggle("Backpack expander", Vars::Misc::Automation::BackpackExpander); + } EndSection(); + if (Section("Sound")) + { + FDropdown("Block", Vars::Misc::Sound::Block, { "Footsteps", "Noisemaker" }, {}, FDropdown_Multi); + FToggle("Giant weapon sounds", Vars::Misc::Sound::GiantWeaponSounds); + FToggle("Hitsound always", Vars::Misc::Sound::HitsoundAlways, FToggle_Middle); + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Game")) + { + FToggle("Network fix", Vars::Misc::Game::NetworkFix); + FToggle("Prediction error jitter fix", Vars::Misc::Game::PredictionErrorJitterFix); + FToggle("Bones optimization", Vars::Misc::Game::SetupBonesOptimization, FToggle_Middle); + } EndSection(); + if (Section("Queueing")) + { + FDropdown("Force regions", Vars::Misc::Queueing::ForceRegions, + { "Atlanta", "Chicago", "Texas", "Los Angeles", "Moses Lake", "New York", "Seattle", "Virginia", "Amsterdam", "Frankfurt", "Helsinki", "London", "Madrid", "Paris", "Stockholm", "Vienna", "Warsaw", "Buenos" "Aires", "Lima", "Santiago", "Sao" "Paulo", "Bombay", "Chennai", "Dubai", "Hong Kong", "Madras", "Mumbai", "Seoul", "Singapore", "Tokyo", "Sydney", "Johannesburg" }, + {}, FDropdown_Multi + ); + FToggle("Freeze queue", Vars::Misc::Queueing::FreezeQueue); + FToggle("Auto queue", Vars::Misc::Queueing::AutoCasualQueue, FToggle_Middle); + } EndSection(); + if (Section("Mann vs. Machine")) + { + FToggle("Instant respawn", Vars::Misc::MannVsMachine::InstantRespawn); + FToggle("Instant revive", Vars::Misc::MannVsMachine::InstantRevive, FToggle_Middle); + } EndSection(); + if (Section("Chat")) + { + FToggle("Chat tags", Vars::Misc::Chat::Tags); + } EndSection(); + if (Section("Steam RPC")) + { + FToggle("Steam RPC", Vars::Misc::Steam::EnableRPC); + FDropdown("Match group", Vars::Misc::Steam::MatchGroup, { "Special Event", "MvM Mann Up", "Competitive", "Casual", "MvM Boot Camp" }, {}, FDropdown_Left); + FSDropdown("Map text", Vars::Misc::Steam::MapText, { "Fedoraware", "Figoraware", "Meowhook.club", "Rathook.cc", "Nitro.tf" }, FSDropdown_Custom | FDropdown_Right); + FSlider("Group size", Vars::Misc::Steam::GroupSize, 0, 6); + FToggle("Override in menu", Vars::Misc::Steam::OverrideMenu); + } EndSection(); + + EndTable(); + } +} + +/* Tab: Settings */ +void CMenu::MenuLogs() +{ + using namespace ImGui; + + switch (CurrentLogsTab) + { + // Logs + case 0: + // Eventually put all logs here, regardless of any settings + break; + // Settings + case 1: + if (BeginTable("ConfigSettingsTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Logging")) + { + FDropdown("Logs", Vars::Logging::Logs, { "Vote start", "Vote cast", "Class changes", "Damage", "Cheat detection", "Tags" }, {}, FDropdown_Multi); + FSlider("Notification time", Vars::Logging::Lifetime, 0.5f, 5.f, 0.5f, "%.1f"); + } EndSection(); + if (Section("Vote Start")) + { + bTransparent = !(FGet(Vars::Logging::Logs) & 1 << 0); + FDropdown("Log to", Vars::Logging::VoteStart::LogTo, { "Toasts", "Chat", "Party", "Console" }, { 1 << 0, 1 << 1, 1 << 2, 1 << 3 }, FDropdown_Multi); + bTransparent = false; + } EndSection(); + if (Section("Vote Cast")) + { + bTransparent = !(FGet(Vars::Logging::Logs) & 1 << 1); + FDropdown("Log to", Vars::Logging::VoteCast::LogTo, { "Toasts", "Chat", "Party", "Console" }, { 1 << 0, 1 << 1, 1 << 2, 1 << 3 }, FDropdown_Multi); + bTransparent = false; + } EndSection(); + if (Section("Class Change")) + { + bTransparent = !(FGet(Vars::Logging::Logs) & 1 << 2); + FDropdown("Log to", Vars::Logging::ClassChange::LogTo, { "Toasts", "Chat", "Party", "Console" }, { 1 << 0, 1 << 1, 1 << 2, 1 << 3 }, FDropdown_Multi); + bTransparent = false; + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Damage")) + { + bTransparent = !(FGet(Vars::Logging::Logs) & 1 << 3); + FDropdown("Log to", Vars::Logging::Damage::LogTo, { "Toasts", "Chat", "Party", "Console" }, { 1 << 0, 1 << 1, 1 << 2, 1 << 3 }, FDropdown_Multi); + bTransparent = false; + } EndSection(); + if (Section("Cheat Detection")) + { + bTransparent = !(FGet(Vars::Logging::Logs) & 1 << 4); + FDropdown("Log to", Vars::Logging::CheatDetection::LogTo, { "Toasts", "Chat", "Party", "Console" }, { 1 << 0, 1 << 1, 1 << 2, 1 << 3 }, FDropdown_Multi); + bTransparent = false; + } EndSection(); + if (Section("Tags")) + { + bTransparent = !(FGet(Vars::Logging::Logs) & 1 << 5); + FDropdown("Log to", Vars::Logging::Tags::LogTo, { "Toasts", "Chat", "Party", "Console" }, { 1 << 0, 1 << 1, 1 << 2, 1 << 3 }, FDropdown_Multi); + bTransparent = false; + } EndSection(); + + EndTable(); + } + } +} + +/* Tab: Config */ +void CMenu::MenuSettings() +{ + using namespace ImGui; + + switch (CurrentConfigTab) + { + // Settings + case 0: + if (BeginTable("ConfigSettingsTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Config")) + { + if (FButton("Configs folder", FButton_Left)) + ShellExecuteA(NULL, NULL, F::Configs.sConfigPath.c_str(), NULL, NULL, SW_SHOWNORMAL); + if (FButton("Visuals folder", FButton_Right | FButton_SameLine)) + ShellExecuteA(NULL, NULL, F::Configs.sVisualsPath.c_str(), NULL, NULL, SW_SHOWNORMAL); + + FTabs({ "GENERAL", "VISUALS", }, &CurrentConfigType, { GetColumnWidth() / 2 + 2, SubTabSize.y }, { 6, GetCursorPos().y }, false); + + switch (CurrentConfigType) + { + // General + case 0: + { + static std::string newName; + FSDropdown("Config name", &newName, {}, FSDropdown_AutoUpdate | FDropdown_Left); + if (FButton("Create", FButton_Fit | FButton_SameLine | FButton_Large) && newName.length() > 0) + { + if (!std::filesystem::exists(F::Configs.sConfigPath + "\\" + newName)) + F::Configs.SaveConfig(newName); + newName.clear(); + } + + for (const auto& entry : std::filesystem::directory_iterator(F::Configs.sConfigPath)) + { + if (!entry.is_regular_file() || entry.path().extension() != F::Configs.sConfigExtension) + continue; + + std::string configName = entry.path().filename().string(); + configName.erase(configName.end() - F::Configs.sConfigExtension.size(), configName.end()); + + const auto current = GetCursorPos().y; + + SetCursorPos({ 14, current + 11 }); + TextColored(configName == F::Configs.sCurrentConfig ? F::Render.Active.Value : F::Render.Inactive.Value, configName.c_str()); + + int o = 26; + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_DELETE)) + OpenPopup(std::format("Confirmation## DeleteConfig{}", configName).c_str()); + o += 25; + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_SAVE)) + { + if (configName != F::Configs.sCurrentConfig || F::Configs.sCurrentVisuals.length()) + OpenPopup(std::format("Confirmation## SaveConfig{}", configName).c_str()); + else + F::Configs.SaveConfig(configName); + } + o += 25; + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_DOWNLOAD)) + F::Configs.LoadConfig(configName); + + // Dialogs + { + // Save config dialog + if (BeginPopupModal(std::format("Confirmation## SaveConfig{}", configName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + Text(std::format("Do you really want to override '{}'?", configName).c_str()); + + if (FButton("Yes, override", FButton_Left)) + { + F::Configs.SaveConfig(configName); + CloseCurrentPopup(); + } + if (FButton("No", FButton_Right | FButton_SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + + // Delete config dialog + if (BeginPopupModal(std::format("Confirmation## DeleteConfig{}", configName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + Text(std::format("Do you really want to delete '{}'?", configName).c_str()); + + if (FButton("Yes, delete", FButton_Left)) + { + F::Configs.RemoveConfig(configName); + CloseCurrentPopup(); + } + if (FButton("No", FButton_Right | FButton_SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + } + + SetCursorPos({ 6, current }); DebugDummy({ 0, 28 }); + } + break; + } + // Visuals + case 1: + { + static std::string newName; + FSDropdown("Config name", &newName, {}, FSDropdown_AutoUpdate | FDropdown_Left); + if (FButton("Create", FButton_Fit | FButton_SameLine | FButton_Large) && newName.length() > 0) + { + if (!std::filesystem::exists(F::Configs.sVisualsPath + "\\" + newName)) + F::Configs.SaveVisual(newName); + newName.clear(); + } + + for (const auto& entry : std::filesystem::directory_iterator(F::Configs.sVisualsPath)) + { + if (!entry.is_regular_file() || entry.path().extension() != F::Configs.sConfigExtension) + continue; + + std::string configName = entry.path().filename().string(); + configName.erase(configName.end() - F::Configs.sConfigExtension.size(), configName.end()); + + const auto current = GetCursorPos().y; + + SetCursorPos({ 14, current + 11 }); + TextColored(configName == F::Configs.sCurrentVisuals ? F::Render.Active.Value : F::Render.Inactive.Value, configName.c_str()); + + int o = 26; + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_DELETE)) + OpenPopup(std::format("Confirmation## DeleteVisual{}", configName).c_str()); + o += 25; + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_SAVE)) + { + if (configName != F::Configs.sCurrentVisuals) + OpenPopup(std::format("Confirmation## SaveVisual{}", configName).c_str()); + else + F::Configs.SaveVisual(configName); + } + o += 25; + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_DOWNLOAD)) + F::Configs.LoadVisual(configName); + + // Dialogs + { + // Save config dialog + if (BeginPopupModal(std::format("Confirmation## SaveVisual{}", configName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + Text(std::format("Do you really want to override '{}'?", configName).c_str()); + + if (FButton("Yes, override", FButton_Left)) + { + F::Configs.SaveVisual(configName); + CloseCurrentPopup(); + } + if (FButton("No", FButton_Right | FButton_SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + + // Delete config dialog + if (BeginPopupModal(std::format("Confirmation## DeleteVisual{}", configName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + Text(std::format("Do you really want to delete '{}'?", configName).c_str()); + + if (FButton("Yes, delete", FButton_Left)) + { + F::Configs.RemoveVisual(configName); + CloseCurrentPopup(); + } + if (FButton("No", FButton_Right | FButton_SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + } + + SetCursorPos({ 6, current }); DebugDummy({ 0, 28 }); + } + } + } + } EndSection(); + SetCursorPosX(GetCursorPosX() + 8); + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + Text("Built @ %s, %s", __DATE__, __TIME__); + PopStyleColor(); + + /* Column 2 */ + TableNextColumn(); + if (Section("Debug")) + { + FToggle("Debug info", Vars::Debug::Info); + FToggle("Debug logging", Vars::Debug::Logging, FToggle_Middle); + FToggle("Show server hitboxes", Vars::Debug::ServerHitbox); HelpMarker("localhost servers"); + FToggle("Anti aim lines", Vars::Debug::AntiAimLines, FToggle_Middle); + } EndSection(); + if (Section("Extra")) + { + if (FButton("cl_fullupdate", FButton_Left)) + I::EngineClient->ClientCmd_Unrestricted("cl_fullupdate"); + if (FButton("retry", FButton_Right | FButton_SameLine)) + I::EngineClient->ClientCmd_Unrestricted("retry"); + if (FButton("Console", FButton_Left)) + I::EngineClient->ClientCmd_Unrestricted("toggleconsole"); + if (FButton("Fix Chams", FButton_Right | FButton_SameLine)) + F::Materials.ReloadMaterials(); + + if (!I::EngineClient->IsConnected()) + { + if (FButton("Unlock achievements", FButton_Left)) + OpenPopup("Unlock achievements?"); + if (FButton("Lock achievements", FButton_Right | FButton_SameLine)) + OpenPopup("Lock achievements?"); + + if (BeginPopupModal("Unlock achievements?", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + Text("Do you really want to unlock all achievements?"); + + Separator(); + if (Button("Yes, unlock", ImVec2(150, 0))) + { + //F::Misc.UnlockAchievements(); + CloseCurrentPopup(); + } + SameLine(); + if (Button("No", ImVec2(150, 0))) + CloseCurrentPopup(); + EndPopup(); + } + if (BeginPopupModal("Lock achievements?", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + Text("Do you really want to lock all achievements?"); + + Separator(); + if (Button("Yes, lock", ImVec2(150, 0))) + { + //F::Misc.LockAchievements(); + CloseCurrentPopup(); + } + SameLine(); + if (Button("No", ImVec2(150, 0))) + CloseCurrentPopup(); + EndPopup(); + } + } + if (Vars::Debug::Info.Value) + { + if (FButton("Reveal bullet lines", FButton_Left)) + F::Visuals.RevealBulletLines(); + if (FButton("Reveal prediction lines", FButton_Right | FButton_SameLine)) + F::Visuals.RevealSimLines(); + if (FButton("Reveal boxes", FButton_Left)) + F::Visuals.RevealBoxes(); + } + } EndSection(); + + EndTable(); + } + break; + // Conditions + case 1: + if (Section("Settings")) + { + FToggle("Show bind window", Vars::Menu::ShowBinds); + FToggle("Menu shows binds", Vars::Menu::MenuShowsBinds, FToggle_Middle); + } EndSection(); + if (Section("Conditions")) + { + static std::string sName = ""; + static Condition_t tCond = {}; + + if (BeginTable("ConditionsTable", 2)) + { + /* Column 1 */ + TableNextColumn(); SetCursorPos({ GetCursorPos().x - 8, GetCursorPos().y - 8 }); + if (BeginChild("ConditionsTableTable1", { GetColumnWidth() + 4, 104 }, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoBackground)) + { + FSDropdown("Name", &sName, {}, FSDropdown_AutoUpdate | FDropdown_Left); + FSDropdown("Parent", &tCond.Parent, {}, FSDropdown_AutoUpdate | FDropdown_Right); + FDropdown("Type", &tCond.Type, { "Key", "Class", "Weapon type" }, {}, FDropdown_Left); + switch (tCond.Type) + { + case 0: tCond.Info = std::min(tCond.Info, 2); FDropdown("Behavior", &tCond.Info, { "Hold", "Toggle", "Double click" }, {}, FDropdown_Right); break; + case 1: tCond.Info = std::min(tCond.Info, 8); FDropdown("Class", &tCond.Info, { "Scout", "Soldier", "Pyro", "Demoman", "Heavy", "Engineer", "Medic", "Sniper", "Spy" }, {}, FDropdown_Right); break; + case 2: tCond.Info = std::min(tCond.Info, 2); FDropdown("Weapon type", &tCond.Info, { "Hitscan", "Projectile", "Melee" }, {}, FDropdown_Right); break; + } + } EndChild(); + + /* Column 2 */ + TableNextColumn(); SetCursorPos({ GetCursorPos().x - 4, GetCursorPos().y - 8 }); + if (BeginChild("ConditionsTableTable2", { GetColumnWidth() + 8, 104 }, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoBackground)) + { + SetCursorPos({ 8, 24 }); + FToggle("Visible", &tCond.Visible); + FToggle("Not", &tCond.Not, FToggle_Middle); + if (tCond.Type == 0) + { + SetCursorPos({ 8, 56 }); + FKeybind("Key", tCond.Key, FButton_Large, -96); + } + + // create/modify button + bool bCreate = false, bClear = false, bMatch = false, bParent = true; + if (tCond.Parent.length()) + bParent = F::Conditions.mConditions.contains(tCond.Parent); + + SetCursorPos({ GetWindowSize().x - 96, 64 }); + PushStyleColor(ImGuiCol_Button, F::Render.Foremost.Value); + PushStyleColor(ImGuiCol_ButtonActive, F::Render.Foremost.Value); + if (sName.length() && FNV1A::Hash(sName.c_str()) != FNV1A::HashConst("default") && bParent && (!tCond.Type ? tCond.Key : true)) + { + PushStyleColor(ImGuiCol_ButtonHovered, F::Render.ForemostLight.Value); + bCreate = Button("##CreateButton", { 40, 40 }); + } + else + { + PushStyleColor(ImGuiCol_ButtonHovered, F::Render.Foremost.Value); + Button("##CreateButton", { 40, 40 }); + } + PopStyleColor(3); + SetCursorPos({ GetWindowSize().x - 83, 76 }); + if (sName.length() && FNV1A::Hash(sName.c_str()) != FNV1A::HashConst("default") && bParent && (!tCond.Type ? tCond.Key : true)) + { + bMatch = F::Conditions.mConditions.contains(sName); + IconImage(bMatch ? ICON_MD_SETTINGS : ICON_MD_ADD); + } + else + { + bTransparent = true; + IconImage(ICON_MD_ADD); + bTransparent = false; + } + + // clear button + SetCursorPos({ GetWindowSize().x - 48, 64 }); + PushStyleColor(ImGuiCol_Button, F::Render.Foremost.Value); + PushStyleColor(ImGuiCol_ButtonHovered, F::Render.ForemostLight.Value); + PushStyleColor(ImGuiCol_ButtonActive, F::Render.Foremost.Value); + bClear = Button("##ClearButton", { 40, 40 }); + PopStyleColor(3); + SetCursorPos({ GetWindowSize().x - 35, 76 }); + IconImage(ICON_MD_CLEAR); + + if (bCreate) + F::Conditions.AddCondition(sName, tCond); + if (bCreate || bClear) + { + sName = ""; + tCond = {}; + } + } EndChild(); + + EndTable(); + } + + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + SetCursorPos({ 14, 128 }); FText("Conditions"); + PopStyleColor(); + + std::function getConds = [&](std::string sParent, int x, int y) + { + auto uHash = FNV1A::Hash(sParent.c_str()); + for (auto& sCond : F::Conditions.vConditions) + { + auto& cCond = F::Conditions.mConditions[sCond]; + if (uHash != FNV1A::Hash(cCond.Parent.c_str())) + continue; + + y++; + + std::string info; std::string state; + switch (cCond.Type) + { + // key + case 0: + switch (cCond.Info) + { + case 0: { info = "hold"; break; } + case 1: { info = "toggle"; break; } + case 2: { info = "double"; break; } + } + state = VK2STR(cCond.Key); + break; + // class + case 1: + info = "class"; + switch (cCond.Info) + { + case 0: { state = "scout"; break; } + case 1: { state = "soldier"; break; } + case 2: { state = "pyro"; break; } + case 3: { state = "demoman"; break; } + case 4: { state = "heavy"; break; } + case 5: { state = "engineer"; break; } + case 6: { state = "medic"; break; } + case 7: { state = "sniper"; break; } + case 8: { state = "spy"; break; } + } + break; + // weapon type + case 2: + info = "weapon"; + switch (cCond.Info) + { + case 0: { state = "hitscan"; break; } + case 1: { state = "projectile"; break; } + case 2: { state = "melee"; break; } + } + } + if (cCond.Not) + info = std::format("not {}", info); + std::string str = std::format("{}, {}", info, state); + + bool bClicked = false, bDelete = false, bEdit = false; + + const ImVec2 restorePos = { 8.f + 28 * x, 108.f + 36.f * y }; + + // background + const float width = GetWindowSize().x - 16 - 28 * x; const auto winPos = GetWindowPos(); + GetWindowDrawList()->AddRectFilled({ winPos.x + restorePos.x, winPos.y + restorePos.y }, { winPos.x + restorePos.x + width, winPos.y + restorePos.y + 28 }, F::Render.Foremost, 3); + + // text + SetCursorPos({ restorePos.x + 10, restorePos.y + 7 }); + TextUnformatted(sCond.c_str()); + + SetCursorPos({ restorePos.x + width / 2 - CalcTextSize(str.c_str()).x / 2, restorePos.y + 7 }); + TextUnformatted(std::format("{}", str).c_str()); + + // buttons + SetCursorPos({ restorePos.x + width - 22, restorePos.y + 5 }); + bDelete = IconButton(ICON_MD_DELETE); + + SetCursorPos({ restorePos.x + width - 47, restorePos.y + 5 }); + bEdit = IconButton(ICON_MD_EDIT); + + SetCursorPos(restorePos); + bClicked = Button(std::format("##{}", sCond).c_str(), { width, 28 }); + + if (bClicked) + { + sName = sCond; + tCond = cCond; + } + if (bDelete) + OpenPopup(std::format("Confirmation## DeleteCond{}", sCond).c_str()); + if (BeginPopupModal(std::format("Confirmation## DeleteCond{}", sCond).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + const bool bChildren = F::Conditions.HasChildren(sCond); + Text(std::format("Do you really want to delete '{}'{}?", sCond, bChildren ? " and all of its children" : "").c_str()); + + if (FButton("Yes", FButton_Left)) + { + F::Conditions.RemoveCondition(sCond); + CloseCurrentPopup(); + } + if (FButton("No", FButton_Right | FButton_SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + if (bEdit) + { + if (sCondition != sCond) + sCondition = sCond; + else + sCondition = "default"; + } + + y = getConds(sCond, x + 1, y); + } + + return y; + }; + getConds("", 0, 0); + } EndSection(); + break; + // PlayerList + case 2: + if (Section("Players")) + { + if (I::EngineClient->IsInGame()) + { + std::lock_guard lock(F::PlayerUtils.mutex); + const auto& playerCache = F::PlayerUtils.vPlayerCache; + + auto getTeamColor = [](int team, bool alive) + { + switch (team) + { + case 3: return Color_t(50, 75, 100, alive ? 255 : 127); + case 2: return Color_t(125, 50, 50, alive ? 255 : 127); + } + return Color_t(100, 100, 100, 255); + }; + auto drawPlayer = [getTeamColor](const ListPlayer& player, int x, int y) + { + bool bClicked = false, bAdd = false, bPitch = false, bYaw = false; + + const Color_t teamColor = getTeamColor(player.Team, player.Alive); + const ImColor imColor = ColorToVec(teamColor); + + const ImVec2 restorePos = { x ? GetWindowSize().x / 2 + 4.f : 8.f, 32.f + 36.f * y }; + + // background + const float width = GetWindowSize().x / 2 - 12; const auto winPos = GetWindowPos(); + GetWindowDrawList()->AddRectFilled({ winPos.x + restorePos.x, winPos.y + restorePos.y }, { winPos.x + restorePos.x + width, winPos.y + restorePos.y + 28 }, imColor, 3); + + // text + icons + if (player.Local) + { + SetCursorPos({ restorePos.x + 7, restorePos.y + 5 }); + IconImage(ICON_MD_PERSON); + } + else if (player.Friend) + { + SetCursorPos({ restorePos.x + 7, restorePos.y + 5 }); + IconImage(ICON_MD_GROUP); + } + int lOffset = player.Local || player.Friend ? 29 : 10; + SetCursorPos({ restorePos.x + lOffset, restorePos.y + 7 }); + TextUnformatted(player.Name); + lOffset += CalcTextSize(player.Name).x + 8; + + // buttons + if (!player.Fake) + { + // right + SetCursorPos({ restorePos.x + width - 22, restorePos.y + 5 }); + bAdd = IconButton(ICON_MD_ADD); + if (Vars::AntiHack::Resolver::Resolver.Value && !player.Local) + { + SetCursorPos({ restorePos.x + width - 42, restorePos.y + 5 }); + bYaw = IconButton(ICON_MD_ARROW_FORWARD); + + SetCursorPos({ restorePos.x + width - 62, restorePos.y + 5 }); + bPitch = IconButton(ICON_MD_ARROW_UPWARD); + } + + // tag bar + SetCursorPos({ restorePos.x + lOffset, restorePos.y }); + if (BeginChild(std::format("TagBar{}", player.FriendsID).c_str(), { width - lOffset - (Vars::AntiHack::Resolver::Resolver.Value ? 68 : 28), 28 }, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBackground)) + { + PushFont(F::Render.FontSmall); + + const auto childPos = GetWindowPos(); + float tOffset = 0; + for (const auto& sTag : F::PlayerUtils.mPlayerTags[player.FriendsID]) + { + PriorityLabel_t plTag; + if (!F::PlayerUtils.GetTag(sTag, &plTag)) + continue; + + const ImColor tagColor = ColorToVec(plTag.Color); + const float tagWidth = CalcTextSize(sTag.c_str()).x + 25; + const ImVec2 tagPos = { tOffset, 4 }; + + PushStyleColor(ImGuiCol_Text, IsColorBright(tagColor) ? ImVec4{ 0, 0, 0, 1 } : ImVec4{ 1, 1, 1, 1 }); + + GetWindowDrawList()->AddRectFilled({ childPos.x + tagPos.x, childPos.y + tagPos.y }, { childPos.x + tagPos.x + tagWidth, childPos.y + tagPos.y + 20 }, tagColor, 3); + SetCursorPos({ tagPos.x + 5, tagPos.y + 4 }); + TextUnformatted(sTag.c_str()); + SetCursorPos({ tagPos.x + tagWidth - 18, tagPos.y + 2 }); + if (IconButton(ICON_MD_CANCEL)) + F::PlayerUtils.RemoveTag(player.FriendsID, sTag, true, player.Name); + + PopStyleColor(); + + tOffset += tagWidth + 4; + } + PopFont(); + } EndChild(); + + if (!player.Local) + { + //bClicked = IsItemClicked(); + bClicked = IsItemHovered() && IsMouseClicked(ImGuiMouseButton_Right) || bClicked; + + SetCursorPos(restorePos); + /*bClicked = */Button(std::format("##{}", player.Name).c_str(), { width, 28 }) || bClicked; + bClicked = IsItemHovered() && IsMouseClicked(ImGuiMouseButton_Right) || bClicked; + } + } + + SetCursorPos(restorePos); + DebugDummy({ 0, 28 }); + + if (bClicked) + OpenPopup(std::format("Clicked{}", player.FriendsID).c_str()); + else if (bAdd) + OpenPopup(std::format("Add{}", player.FriendsID).c_str()); + else if (bPitch) + OpenPopup(std::format("Pitch{}", player.FriendsID).c_str()); + else if (bYaw) + OpenPopup(std::format("Yaw{}", player.FriendsID).c_str()); + + // popups + if (FBeginPopup(std::format("Clicked{}", player.FriendsID).c_str())) + { + if (FSelectable("Profile")) + { + //g_SteamInterfaces.Friends->ActivateGameOverlayToUser("steamid", CSteamID(0x0110000100000000ULL + player.FriendsID)); + } + + if (FSelectable("Votekick")) + I::EngineClient->ClientCmd_Unrestricted(std::format("callvote kick {}", player.UserID).c_str()); + + FEndPopup(); + } + else if (FBeginPopup(std::format("Add{}", player.FriendsID).c_str())) + { + for (const auto& [sTag, plTag] : F::PlayerUtils.mTags) + { + if (!plTag.Assignable || F::PlayerUtils.HasTag(player.FriendsID, sTag)) + continue; + + auto imColor = ColorToVec(plTag.Color); + PushStyleColor(ImGuiCol_Text, imColor); + imColor.x /= 3; imColor.y /= 3; imColor.z /= 3; + if (FSelectable(sTag.c_str(), imColor)) + F::PlayerUtils.AddTag(player.FriendsID, sTag, true, player.Name); + PopStyleColor(); + } + + FEndPopup(); + } + else if (FBeginPopup(std::format("Pitch{}", player.FriendsID).c_str())) + { + for (size_t i = 0; i < F::PlayerUtils.vListPitch.size(); i++) + { + if (FSelectable(F::PlayerUtils.vListPitch[i])) + F::Resolver.mResolverMode[player.FriendsID].second = int(i); + } + FEndPopup(); + } + else if (FBeginPopup(std::format("Yaw{}", player.FriendsID).c_str())) + { + for (size_t i = 0; i < F::PlayerUtils.vListYaw.size(); i++) + { + if (FSelectable(F::PlayerUtils.vListYaw[i])) + F::Resolver.mResolverMode[player.FriendsID].second = int(i); + } + FEndPopup(); + } + }; + + // display players + int iBlu = 0, iRed = 0; + for (const auto& player : playerCache) + { + switch (player.Team) + { + case 3: + drawPlayer(player, 0, iBlu); + iBlu++; break; + case 2: + drawPlayer(player, 1, iRed); + iRed++; break; + } + } + int iOther = 0; const int iMax = std::max(iBlu, iRed); + for (const auto& player : playerCache) + { + if (player.Team != 3 && player.Team != 2) + { + drawPlayer(player, iOther % 2, iMax + iOther / 2); + iOther++; + } + } + } + else + { + SetCursorPos({ 18, 39 }); + Text("Not ingame"); + DebugDummy({ 0, 8 }); + } + } EndSection(); + if (Section("Tags")) + { + static std::string sName = ""; + static PriorityLabel_t tTag = {}; + + if (BeginTable("TagTable", 2)) + { + /* Column 1 */ + TableNextColumn(); SetCursorPos({ GetCursorPos().x - 8, GetCursorPos().y - 8 }); + if (BeginChild("TagTable1", { GetColumnWidth() + 4, 56 }, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoBackground)) + { + FSDropdown("Name", &sName, {}, FSDropdown_AutoUpdate | FDropdown_Left, 1); + FColorPicker("Color", &tTag.Color, 0, FColorPicker_Dropdown); + + auto uHash = FNV1A::Hash(sName.c_str()); + bDisabled = uHash == FNV1A::HashConst("Original") || uHash == FNV1A::HashConst("Ignored"); + int iLabel = bDisabled ? 0 : tTag.Label; + FDropdown("Type", &iLabel, { "Priority", "Label" }, {}, FDropdown_Right); + tTag.Label = iLabel; + if (bDisabled) + tTag.Label = false; + bDisabled = false; + } EndChild(); + + /* Column 2 */ + TableNextColumn(); SetCursorPos({ GetCursorPos().x - 4, GetCursorPos().y - 8 }); + if (BeginChild("TagTable2", { GetColumnWidth() + 8, 56 }, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoBackground)) + { + bTransparent = tTag.Label; // transparent if we want a label, user can still use to sort + SetCursorPosY(GetCursorPos().y + 12); + FSlider("Priority", &tTag.Priority, -10, 10, 1, "%d", FSlider_Left); + bTransparent = false; + + // create/modify button + bool bCreate = false, bClear = false; + + SetCursorPos({ GetWindowSize().x - 96, 16 }); + PushStyleColor(ImGuiCol_Button, F::Render.Foremost.Value); + PushStyleColor(ImGuiCol_ButtonActive, F::Render.Foremost.Value); + if (sName.length()) + { + PushStyleColor(ImGuiCol_ButtonHovered, F::Render.ForemostLight.Value); + bCreate = Button("##CreateButton", { 40, 40 }); + } + else + { + PushStyleColor(ImGuiCol_ButtonHovered, F::Render.Foremost.Value); + Button("##CreateButton", { 40, 40 }); + } + PopStyleColor(3); + SetCursorPos({ GetWindowSize().x - 83, 28 }); + if (sName.length()) + { + bool bMatch = F::PlayerUtils.mTags.contains(sName); + IconImage(bMatch ? ICON_MD_SETTINGS : ICON_MD_ADD); + } + else + { + bTransparent = true; + IconImage(ICON_MD_ADD); + bTransparent = false; + } + + // clear button + SetCursorPos({ GetWindowSize().x - 48, 16 }); + PushStyleColor(ImGuiCol_Button, F::Render.Foremost.Value); + PushStyleColor(ImGuiCol_ButtonHovered, F::Render.ForemostLight.Value); + PushStyleColor(ImGuiCol_ButtonActive, F::Render.Foremost.Value); + bClear = Button("##ClearButton", { 40, 40 }); + PopStyleColor(3); + SetCursorPos({ GetWindowSize().x - 35, 28 }); + IconImage(ICON_MD_CLEAR); + + if (bCreate) + { + F::PlayerUtils.bSaveTags = true; + F::PlayerUtils.mTags[sName].Color = tTag.Color; + F::PlayerUtils.mTags[sName].Priority = tTag.Priority; + F::PlayerUtils.mTags[sName].Label = tTag.Label; + } + if (bCreate || bClear) + { + sName = ""; + tTag = {}; + } + } EndChild(); + + EndTable(); + } + + auto drawTag = [](const std::string sTag, const PriorityLabel_t& plTag, int y) + { + bool bClicked = false, bDelete = false; + + ImColor imColor = ColorToVec(plTag.Color); + imColor.Value.x /= 3; imColor.Value.y /= 3; imColor.Value.z /= 3; + + const ImVec2 restorePos = { plTag.Label ? GetWindowSize().x * 2 / 3 + 4.f : 8.f, 96.f + 36.f * y }; + + // background + const float width = GetWindowSize().x * (plTag.Label ? 1.f / 3 : 2.f / 3) - 12; const auto winPos = GetWindowPos(); + GetWindowDrawList()->AddRectFilled({ winPos.x + restorePos.x, winPos.y + restorePos.y }, { winPos.x + restorePos.x + width, winPos.y + restorePos.y + 28 }, imColor, 3); + + // text + SetCursorPos({ restorePos.x + 10, restorePos.y + 7 }); + TextUnformatted(sTag.c_str()); + + if (!plTag.Label) + { + SetCursorPos({ restorePos.x + width / 2, restorePos.y + 7 }); + TextUnformatted(std::format("{}", plTag.Priority).c_str()); + } + + // buttons + if (!plTag.Locked) + { + SetCursorPos({ restorePos.x + width - 22, restorePos.y + 5 }); + bDelete = IconButton(ICON_MD_DELETE); + } + + SetCursorPos(restorePos); + bClicked = Button(std::format("##{}", sTag).c_str(), { width, 28 }); + + if (bClicked) + { + sName = sTag; + tTag.Color = plTag.Color; + tTag.Priority = plTag.Priority; + tTag.Label = plTag.Label; + } + if (bDelete) + { + F::PlayerUtils.mTags.erase(sTag); + F::PlayerUtils.bSaveTags = true; + if (sName == sTag) + { + sName = ""; + tTag = {}; + } + } + }; + + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + SetCursorPos({ 14, 80 }); FText("Priorities"); + SetCursorPos({ GetWindowSize().x * 2 / 3 + 10, 80 }); FText("Labels"); + PopStyleColor(); + + std::vector> vPriorities = {}, vLabels = {}; + for (const auto& [sTag, plTag] : F::PlayerUtils.mTags) + { + if (!plTag.Label) + vPriorities.push_back({ sTag, plTag }); + else + vLabels.push_back({ sTag, plTag }); + } + + std::sort(vPriorities.begin(), vPriorities.end(), [&](const auto& a, const auto& b) -> bool + { + // override for default tag + if (FNV1A::Hash(a.first.c_str()) == FNV1A::HashConst("Default")) + return true; + if (FNV1A::Hash(b.first.c_str()) == FNV1A::HashConst("Default")) + return false; + + // sort by priority if unequal + if (a.second.Priority != b.second.Priority) + return a.second.Priority > b.second.Priority; + + return a.first < b.first; + }); + std::sort(vLabels.begin(), vLabels.end(), [&](const auto& a, const auto& b) -> bool + { + // sort by priority if unequal + if (a.second.Priority != b.second.Priority) + return a.second.Priority > b.second.Priority; + + return a.first < b.first; + }); + + // display tags + int iPriorities = 0, iLabels = 0; + for (const auto& pair : vPriorities) + { + drawTag(pair.first, pair.second, iPriorities); + iPriorities++; + } + for (const auto& pair : vLabels) + { + drawTag(pair.first, pair.second, iLabels); + iLabels++; + } + SetCursorPos({ 0, 60.f + 36.f * std::max(iPriorities, iLabels) }); DebugDummy({ 0, 28 }); + } EndSection(); + break; + // MaterialManager + case 3: + if (BeginTable("MaterialsTable", 2)) + { + /* Column 1 */ + TableNextColumn(); + if (Section("Manager")) + { + static std::string newName; + FSDropdown("Material name", &newName, {}, FSDropdown_AutoUpdate | FDropdown_Left); + if (FButton("Create", FButton_Fit | FButton_SameLine | FButton_Large) && newName.length() > 0) + { + F::Materials.AddMaterial(newName); + newName.clear(); + } + + if (FButton("Folder", FButton_Fit | FButton_SameLine | FButton_Large)) + ShellExecuteA(nullptr, "open", MaterialFolder.c_str(), nullptr, nullptr, SW_SHOWDEFAULT); + + std::vector> vMaterials; + for (auto const& [sName, mat] : F::Materials.mChamMaterials) + vMaterials.push_back({ sName, mat }); + + std::sort(vMaterials.begin(), vMaterials.end(), [&](const auto& a, const auto& b) -> bool + { + // override for none material + if (FNV1A::Hash(a.first.c_str()) == FNV1A::HashConst("None")) + return true; + if (FNV1A::Hash(b.first.c_str()) == FNV1A::HashConst("None")) + return false; + + // keep locked materials higher + if (a.second.bLocked && !b.second.bLocked) + return true; + if (!a.second.bLocked && b.second.bLocked) + return false; + + return a.first < b.first; + }); + + for (auto const& pair : vMaterials) + { + const auto current = GetCursorPos().y; + + SetCursorPos({ 14, current + 11 }); + TextColored(pair.second.bLocked ? F::Render.Inactive.Value : F::Render.Active.Value, pair.first.c_str()); + + int o = 26; + + if (!pair.second.bLocked) + { + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_DELETE)) + OpenPopup(std::format("Confirmation## DeleteMat{}", pair.first).c_str()); + if (BeginPopupModal(std::format("Confirmation## DeleteMat{}", pair.first).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + Text(std::format("Do you really want to delete '{}'?", pair.first).c_str()); + + if (FButton("Yes", FButton_Left)) + { + F::Materials.RemoveMaterial(pair.first); + CloseCurrentPopup(); + } + if (FButton("No", FButton_Right | FButton_SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + o += 25; + } + + SetCursorPos({ GetWindowSize().x - o, current + 9 }); + if (IconButton(ICON_MD_EDIT)) + { + CurrentMaterial = pair.first; + LockedMaterial = pair.second.bLocked; + + TextEditor.SetText(F::Materials.GetVMT(CurrentMaterial)); + TextEditor.SetReadOnly(LockedMaterial); + } + + SetCursorPos({ 6, current }); DebugDummy({ 0, 28 }); + } + } EndSection(); + + /* Column 2 */ + TableNextColumn(); + if (CurrentMaterial.length()) + { + auto count = std::ranges::count(TextEditor.GetText(), '\n'); // doesn't account for text editor size otherwise + if (Section("Editor", 81 + 15 * count, true)) + { + // Toolbar + if (!LockedMaterial) + { + if (FButton("Save", FButton_Fit)) + { + auto text = TextEditor.GetText(); + text.erase(text.end() - 1, text.end()); // get rid of random newline + F::Materials.EditMaterial(CurrentMaterial, text); + } + SameLine(); + } + if (FButton("Close", FButton_Fit)) + CurrentMaterial = ""; + SameLine(); SetCursorPosY(GetCursorPosY() + 27); + PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); + FText(LockedMaterial ? std::format("Viewing: {}", CurrentMaterial).c_str() : std::format("Editing: {}", CurrentMaterial).c_str(), FText_Right); + PopStyleColor(); + + // Text editor + Dummy({ 0, 8 }); + + PushFont(F::Render.FontMono); + TextEditor.Render("TextEditor"); + PopFont(); + } EndSection(); + } + + EndTable(); + } + break; + } +} +#pragma endregion + +void CMenu::AddDraggable(const char* szTitle, ConfigVar& var, bool bShouldDraw) +{ + using namespace ImGui; + + if (!bShouldDraw) + return; + + static std::unordered_map> old = {}; + DragBox_t info = FGet(var); + const float sizeX = 100.f * Vars::Menu::DPI.Map["default"], sizeY = 40.f * Vars::Menu::DPI.Map["default"]; + SetNextWindowSize({ sizeX, sizeY }, ImGuiCond_Always); + if (!old.contains(szTitle) || info != old[szTitle].first || sizeX != old[szTitle].second) + SetNextWindowPos({ float(info.x - sizeX / 2), float(info.y) }, ImGuiCond_Always); + + PushStyleColor(ImGuiCol_WindowBg, {}); + PushStyleColor(ImGuiCol_Border, F::Render.Active.Value); + PushStyleVar(ImGuiStyleVar_WindowRounding, 3); + PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1); + PushStyleVar(ImGuiStyleVar_WindowMinSize, { sizeX, sizeY }); + if (Begin(szTitle, nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing)) + { + const auto winPos = GetWindowPos(); + + info.x = winPos.x + sizeX / 2; info.y = winPos.y; old[szTitle] = { info, sizeX }; + FSet(var, info); + + PushFont(F::Render.FontBlack); + auto size = CalcTextSize(szTitle); + SetCursorPos({ (sizeX - size.x) * 0.5f, (sizeY - size.y) * 0.5f }); + Text(szTitle); + PopFont(); + + End(); + } + PopStyleVar(3); + PopStyleColor(2); +} + +void CMenu::DrawBinds() +{ + using namespace ImGui; + + if ((IsOpen ? !FGet(Vars::Menu::ShowBinds) : !Vars::Menu::ShowBinds.Value) || !IsOpen && I::EngineVGui->IsGameUIVisible()) + return; + + static DragBox_t old = {}; + DragBox_t info = IsOpen ? FGet(Vars::Menu::BindsDisplay) : Vars::Menu::BindsDisplay.Value; + if (info != old) + SetNextWindowPos({ float(info.x), float(info.y) }, ImGuiCond_Always); + + std::vector actives; + std::vector titles; + std::vector infos; + std::vector states; + float titleWidth = 0; + float infoWidth = 0; + float stateWidth = 0; + + PushFont(F::Render.FontSmall); + std::function getConds = [&](std::string sParent) + { + auto uHash = FNV1A::Hash(sParent.c_str()); + for (auto& sCond : F::Conditions.vConditions) + { + auto& tCond = F::Conditions.mConditions[sCond]; + if (uHash != FNV1A::Hash(tCond.Parent.c_str())) + continue; + + if (tCond.Visible) + { + std::string info; std::string state; + switch (tCond.Type) + { + // key + case 0: + switch (tCond.Info) + { + case 0: { info = "hold"; break; } + case 1: { info = "toggle"; break; } + case 2: { info = "double"; break; } + } + state = VK2STR(tCond.Key); + break; + // class + case 1: + info = "class"; + switch (tCond.Info) + { + case 0: { state = "scout"; break; } + case 1: { state = "soldier"; break; } + case 2: { state = "pyro"; break; } + case 3: { state = "demoman"; break; } + case 4: { state = "heavy"; break; } + case 5: { state = "engineer"; break; } + case 6: { state = "medic"; break; } + case 7: { state = "sniper"; break; } + case 8: { state = "spy"; break; } + } + break; + // weapon type + case 2: + info = "weapon"; + switch (tCond.Info) + { + case 0: { state = "hitscan"; break; } + case 1: { state = "projectile"; break; } + case 2: { state = "melee"; break; } + } + } + if (tCond.Not) + info = std::format("not {}", info); + + actives.push_back(tCond.Active); + titles.push_back(sCond); + infos.push_back(info); + states.push_back(state); + titleWidth = std::max(titleWidth, CalcTextSize(sCond.c_str()).x); + infoWidth = std::max(infoWidth, CalcTextSize(info.c_str()).x); + stateWidth = std::max(stateWidth, CalcTextSize(state.c_str()).x); + } + + if (tCond.Active) + getConds(sCond); + } + }; + getConds(""); + + SetNextWindowSize({ std::max(titleWidth + infoWidth + stateWidth + 42, 56.f), 18.f * actives.size() + 38 }); + PushStyleVar(ImGuiStyleVar_WindowMinSize, { 40.f, 40.f }); + if (Begin("Binds", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize)) + { + const auto winPos = GetWindowPos(); + + info.x = winPos.x; info.y = winPos.y; old = info; + if (IsOpen) + FSet(Vars::Menu::BindsDisplay, info); + + PushFont(F::Render.FontLarge); + SetCursorPos({ 11, 9 }); + Text("Binds"); + PopFont(); + + const float width = std::max(titleWidth + infoWidth + stateWidth + 42, 56.f); + GetWindowDrawList()->AddRectFilled({ winPos.x + 8, winPos.y + 26 }, { winPos.x + width - 8, winPos.y + 27 }, F::Render.Accent, 3); + + for (size_t i = 0; i < actives.size(); i++) + { + SetCursorPos({ 12, 18.f * i + 35 }); + PushStyleColor(ImGuiCol_Text, actives[i] ? F::Render.Accent.Value : F::Render.Inactive.Value); + Text(titles[i].c_str()); + PopStyleColor(); + + SetCursorPos({ titleWidth + 22, 18.f * i + 35 }); + PushStyleColor(ImGuiCol_Text, actives[i] ? F::Render.Active.Value : F::Render.Inactive.Value); + Text(infos[i].c_str()); + + SetCursorPos({ titleWidth + infoWidth + 32, 18.f * i + 35 }); + Text(states[i].c_str()); + PopStyleColor(); + } + + End(); + } + PopStyleVar(); + PopFont(); +} + +/* Window for the camera feature */ +void CMenu::DrawCameraWindow() +{ + using namespace ImGui; + + if (!FGet(Vars::Visuals::Simulation::ProjectileCamera)) + return; + + static WindowBox_t old = {}; + WindowBox_t info = FGet(Vars::Visuals::Simulation::ProjectileWindow); + if (info != old) + { + SetNextWindowPos({ float(info.x), float(info.y) }, ImGuiCond_Always); + SetNextWindowSize({ float(info.w), float(info.h) }, ImGuiCond_Always); + } + + PushStyleColor(ImGuiCol_WindowBg, {}); + PushStyleColor(ImGuiCol_Border, F::Render.Active.Value); + PushStyleVar(ImGuiStyleVar_WindowRounding, 3); + PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1); + PushStyleVar(ImGuiStyleVar_WindowMinSize, { 100.f, 100.f }); + if (Begin("Camera", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing)) + { + const auto winPos = GetWindowPos(); + const auto winSize = GetWindowSize(); + + info.x = winPos.x; info.y = winPos.y; info.w = winSize.x; info.h = winSize.y; old = info; + FSet(Vars::Visuals::Simulation::ProjectileWindow, info); + + PushFont(F::Render.FontBlack); + auto size = CalcTextSize("Camera"); + SetCursorPos({ (winSize.x - size.x) * 0.5f, (winSize.y - size.y) * 0.5f }); + Text("Camera"); + PopFont(); + + End(); + } + PopStyleVar(3); + PopStyleColor(2); +} + +static void SquareConstraints(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = std::max(data->DesiredSize.x, data->DesiredSize.y); } +void CMenu::DrawRadar() +{ + using namespace ImGui; + + if (!FGet(Vars::Radar::Main::Enabled)) + return; + + static WindowBox_t old = {}; + WindowBox_t info = FGet(Vars::Radar::Main::Window); + if (info != old) + { + SetNextWindowPos({ float(info.x), float(info.y) }, ImGuiCond_Always); + SetNextWindowSize({ float(info.w), float(info.w) }, ImGuiCond_Always); + } + + PushStyleColor(ImGuiCol_WindowBg, {}); + PushStyleColor(ImGuiCol_Border, F::Render.Active.Value); + PushStyleVar(ImGuiStyleVar_WindowRounding, 3); + PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1); + SetNextWindowSizeConstraints({ 100.f, 100.f }, { 1000.f, 1000.f }, SquareConstraints); + if (Begin("Radar", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing)) + { + const ImVec2 winPos = GetWindowPos(); + const ImVec2 winSize = GetWindowSize(); + + info.x = winPos.x; info.y = winPos.y; info.w = winSize.x; old = info; + FSet(Vars::Radar::Main::Window, info); + + PushFont(F::Render.FontBlack); + auto size = CalcTextSize("Radar"); + SetCursorPos({ (winSize.x - size.x) * 0.5f, (winSize.y - size.y) * 0.5f }); + Text("Radar"); + PopFont(); + + End(); + } + PopStyleVar(2); + PopStyleColor(2); +} + +void CMenu::Render() +{ + using namespace ImGui; + + if (!ConfigLoaded) + return; + + InKeybind = false; + if (U::KeyHandler.Pressed(Vars::Menu::MenuPrimaryKey.Value) || U::KeyHandler.Pressed(Vars::Menu::MenuSecondaryKey.Value)) + I::MatSystemSurface->SetCursorAlwaysVisible(IsOpen = !IsOpen); + + DrawBinds(); + + if (IsOpen) + { + KeyHandler(); + + DrawMenu(); + + DrawCameraWindow(); + DrawRadar(); + + AddDraggable("Ticks", Vars::Menu::TicksDisplay, FGet(Vars::Menu::Indicators) & (1 << 0)); + AddDraggable("Crit hack", Vars::Menu::CritsDisplay, FGet(Vars::Menu::Indicators) & (1 << 1)); + AddDraggable("Spectators", Vars::Menu::SpectatorsDisplay, FGet(Vars::Menu::Indicators) & (1 << 2)); + AddDraggable("Ping", Vars::Menu::PingDisplay, FGet(Vars::Menu::Indicators) & (1 << 3)); + AddDraggable("Conditions", Vars::Menu::ConditionsDisplay, FGet(Vars::Menu::Indicators) & (1 << 4)); + AddDraggable("Seed prediction", Vars::Menu::SeedPredictionDisplay, FGet(Vars::Menu::Indicators) & (1 << 5)); + + F::Render.Cursor = GetMouseCursor(); + } + else + mActives.clear(); +} \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/Menu/Menu.h b/Amalgam/src/Features/ImGui/Menu/Menu.h new file mode 100644 index 0000000..90600d0 --- /dev/null +++ b/Amalgam/src/Features/ImGui/Menu/Menu.h @@ -0,0 +1,45 @@ +#pragma once +#include "../../../SDK/SDK.h" +#include "../Render.h" +#include + +class CMenu +{ + void DrawMenu(); + + void MenuAimbot(); + void MenuVisuals(); + void MenuMisc(); + void MenuLogs(); + void MenuSettings(); + + void AddDraggable(const char* szTitle, ConfigVar& info, bool bShouldDraw); + void DrawBinds(); + void DrawCameraWindow(); + void DrawRadar(); + + int CurrentTab = 0; + + int CurrentAimbotTab = 0; + int CurrentVisualsTab = 0; + int CurrentLogsTab = 0; + int CurrentConfigTab = 0; + int CurrentConfigType = 0; + + ImVec2 TabSize = { 65, 72 }; + ImVec2 SubTabSize = { 90, 48 }; + + // material editor stuff + TextEditor TextEditor; + std::string CurrentMaterial; + bool LockedMaterial; + +public: + void Render(); + + bool IsOpen = false; + bool ConfigLoaded = false; + bool InKeybind = false; +}; + +ADD_FEATURE(CMenu, Menu); \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/Render.cpp b/Amalgam/src/Features/ImGui/Render.cpp new file mode 100644 index 0000000..b9abe98 --- /dev/null +++ b/Amalgam/src/Features/ImGui/Render.cpp @@ -0,0 +1,152 @@ +#include "Render.h" + +#include "../../Hooks/Direct3DDevice9_EndScene.h" +#include +#include "MaterialDesign/MaterialIcons.h" +#include "MaterialDesign/IconDefinitions.h" +#include "Menu/Menu.h" +#include "../Visuals/Visuals.h" + +void CRender::Render(IDirect3DDevice9* pDevice) +{ + using namespace ImGui; + + static std::once_flag initFlag; + std::call_once(initFlag, [&] + { + Initialize(pDevice); + }); + + pDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0xFFFFFFFF); + pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, false); + + ImGui_ImplDX9_NewFrame(); + ImGui_ImplWin32_NewFrame(); + NewFrame(); + + LoadColors(); + PushFont(FontRegular); + + F::Visuals.DrawTickbaseBars(); + F::Menu.Render(); + + PopFont(); + + EndFrame(); + ImGui::Render(); + ImGui_ImplDX9_RenderDrawData(GetDrawData()); + pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, true); +} + +void CRender::LoadColors() +{ + using namespace ImGui; + + auto ColorToVec = [](Color_t color) -> ImColor + { + return { float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f, float(color.a) / 255.f }; + }; + + Accent = ColorToVec(Vars::Menu::Theme::Accent.Value); + AccentLight = ImColor(Accent.Value.x * 1.1f, Accent.Value.y * 1.1f, Accent.Value.z * 1.1f, Accent.Value.w); + Background = ColorToVec(Vars::Menu::Theme::Background.Value); + Foreground = ColorToVec(Vars::Menu::Theme::Foreground.Value); + Foremost = ColorToVec(Vars::Menu::Theme::Foremost.Value); + ForemostLight = ImColor(Foremost.Value.x * 1.1f, Foremost.Value.y * 1.1f, Foremost.Value.z * 1.1f, Foremost.Value.w); + Inactive = ColorToVec(Vars::Menu::Theme::Inactive.Value); + Active = ColorToVec(Vars::Menu::Theme::Active.Value); + + ImVec4* colors = GetStyle().Colors; + colors[ImGuiCol_Button] = {}; + colors[ImGuiCol_ButtonHovered] = {}; + colors[ImGuiCol_ButtonActive] = {}; + colors[ImGuiCol_FrameBg] = Foremost; + colors[ImGuiCol_FrameBgHovered] = ForemostLight; + colors[ImGuiCol_FrameBgActive] = Foremost; + colors[ImGuiCol_Header] = {}; + colors[ImGuiCol_HeaderHovered] = ForemostLight; + colors[ImGuiCol_HeaderActive] = {}; + colors[ImGuiCol_ModalWindowDimBg] = { Background.Value.x, Background.Value.y, Background.Value.z, 0.4f }; + colors[ImGuiCol_PopupBg] = ForemostLight; + colors[ImGuiCol_ResizeGrip] = {}; + colors[ImGuiCol_ResizeGripActive] = {}; + colors[ImGuiCol_ResizeGripHovered] = {}; + colors[ImGuiCol_ScrollbarBg] = {}; + colors[ImGuiCol_SliderGrab] = Accent; + colors[ImGuiCol_SliderGrabActive] = AccentLight; + colors[ImGuiCol_Text] = Active; + colors[ImGuiCol_WindowBg] = Background; +} + +void CRender::LoadStyle() +{ + using namespace ImGui; + + auto& style = GetStyle(); + style.ButtonTextAlign = { 0.5f, 0.5f }; // Center button text + style.CellPadding = { 4, 0 }; + style.ChildBorderSize = 0.f; + style.ChildRounding = 0.f; + style.FrameBorderSize = 0.f; + style.FramePadding = { 0, 0 }; + style.FrameRounding = 3.f; + style.ItemInnerSpacing = { 0, 0 }; + style.ItemSpacing = { 8, 8 }; + style.PopupBorderSize = 0.f; + style.PopupRounding = 3.f; + style.ScrollbarSize = 9.f; + style.ScrollbarRounding = 0.f; + style.WindowBorderSize = 0.f; + style.WindowMinSize = { 100, 100 }; + style.WindowPadding = { 0, 0 }; + style.WindowRounding = 3.f; +} + +void CRender::Initialize(IDirect3DDevice9* pDevice) +{ + while (!WndProc::hwWindow) + WndProc::hwWindow = SDK::GetTeamFortressWindow(); + + // Initialize ImGui and device + ImGui::CreateContext(); + ImGui_ImplWin32_Init(WndProc::hwWindow); + ImGui_ImplDX9_Init(pDevice); + + // Fonts + { + const auto& io = ImGui::GetIO(); + + ImFontConfig fontConfig; + fontConfig.OversampleH = 2; + constexpr ImWchar fontRange[]{ 0x0020, 0x00FF, 0x0400, 0x044F, 0 }; // Basic Latin, Latin Supplement and Cyrillic + + FontSmall = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 11.f, &fontConfig, fontRange); + FontRegular = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 13.f, &fontConfig, fontRange); + FontBold = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 13.f, &fontConfig, fontRange); + FontLarge = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 15.f, &fontConfig, fontRange); + FontBlack = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 15.f, &fontConfig, fontRange); + FontTitle = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 20.f, &fontConfig, fontRange); + FontMono = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\verdana.ttf)", 15.f, &fontConfig, fontRange); + + //FontSmall = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 11.f, &fontConfig, fontRange); + //FontRegular = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 13.f, &fontConfig, fontRange); + //FontBold = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoBold_compressed_data, RobotoBold_compressed_size, 13.f, &fontConfig, fontRange); + //FontLarge = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 15.f, &fontConfig, fontRange); + //FontBlack = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoBlack_compressed_data, RobotoBlack_compressed_size, 15.f, &fontConfig, fontRange); + //FontTitle = io.Fonts->AddFontFromMemoryCompressedTTF(RobotoMedium_compressed_data, RobotoMedium_compressed_size, 20.f, &fontConfig, fontRange); + //FontMono = io.Fonts->AddFontFromMemoryCompressedTTF(CascadiaMono_compressed_data, CascadiaMono_compressed_size, 15.f, &fontConfig, fontRange); + + ImFontConfig iconConfig; + iconConfig.PixelSnapH = true; + constexpr ImWchar iconRange[]{ short(ICON_MIN_MD), short(ICON_MAX_MD), 0 }; + + IconFontRegular = io.Fonts->AddFontFromMemoryCompressedTTF(MaterialIcons_compressed_data, MaterialIcons_compressed_size, 15.f, &iconConfig, iconRange); + IconFontLarge = io.Fonts->AddFontFromMemoryCompressedTTF(MaterialIcons_compressed_data, MaterialIcons_compressed_size, 16.f, &iconConfig, iconRange); + + io.Fonts->Build(); + } + + LoadStyle(); +} \ No newline at end of file diff --git a/Amalgam/src/Features/ImGui/Render.h b/Amalgam/src/Features/ImGui/Render.h new file mode 100644 index 0000000..91b2e4a --- /dev/null +++ b/Amalgam/src/Features/ImGui/Render.h @@ -0,0 +1,40 @@ +#pragma once +#include "../../SDK/SDK.h" +#include +#include + +class CRender +{ +public: + void Render(IDirect3DDevice9* pDevice); + void Initialize(IDirect3DDevice9* pDevice); + + void LoadColors(); + void LoadStyle(); + + int Cursor = 2; + + // Colors + ImColor Accent = { 255, 101, 101 }; + ImColor AccentLight = { 255, 111, 111 }; + ImColor Background = { 23, 23, 23, 250 }; + ImColor Foreground = { 11, 11, 11, 250 }; + ImColor Foremost = { 23, 23, 23, 250 }; + ImColor ForemostLight = { 25, 25, 25, 250 }; + ImColor Inactive = { 150, 150, 150 }; + ImColor Active = { 255, 255, 255 }; + + // Fonts + ImFont* FontSmall = nullptr; + ImFont* FontRegular = nullptr; + ImFont* FontBold = nullptr; + ImFont* FontLarge = nullptr; + ImFont* FontBlack = nullptr; + ImFont* FontTitle = nullptr; + ImFont* FontMono = nullptr; + + ImFont* IconFontRegular = nullptr; + ImFont* IconFontLarge = nullptr; +}; + +ADD_FEATURE(CRender, Render); \ No newline at end of file diff --git a/Amalgam/src/Features/Misc/Misc.cpp b/Amalgam/src/Features/Misc/Misc.cpp new file mode 100644 index 0000000..064722f --- /dev/null +++ b/Amalgam/src/Features/Misc/Misc.cpp @@ -0,0 +1,662 @@ +#include "Misc.h" + +#include "../Backtrack/Backtrack.h" +#include "../CheaterDetection/CheaterDetection.h" +#include "../PacketManip/AntiAim/AntiAim.h" +#include "../TickHandler/TickHandler.h" +#include "../Players/PlayerUtils.h" + +void CMisc::RunPre(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + CheatsBypass(); + PingReducer(); + WeaponSway(); + + if (!pLocal) + return; + + AntiAFK(pLocal, pCmd); + InstantRespawnMVM(pLocal); + + if (!pLocal->IsAlive() || pLocal->IsAGhost() || pLocal->m_MoveType() != MOVETYPE_WALK || pLocal->IsSwimming() || pLocal->IsCharging() || pLocal->IsInBumperKart()) + return; + + AutoJump(pLocal, pCmd); + AutoJumpbug(pLocal, pCmd); + AutoStrafe(pLocal, pCmd); + AntiBackstab(pLocal, pCmd); + AutoPeek(pLocal, pCmd); +} + +void CMisc::RunPost(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket) +{ + if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost() || pLocal->m_MoveType() != MOVETYPE_WALK || pLocal->IsSwimming() || pLocal->IsCharging()) + return; + + TauntKartControl(pLocal, pCmd); + FastMovement(pLocal, pCmd); + AntiWarp(pLocal, pCmd); + LegJitter(pLocal, pCmd, pSendPacket); +} + + + +void CMisc::AutoJump(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!Vars::Misc::Movement::Bunnyhop.Value) + return; + + static bool bStaticJump = false, bStaticGrounded = false, bLastAttempted = false; + const bool bLastJump = bStaticJump, bLastGrounded = bStaticGrounded; + const bool bCurJump = bStaticJump = pCmd->buttons & IN_JUMP, bCurGrounded = bStaticGrounded = pLocal->OnSolid(); + + if (bCurJump && bLastJump) + { + if (!(bCurGrounded && !bLastGrounded)) + pCmd->buttons &= ~IN_JUMP; + + if (!(pCmd->buttons & IN_JUMP) && bCurGrounded && !bLastAttempted) + pCmd->buttons |= IN_JUMP; + } + + bLastAttempted = pCmd->buttons & IN_JUMP; +} + +void CMisc::AutoJumpbug(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!Vars::Misc::Movement::AutoJumpbug.Value || !(pCmd->buttons & IN_DUCK) || pLocal->OnSolid() || pLocal->m_vecVelocity().z > -650.f) + return; + + CGameTrace trace; + CTraceFilterWorldAndPropsOnly filter = {}; + filter.pSkip = pLocal; + + Vec3 origin = pLocal->m_vecOrigin(); + SDK::TraceHull(origin, origin - Vec3(0, 0, 22), pLocal->m_vecMins(), pLocal->m_vecMaxs(), MASK_PLAYERSOLID, &filter, &trace); + if (!trace.DidHit()) // don't try if we aren't in range to unduck + return; + + const float flDist = origin.DistTo(trace.endpos); + if (20.f < flDist /*&& flDist < 22.f*/) // this seems to be the range where this works + { + pCmd->buttons &= ~IN_DUCK; + pCmd->buttons |= IN_JUMP; + } +} + +void CMisc::AutoStrafe(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!Vars::Misc::Movement::AutoStrafe.Value || pLocal->OnSolid() || !(pLocal->m_afButtonLast() & IN_JUMP) && (pCmd->buttons & IN_JUMP)) + return; + + switch (Vars::Misc::Movement::AutoStrafe.Value) + { + case 1: + { + static auto cl_sidespeed = U::ConVars.FindVar("cl_sidespeed"); + const float flSideSpeed = cl_sidespeed ? cl_sidespeed->GetFloat() : 450.f; + + if (pCmd->mousedx) + { + pCmd->forwardmove = 0.f; + pCmd->sidemove = pCmd->mousedx > 0 ? flSideSpeed : -flSideSpeed; + } + break; + } + case 2: + { + //credits: KGB + if (!(pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT))) + break; + + float flForwardMove = pCmd->forwardmove; + float flSideMove = pCmd->sidemove; + + Vec3 vForward = {}, vRight = {}; + Math::AngleVectors(pCmd->viewangles, &vForward, &vRight, nullptr); + + vForward.z = vRight.z = 0.f; + + vForward.Normalize(); + vRight.Normalize(); + + Vec3 vWishDir = {}; + Math::VectorAngles({ (vForward.x * flForwardMove) + (vRight.x * flSideMove), (vForward.y * flForwardMove) + (vRight.y * flSideMove), 0.f }, vWishDir); + + Vec3 vCurDir = {}; + Math::VectorAngles(pLocal->m_vecVelocity(), vCurDir); + + float flDirDelta = Math::NormalizeAngle(vWishDir.y - vCurDir.y); + float flTurnScale = Math::RemapValClamped(Vars::Misc::Movement::AutoStrafeTurnScale.Value, 0.f, 1.f, 0.9f, 1.f); + float flRotation = DEG2RAD((flDirDelta > 0.f ? -90.f : 90.f) + (flDirDelta * flTurnScale)); + + float flCosRot = cosf(flRotation); + float flSinRot = sinf(flRotation); + + pCmd->forwardmove = (flCosRot * flForwardMove) - (flSinRot * flSideMove); + pCmd->sidemove = (flSinRot * flForwardMove) + (flCosRot * flSideMove); + } + } +} + +void CMisc::AntiBackstab(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + G::Busy = false; + if (!Vars::Misc::Automation::AntiBackstab.Value || G::IsAttacking || pLocal->IsInBumperKart() || !Vars::Misc::Automation::AntiBackstab.Value) + return; + + std::vector vTargets = {}; + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ENEMIES)) + { + auto pPlayer = pEntity->As(); + if (!pPlayer->IsAlive() || pPlayer->IsAGhost() || pPlayer->IsCloaked() || pPlayer->m_bFeignDeathReady()) + continue; + + if (auto pWeapon = pPlayer->m_hActiveWeapon().Get()->As()) + { + if (pWeapon->m_iWeaponID() != TF_WEAPON_KNIFE) + continue; + } + + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) && F::PlayerUtils.IsIgnored(pi.friendsID)) + continue; + + Vec3 vTargetPos = pPlayer->m_vecOrigin() + pPlayer->m_vecVelocity() * F::Backtrack.GetReal(); + if (pLocal->m_vecOrigin().DistTo(vTargetPos) > 200.f || !SDK::VisPos(pLocal, pPlayer, pLocal->m_vecOrigin(), vTargetPos)) + continue; + + vTargets.push_back(vTargetPos); + } + + std::sort(vTargets.begin(), vTargets.end(), [&](const auto& a, const auto& b) -> bool + { + return pLocal->m_vecOrigin().DistTo(a) < pLocal->m_vecOrigin().DistTo(b); + }); + + auto vTargetPos = vTargets.begin(); + if (vTargetPos != vTargets.end()) + { + const Vec3 vAngleTo = Math::CalcAngle(pLocal->m_vecOrigin(), *vTargetPos); + G::Busy = true; + SDK::FixMovement(pCmd, vAngleTo); + pCmd->viewangles.y = vAngleTo.y; + } +} + +void CMisc::AutoPeek(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + static bool bPosPlaced = false; + static bool bReturning = false; + + if (Vars::CL_Move::AutoPeek.Value) + { + const Vec3 localPos = pLocal->GetAbsOrigin(); + + // We just started peeking. Save the return position! + if (!bPosPlaced) + { + if (pLocal->OnSolid()) + { + vPeekReturnPos = localPos; + bPosPlaced = true; + } + } + else + { + static Timer particleTimer{}; + if (particleTimer.Run(700)) + H::Particles.DispatchParticleEffect("ping_circle", vPeekReturnPos, {}); + } + + // We've just attacked. Let's return! + if (G::LastUserCmd->buttons & IN_ATTACK || G::IsAttacking) + bReturning = true; + + if (bReturning) + { + if (localPos.DistTo(vPeekReturnPos) < 7.f) + { + bReturning = false; + return; + } + + SDK::WalkTo(pCmd, pLocal, vPeekReturnPos); + } + } + else + { + bPosPlaced = bReturning = false; + vPeekReturnPos = Vec3(); + } +} + +void CMisc::AntiAFK(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + static Timer afkTimer{}; + + static auto mp_idledealmethod = U::ConVars.FindVar("mp_idledealmethod"); + static auto mp_idlemaxtime = U::ConVars.FindVar("mp_idlemaxtime"); + const int iIdleMethod = mp_idledealmethod ? mp_idledealmethod->GetInt() : 1; + const float flMaxIdleTime = mp_idlemaxtime ? mp_idlemaxtime->GetFloat() : 3.f; + + if (pCmd->buttons & (IN_MOVELEFT | IN_MOVERIGHT | IN_FORWARD | IN_BACK) || !pLocal->IsAlive()) + afkTimer.Update(); + // Trigger 10 seconds before kick + else if (Vars::Misc::Automation::AntiAFK.Value && iIdleMethod && afkTimer.Check(flMaxIdleTime * 60 * 1000 - 10000)) + pCmd->buttons |= pCmd->command_number % 2 ? IN_FORWARD : IN_BACK; +} + +void CMisc::InstantRespawnMVM(CTFPlayer* pLocal) +{ + if (Vars::Misc::MannVsMachine::InstantRespawn.Value && I::EngineClient->IsInGame() && !pLocal->IsAlive()) + { + auto kv = new KeyValues("MVM_Revive_Response"); + kv->SetInt("accepted", 1); + I::EngineClient->ServerCmdKeyValues(kv); + } +} + +void CMisc::CheatsBypass() +{ + static bool bCheatSet = false; + static auto sv_cheats = U::ConVars.FindVar("sv_cheats"); + if (sv_cheats) + { + if (Vars::Misc::Exploits::CheatsBypass.Value) + { + sv_cheats->m_nValue = 1; + bCheatSet = true; + } + else if (bCheatSet) + { + sv_cheats->m_nValue = 0; + bCheatSet = false; + } + } +} + +void CMisc::PingReducer() +{ + auto pNetChan = reinterpret_cast(I::EngineClient->GetNetChannelInfo()); + if (!pNetChan) + return; + + static auto cl_cmdrate = U::ConVars.FindVar("cl_cmdrate"); + const int iCmdRate = cl_cmdrate ? cl_cmdrate->GetInt() : 66; + + static Timer updateRateTimer{}; + if (updateRateTimer.Run(100)) + { + const int iTarget = Vars::Misc::Exploits::PingReducer.Value ? Vars::Misc::Exploits::PingTarget.Value : iCmdRate; + if (iTarget == iLastCmdrate) + return; + iLastCmdrate = iTarget; + + SDK::Output("SendNetMsg", std::format("cl_cmdrate: {}", iTarget).c_str(), { 224, 255, 131, 255 }, Vars::Debug::Logging.Value); + + NET_SetConVar cmd("cl_cmdrate", std::to_string(iTarget).c_str()); + pNetChan->SendNetMsg(cmd); + } +} + +void CMisc::WeaponSway() +{ + static auto cl_wpn_sway_interp = U::ConVars.FindVar("cl_wpn_sway_interp"); + static auto cl_wpn_sway_scale = U::ConVars.FindVar("cl_wpn_sway_scale"); + if (cl_wpn_sway_interp) + cl_wpn_sway_interp->SetValue(Vars::Visuals::Viewmodel::Sway.Value ? Vars::Visuals::Viewmodel::SwayInterp.Value : 0.f); + if (cl_wpn_sway_scale) + cl_wpn_sway_scale->SetValue(Vars::Visuals::Viewmodel::Sway.Value ? Vars::Visuals::Viewmodel::SwayScale.Value : 0.f); +} + + + +void CMisc::TauntKartControl(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + // Handle Taunt Slide + if (Vars::Misc::Automation::TauntControl.Value && pLocal->IsTaunting()) + { + if (pCmd->buttons & IN_FORWARD) + { + pCmd->forwardmove = 450.f; + pCmd->viewangles.x = 0.f; + } + if (pCmd->buttons & IN_BACK) + { + pCmd->forwardmove = 450.f; + pCmd->viewangles.x = 91.f; + } + if (pCmd->buttons & IN_MOVELEFT) + pCmd->sidemove = -450.f; + if (pCmd->buttons & IN_MOVERIGHT) + pCmd->sidemove = 450.f; + + if (!(pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT))) + pCmd->viewangles.x = 90.f; + + Vec3 vAngle = I::EngineClient->GetViewAngles(); + pCmd->viewangles.y = vAngle.y; + + G::SilentAngles = true; + } + else if (Vars::Misc::Automation::KartControl.Value && pLocal->IsInBumperKart()) + { + const bool bForward = pCmd->buttons & IN_FORWARD; + const bool bBack = pCmd->buttons & IN_BACK; + const bool bLeft = pCmd->buttons & IN_MOVELEFT; + const bool bRight = pCmd->buttons & IN_MOVERIGHT; + + const bool flipVar = pCmd->command_number % 2; + if (bForward && (!bLeft && !bRight || !flipVar)) + { + pCmd->forwardmove = 450.f; + pCmd->viewangles.x = 0.f; + } + else if (bBack && (!bLeft && !bRight || !flipVar)) + { + pCmd->forwardmove = 450.f; + pCmd->viewangles.x = 91.f; + } + else if (pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT)) + { + if (flipVar) + { // you could just do this if you didn't care about viewangles + const Vec3 vecMove(pCmd->forwardmove, pCmd->sidemove, 0.f); + const float flLength = vecMove.Length(); + Vec3 angMoveReverse; + Math::VectorAngles(vecMove * -1.f, angMoveReverse); + pCmd->forwardmove = -flLength; + pCmd->sidemove = 0.f; + pCmd->viewangles.y = fmodf(pCmd->viewangles.y - angMoveReverse.y, 360.f); + pCmd->viewangles.z = 270.f; + G::PSilentAngles = true; + } + } + else + pCmd->viewangles.x = 90.f; + + G::SilentAngles = true; + } +} + +void CMisc::FastMovement(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!pLocal->OnSolid() || pLocal->IsInBumperKart()) + return; + + const float flSpeed = pLocal->m_vecVelocity().Length2D(); + const int flMaxSpeed = std::min(pLocal->m_flMaxspeed() * 0.9f, 520.f) - 10.f; + const int iRun = !pCmd->forwardmove && !pCmd->sidemove ? 0 : flSpeed < flMaxSpeed ? 1 : 2; + + switch (iRun) + { + case 0: + { + if (!Vars::Misc::Movement::FastStop.Value || !flSpeed) + return; + + if (G::ShiftedTicks != G::MaxShift && !G::IsAttacking && !G::AntiAim) + { + if (!SDK::StopMovement(pLocal, pCmd)) + return; + + if (!G::Recharge && !G::DoubleTap) + G::PSilentAngles = true; + else + G::SilentAngles = true; + } + else + { + Vec3 direction = pLocal->m_vecVelocity().toAngle(); + direction.y = pCmd->viewangles.y - direction.y; + const Vec3 negatedDirection = direction.fromAngle() * -flSpeed; + pCmd->forwardmove = negatedDirection.x; + pCmd->sidemove = negatedDirection.y; + } + + break; + } + case 1: + { + if ((pLocal->IsDucking() ? !Vars::Misc::Movement::CrouchSpeed.Value : !Vars::Misc::Movement::FastAccel.Value) || G::IsAttacking || G::DoubleTap || G::Recharge || G::AntiAim || pCmd->command_number % 2) + return; + + if (!(pCmd->buttons & (IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT))) + return; + + const Vec3 vecMove(pCmd->forwardmove, pCmd->sidemove, 0.f); + const float flLength = vecMove.Length(); + Vec3 angMoveReverse; + Math::VectorAngles(vecMove * -1.f, angMoveReverse); + pCmd->forwardmove = -flLength; + pCmd->sidemove = 0.f; + pCmd->viewangles.y = fmodf(pCmd->viewangles.y - angMoveReverse.y, 360.f); + pCmd->viewangles.z = 270.f; + G::PSilentAngles = true; + + break; + } + case 2: + { + if (!Vars::Misc::Movement::FastStrafe.Value || G::IsAttacking) + return; + + static bool bFwd = pCmd->forwardmove > 0; + static bool bSde = pCmd->sidemove > 0; + const bool bCurFwd = pCmd->forwardmove > 0; + const bool bCurSde = pCmd->sidemove > 0; + + bool bChanged = false; + if (fabsf(pCmd->sidemove) > 400) + { + if (bSde != bCurSde) + { + pCmd->viewangles.x = 90.f; + pCmd->viewangles.y += bSde ? -90.f : 90.f; + pCmd->sidemove = bSde ? -pCmd->forwardmove : pCmd->forwardmove; + + G::PSilentAngles = bChanged = true; + } + + bSde = bCurSde; + if (bChanged) + return; + } + if (fabsf(pCmd->forwardmove) > 400) + { + if (bFwd != bCurFwd) + { + pCmd->viewangles.x = 90.f; + pCmd->viewangles.y += bFwd ? 0.f : 180.f; + pCmd->sidemove *= bFwd ? 1 : -1; + + G::PSilentAngles = bChanged = true; + } + + bFwd = bCurFwd; + if (bChanged) + return; + } + } + } +} + +void CMisc::AntiWarp(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + static Vec3 vVelocity = {}; + if (G::AntiWarp) + { + const int iDoubletapTicks = F::Ticks.GetTicks(pLocal); + + Vec3 angles = {}; Math::VectorAngles(vVelocity, angles); + angles.y = pCmd->viewangles.y - angles.y; + Vec3 forward = {}; Math::AngleVectors(angles, &forward); + forward *= vVelocity.Length(); + + if (iDoubletapTicks > std::max(Vars::CL_Move::Doubletap::TickLimit.Value - 8, 3)) + { + pCmd->forwardmove = -forward.x; + pCmd->sidemove = -forward.y; + } + else if (iDoubletapTicks > 3) + { + pCmd->forwardmove = pCmd->sidemove = 0.f; + pCmd->buttons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT); + } + else + { + pCmd->forwardmove = forward.x; + pCmd->sidemove = forward.y; + } + } + else + vVelocity = pLocal->m_vecVelocity(); +} + +void CMisc::LegJitter(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket) +{ + if (!Vars::AntiHack::AntiAim::MinWalk.Value || !F::AntiAim.YawOn() || G::IsAttacking || G::DoubleTap || pSendPacket || !pLocal->OnSolid() || pLocal->IsInBumperKart()) + return; + + static bool pos = true; + const float scale = pLocal->IsDucking() ? 14.f : 1.f; + if (pCmd->forwardmove == 0.f && pCmd->sidemove == 0.f && pLocal->m_vecVelocity().Length2D() < 10.f) + { + pos ? pCmd->forwardmove = scale : pCmd->forwardmove = -scale; + pos ? pCmd->sidemove = scale : pCmd->sidemove = -scale; + pos = !pos; + } +} + + + +void CMisc::Event(IGameEvent* pEvent, FNV1A_t uHash) +{ + switch (uHash) + { + case FNV1A::HashConst("teamplay_round_start"): + case FNV1A::HashConst("client_disconnect"): + case FNV1A::HashConst("client_beginconnect"): + case FNV1A::HashConst("game_newmap"): + iLastCmdrate = -1; + F::Backtrack.flWishInterp = 0.f; + + G::BulletsStorage.clear(); + G::BoxesStorage.clear(); + G::LinesStorage.clear(); + } +} + +void CMisc::DoubletapPacket(CUserCmd* pCmd, bool* pSendPacket) +{ + if (G::DoubleTap || G::Warp) + { + *pSendPacket = G::ShiftedGoal == G::ShiftedTicks; + if ((G::DoubleTap || pCmd->buttons & IN_ATTACK) && I::ClientState->chokedcommands >= 21) + *pSendPacket = true; + } +} + +void CMisc::DetectChoke() +{ + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + if (!pEntity->As()->IsAlive() || pEntity->IsDormant()) + { + G::ChokeMap[pEntity->entindex()] = 0; + continue; + } + + if (pEntity->m_flSimulationTime() == pEntity->m_flOldSimulationTime()) + G::ChokeMap[pEntity->entindex()]++; + else + { + F::CheaterDetection.ReportChoke(pEntity->As(), G::ChokeMap[pEntity->entindex()]); + G::ChokeMap[pEntity->entindex()] = 0; + } + } +} + +void CMisc::UnlockAchievements() +{ + const auto achievementmgr = reinterpret_cast(U::Memory.GetVFunc(I::EngineClient, 114))(); + if (achievementmgr) + { + I::SteamUserStats->RequestCurrentStats(); + for (int i = 0; i < achievementmgr->GetAchievementCount(); i++) + achievementmgr->AwardAchievement(achievementmgr->GetAchievementByIndex(i)->GetAchievementID()); + I::SteamUserStats->StoreStats(); + I::SteamUserStats->RequestCurrentStats(); + } +} + +void CMisc::LockAchievements() +{ + const auto achievementmgr = reinterpret_cast(U::Memory.GetVFunc(I::EngineClient, 114))(); + if (achievementmgr) + { + I::SteamUserStats->RequestCurrentStats(); + for (int i = 0; i < achievementmgr->GetAchievementCount(); i++) + I::SteamUserStats->ClearAchievement(achievementmgr->GetAchievementByIndex(i)->GetName()); + I::SteamUserStats->StoreStats(); + I::SteamUserStats->RequestCurrentStats(); + } +} + +bool CMisc::SteamRPC() +{ + /* + if (!Vars::Misc::Steam::EnableRPC.Value) + { + if (!bSteamCleared) // stupid way to return back to normal rpc + { + I::SteamFriends->SetRichPresence("steam_display", ""); // this will only make it say "Team Fortress 2" until the player leaves/joins some server. its bad but its better than making 1000 checks to recreate the original + bSteamCleared = true; + } + return false; + } + + bSteamCleared = false; + */ + + + if (!Vars::Misc::Steam::EnableRPC.Value) + return false; + + I::SteamFriends->SetRichPresence("steam_display", "#TF_RichPresence_Display"); + if (!I::EngineClient->IsInGame() && !Vars::Misc::Steam::OverrideMenu.Value) + I::SteamFriends->SetRichPresence("state", "MainMenu"); + else + { + I::SteamFriends->SetRichPresence("state", "PlayingMatchGroup"); + + switch (Vars::Misc::Steam::MatchGroup.Value) + { + case 0: I::SteamFriends->SetRichPresence("matchgrouploc", "SpecialEvent"); break; + case 1: I::SteamFriends->SetRichPresence("matchgrouploc", "MannUp"); break; + case 2: I::SteamFriends->SetRichPresence("matchgrouploc", "Competitive6v6"); break; + case 3: I::SteamFriends->SetRichPresence("matchgrouploc", "Casual"); break; + case 4: I::SteamFriends->SetRichPresence("matchgrouploc", "BootCamp"); break; + default: I::SteamFriends->SetRichPresence("matchgrouploc", "SpecialEvent"); break; + } + } + I::SteamFriends->SetRichPresence("currentmap", Vars::Misc::Steam::MapText.Value.empty() ? "Fedoraware" : Vars::Misc::Steam::MapText.Value.c_str()); + I::SteamFriends->SetRichPresence("steam_player_group_size", std::to_string(Vars::Misc::Steam::GroupSize.Value).c_str()); + + return true; +} + +#ifdef DEBUG +void CMisc::DumpClassIDS() { + std::ofstream fDump("CLASSIDDUMP.txt"); + fDump << "enum struct ETFClassID\n{\n"; + CClientClass* ClientClass = I::BaseClientDLL->GetAllClasses(); + while (ClientClass) { + fDump << " " << ClientClass->GetName() << " = " << ClientClass->m_ClassID << ",\n"; + ClientClass = ClientClass->m_pNext; + } + fDump << "}"; + fDump.close(); +} +#endif \ No newline at end of file diff --git a/Amalgam/src/Features/Misc/Misc.h b/Amalgam/src/Features/Misc/Misc.h new file mode 100644 index 0000000..963ca0a --- /dev/null +++ b/Amalgam/src/Features/Misc/Misc.h @@ -0,0 +1,48 @@ +#pragma once +#include "../../SDK/SDK.h" + +#ifdef DEBUG +#include +#include +#endif + +class CMisc +{ + void AutoJump(CTFPlayer* pLocal, CUserCmd* pCmd); + void AutoJumpbug(CTFPlayer* pLocal, CUserCmd* pCmd); + void AutoStrafe(CTFPlayer* pLocal, CUserCmd* pCmd); + void AntiBackstab(CTFPlayer* pLocal, CUserCmd* pCmd); + void AutoPeek(CTFPlayer* pLocal, CUserCmd* pCmd); + void AntiAFK(CTFPlayer* pLocal, CUserCmd* pCmd); + void InstantRespawnMVM(CTFPlayer* pLocal); + + void CheatsBypass(); + void PingReducer(); + void WeaponSway(); + + void TauntKartControl(CTFPlayer* pLocal, CUserCmd* pCmd); + void FastMovement(CTFPlayer* pLocal, CUserCmd* pCmd); + void AntiWarp(CTFPlayer* pLocal, CUserCmd* pCmd); + void LegJitter(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket); + + int iLastCmdrate = -1; + Vec3 vPeekReturnPos = {}; + //bool bSteamCleared = false; + +public: + void RunPre(CTFPlayer* pLocal, CUserCmd* pCmd); + void RunPost(CTFPlayer* pLocal, CUserCmd* pCmd, bool pSendPacket); + void Event(IGameEvent* pEvent, FNV1A_t uNameHash); + void DoubletapPacket(CUserCmd* pCmd, bool* pSendPacket); + void DetectChoke(); + + void UnlockAchievements(); + void LockAchievements(); + bool SteamRPC(); + +#ifdef DEBUG + void DumpClassIDS(); +#endif +}; + +ADD_FEATURE(CMisc, Misc) diff --git a/Amalgam/src/Features/NetworkFix/NetworkFix.cpp b/Amalgam/src/Features/NetworkFix/NetworkFix.cpp new file mode 100644 index 0000000..624145d --- /dev/null +++ b/Amalgam/src/Features/NetworkFix/NetworkFix.cpp @@ -0,0 +1,52 @@ +#include "NetworkFix.h" + +void CReadPacketState::Store() +{ + m_flFrameTimeClientState = I::ClientState->m_frameTime; + m_flFrameTime = I::GlobalVars->frametime; + m_flCurTime = I::GlobalVars->curtime; + m_nTickCount = I::GlobalVars->tickcount; +} + +void CReadPacketState::Restore() +{ + I::ClientState->m_frameTime = m_flFrameTimeClientState; + I::GlobalVars->frametime = m_flFrameTime; + I::GlobalVars->curtime = m_flCurTime; + I::GlobalVars->tickcount = m_nTickCount; +} + +void CNetworkFix::FixInputDelay(bool bFinalTick) +{ + static auto CL_ReadPackets = U::Hooks.m_mHooks["CL_ReadPackets"]; + if (!I::EngineClient->IsInGame() || !Vars::Misc::Game::NetworkFix.Value || !CL_ReadPackets) + return; + + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (pNetChan && pNetChan->IsLoopback()) + return; + + CReadPacketState Backup = {}; + + Backup.Store(); + + CL_ReadPackets->Original()(bFinalTick); + + m_State.Store(); + + Backup.Restore(); +} + +bool CNetworkFix::ShouldReadPackets() +{ + if (!I::EngineClient->IsInGame() || !Vars::Misc::Game::NetworkFix.Value) + return true; + + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (pNetChan && pNetChan->IsLoopback()) + return true; + + m_State.Restore(); + + return false; +} \ No newline at end of file diff --git a/Amalgam/src/Features/NetworkFix/NetworkFix.h b/Amalgam/src/Features/NetworkFix/NetworkFix.h new file mode 100644 index 0000000..31417b9 --- /dev/null +++ b/Amalgam/src/Features/NetworkFix/NetworkFix.h @@ -0,0 +1,27 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CReadPacketState +{ +private: + float m_flFrameTimeClientState = 0.f; + float m_flFrameTime = 0.f; + float m_flCurTime = 0.f; + int m_nTickCount = 0; + +public: + void Store(); + void Restore(); +}; + +class CNetworkFix +{ +private: + CReadPacketState m_State = {}; + +public: + void FixInputDelay(bool bFinalTick); + bool ShouldReadPackets(); +}; + +ADD_FEATURE(CNetworkFix, NetworkFix); \ No newline at end of file diff --git a/Amalgam/src/Features/NoSpread/NoSpread.cpp b/Amalgam/src/Features/NoSpread/NoSpread.cpp new file mode 100644 index 0000000..b00e88a --- /dev/null +++ b/Amalgam/src/Features/NoSpread/NoSpread.cpp @@ -0,0 +1,33 @@ +#include "NoSpread.h" + +#include "NoSpreadProjectile/NoSpreadProjectile.h" +#include "NoSpreadHitscan/NoSpreadHitscan.h" + +bool CNoSpread::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (!Vars::Aimbot::General::NoSpread.Value) + return false; + + if (!pLocal || !pWeapon + || !pLocal->IsAlive() + || pLocal->IsTaunting() + || pLocal->IsBonked() + || pLocal->m_bFeignDeathReady() + || pLocal->IsCloaked() + || pLocal->IsInBumperKart() + || pLocal->IsAGhost()) + { + return false; + } + + return true; +} + +void CNoSpread::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (!ShouldRun(pLocal, pWeapon)) + return; + + F::NoSpreadHitscan.Run(pLocal, pWeapon, pCmd); + F::NoSpreadProjectile.Run(pLocal, pWeapon, pCmd); +} \ No newline at end of file diff --git a/Amalgam/src/Features/NoSpread/NoSpread.h b/Amalgam/src/Features/NoSpread/NoSpread.h new file mode 100644 index 0000000..b0af79e --- /dev/null +++ b/Amalgam/src/Features/NoSpread/NoSpread.h @@ -0,0 +1,13 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CNoSpread +{ +private: + bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CNoSpread, NoSpread) \ No newline at end of file diff --git a/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp new file mode 100644 index 0000000..1e2db12 --- /dev/null +++ b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.cpp @@ -0,0 +1,197 @@ +#include "NoSpreadHitscan.h" + +#include "../../TickHandler/TickHandler.h" +#include +#include + +void CNoSpreadHitscan::Reset(bool bResetPrint) +{ + bWaitingForPlayerPerf = false; + flServerTime = 0.f; + flFloatTimeDelta = 0.f; + + iSeed = 0; + flMantissaStep = 0; + + bSynced = false; + if (bResetPrint) + iBestSync = 0; +} + +bool CNoSpreadHitscan::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bCreateMove) +{ + if (G::WeaponType != EWeaponType::HITSCAN) + return false; + + if (pWeapon->GetWeaponSpread() <= 0.f) + return false; + + return bCreateMove ? G::IsAttacking : true; +} + +int CNoSpreadHitscan::GetSeed(CUserCmd* pCmd) +{ + static auto sv_usercmd_custom_random_seed = U::ConVars.FindVar("sv_usercmd_custom_random_seed"); + if (sv_usercmd_custom_random_seed ? sv_usercmd_custom_random_seed->GetBool() : true) + { + const float flFloatTime = float(SDK::PlatFloatTime()) + flFloatTimeDelta; + //SDK::Output("Seed Prediction", std::format("{}\n", flFloatTime).c_str()); + + const float flTime = (flFloatTime) * 1000; + return std::bit_cast(flTime) & 255; + } + else + return pCmd->random_seed; // i don't think this is right +} + +float CNoSpreadHitscan::CalcMantissaStep(float val) +{ + // Calculate the delta to the next representable value + const float nextValue = std::nextafter(val, std::numeric_limits::infinity()); + const float mantissaStep = (nextValue - val) * 1000; + + // Get the closest mantissa (next power of 2) + return powf(2, ceilf(logf(mantissaStep) / logf(2))); +} + +std::string CNoSpreadHitscan::GetFormat(int m_ServerTime) +{ + const int iDays = m_ServerTime / 86400; + const int iHours = m_ServerTime / 3600 % 24; + const int iMinutes = m_ServerTime / 60 % 60; + const int iSeconds = m_ServerTime % 60; + + if (iDays) + return std::format("{}d {}h", iDays, iHours); + else if (iHours) + return std::format("{}h {}m", iHours, iMinutes); + else + return std::format("{}m {}s", iMinutes, iSeconds); +} + +void CNoSpreadHitscan::AskForPlayerPerf() +{ + if (!Vars::Aimbot::General::NoSpread.Value) + return Reset(); + + static Timer playerperfTimer{}; + if (playerperfTimer.Run(50) && !bWaitingForPlayerPerf && I::EngineClient->IsInGame()) + { + I::EngineClient->ClientCmd_Unrestricted("playerperf"); + bWaitingForPlayerPerf = true; + } +} + +bool CNoSpreadHitscan::ParsePlayerPerf(bf_read& msgData) +{ + if (!Vars::Aimbot::General::NoSpread.Value) + return false; + + char rawMsg[256] = {}; + + msgData.ReadString(rawMsg, sizeof(rawMsg), true); + msgData.Seek(0); + + std::string msg(rawMsg); + msg.erase(msg.begin()); + + std::smatch matches = {}; + std::regex_match(msg, matches, std::regex(R"((\d+.\d+)\s\d+\s\d+\s\d+.\d+\s\d+.\d+\svel\s\d+.\d+)")); + + if (matches.size() == 2) + { + bWaitingForPlayerPerf = false; + + // credits to kgb for idea + const float flNewServerTime = std::stof(matches[1].str()); + if (flNewServerTime < flServerTime) + return true; + + flServerTime = flNewServerTime; + flFloatTimeDelta = flServerTime - float(SDK::PlatFloatTime()); + + flMantissaStep = CalcMantissaStep(flServerTime); + const int iSynced = flMantissaStep < 4.f ? 2 : 1; + bSynced = iSynced == 1; + + if (!iBestSync || iBestSync == 2 && bSynced) + { + iBestSync = iSynced; + SDK::Output("Seed Prediction", bSynced ? std::format("Synced ({})", flFloatTimeDelta).c_str() : "Not synced, step too low", Vars::Menu::Theme::Accent.Value); + SDK::Output("Seed Prediction", std::format("Age {}; Step {}", GetFormat(flServerTime), CalcMantissaStep(flServerTime)).c_str(), Vars::Menu::Theme::Accent.Value); + } + + return true; + } + + return std::regex_match(msg, std::regex(R"(\d+.\d+\s\d+\s\d+)")); +} + +void CNoSpreadHitscan::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + iSeed = GetSeed(pCmd); + if (!bSynced || !ShouldRun(pLocal, pWeapon, true)) + return; + + // credits to cathook for average spread stuff + const float flSpread = pWeapon->GetWeaponSpread(); + auto tfWeaponInfo = pWeapon->GetWeaponInfo(); + int iBulletsPerShot = tfWeaponInfo ? tfWeaponInfo->GetWeaponData(0).m_nBulletsPerShot : 1; + iBulletsPerShot = static_cast(SDK::AttribHookValue(static_cast(iBulletsPerShot), "mult_bullets_per_shot", pWeapon)); + + std::vector vBulletCorrections = {}; + Vec3 vAverageSpread = {}; + for (int iBullet = 0; iBullet < iBulletsPerShot; iBullet++) + { + SDK::RandomSeed(iSeed + iBullet); + + if (!iBullet) // Check if we'll get a guaranteed perfect shot + { + bool bDoubletap = false; // if we are doubletapping and firerate fast enough, prioritize later bullets + int iTicks = F::Ticks.GetTicks(pLocal); + if (iTicks && tfWeaponInfo) + { + float flDoubletapTime = TICKS_TO_TIME(iTicks); + float flFireRate = tfWeaponInfo->GetWeaponData(0).m_flTimeFireDelay; + bDoubletap = flDoubletapTime > flFireRate * 2; + } + + if (!bDoubletap) + { + const float flTimeSinceLastShot = (pLocal->m_nTickBase() * TICK_INTERVAL) - pWeapon->m_flLastFireTime(); + if ((iBulletsPerShot == 1 && flTimeSinceLastShot > 1.25f) || (iBulletsPerShot > 1 && flTimeSinceLastShot > 0.25f)) + return; + } + } + + const float x = SDK::RandomFloat(-0.5f, 0.5f) + SDK::RandomFloat(-0.5f, 0.5f); + const float y = SDK::RandomFloat(-0.5f, 0.5f) + SDK::RandomFloat(-0.5f, 0.5f); + + Vec3 forward, right, up; + Math::AngleVectors(pCmd->viewangles, &forward, &right, &up); + + Vec3 vFixedSpread = forward + (right * x * flSpread) + (up * y * flSpread); + vFixedSpread.Normalize(); + vAverageSpread += vFixedSpread; + + vBulletCorrections.push_back(vFixedSpread); + } + vAverageSpread /= static_cast(iBulletsPerShot); + + const auto cFixedSpread = std::ranges::min_element(vBulletCorrections, + [&](const Vec3& lhs, const Vec3& rhs) + { + return lhs.DistTo(vAverageSpread) < rhs.DistTo(vAverageSpread); + }); + + if (cFixedSpread == vBulletCorrections.end()) + return; + + Vec3 vFixedAngles{}; + Math::VectorAngles(*cFixedSpread, vFixedAngles); + + pCmd->viewangles += pCmd->viewangles - vFixedAngles; + Math::ClampAngles(pCmd->viewangles); + + G::SilentAngles = true; +} \ No newline at end of file diff --git a/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h new file mode 100644 index 0000000..a094c5f --- /dev/null +++ b/Amalgam/src/Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h @@ -0,0 +1,30 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CNoSpreadHitscan +{ +private: + int GetSeed(CUserCmd* pCmd); + float CalcMantissaStep(float val); + +public: + void Reset(bool bResetPrint = false); + bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bCreateMove = false); + + void AskForPlayerPerf(); + bool ParsePlayerPerf(bf_read& msgData); + + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + + std::string GetFormat(int m_ServerTime); + + bool bWaitingForPlayerPerf = false; + int bSynced = 0, iBestSync = 0; + float flServerTime = 0.f; + float flFloatTimeDelta = 0.f; + + int iSeed = 0; + float flMantissaStep = 0; +}; + +ADD_FEATURE(CNoSpreadHitscan, NoSpreadHitscan) \ No newline at end of file diff --git a/Amalgam/src/Features/NoSpread/NoSpreadProjectile/NoSpreadProjectile.cpp b/Amalgam/src/Features/NoSpread/NoSpreadProjectile/NoSpreadProjectile.cpp new file mode 100644 index 0000000..4799f51 --- /dev/null +++ b/Amalgam/src/Features/NoSpread/NoSpreadProjectile/NoSpreadProjectile.cpp @@ -0,0 +1,60 @@ +#include "NoSpreadProjectile.h" + +bool CNoSpreadProjectile::ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) +{ + if (G::WeaponType != EWeaponType::PROJECTILE) + return false; + + switch (G::WeaponDefIndex) + { + case Soldier_m_RocketJumper: + case Demoman_s_StickyJumper: + return false; + } + + return G::IsAttacking; +} + +void CNoSpreadProjectile::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +{ + if (!ShouldRun(pLocal, pWeapon)) + return; + + SDK::RandomSeed(SDK::SeedFileLineHash(MD5_PseudoRandom(pCmd->command_number) & 0x7FFFFFFF, "SelectWeightedSequence", 0)); + for (int i = 0; i < 6; ++i) + SDK::RandomFloat(); + + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_SYRINGEGUN_MEDIC: + { + // don't let the _local_ syringes fool you (is there a way to fix or sync them?) + pCmd->viewangles.x -= SDK::RandomFloat(-1.5f, 1.5f); + pCmd->viewangles.y -= SDK::RandomFloat(-1.5f, 1.5f); + + G::PSilentAngles = true; + return; + } + case TF_WEAPON_COMPOUND_BOW: + { + // ShouldRun huntsman + if (pWeapon->As()->m_flChargeBeginTime() > 0.f && I::GlobalVars->curtime - pWeapon->As()->m_flChargeBeginTime() <= 5.0f) + return; + + float flRand = float(SDK::RandomInt()) / 0x7FFF; + pCmd->viewangles.x -= -6 + flRand * 12.f; + flRand = float(SDK::RandomInt()) / 0x7FFF; + pCmd->viewangles.y -= -6 + flRand * 12.f; + + G::PSilentAngles = true; + return; + } + } + + if (G::WeaponDefIndex == Soldier_m_TheBeggarsBazooka) + { + pCmd->viewangles -= pWeapon->GetSpreadAngles() - I::EngineClient->GetViewAngles(); + + G::PSilentAngles = true; + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/NoSpread/NoSpreadProjectile/NoSpreadProjectile.h b/Amalgam/src/Features/NoSpread/NoSpreadProjectile/NoSpreadProjectile.h new file mode 100644 index 0000000..0e86b12 --- /dev/null +++ b/Amalgam/src/Features/NoSpread/NoSpreadProjectile/NoSpreadProjectile.h @@ -0,0 +1,13 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CNoSpreadProjectile +{ +private: + bool ShouldRun(CTFPlayer* pLocal, CTFWeaponBase* pWeapon); + +public: + void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); +}; + +ADD_FEATURE(CNoSpreadProjectile, NoSpreadProjectile) \ No newline at end of file diff --git a/Amalgam/src/Features/PacketManip/AntiAim/AntiAim.cpp b/Amalgam/src/Features/PacketManip/AntiAim/AntiAim.cpp new file mode 100644 index 0000000..e5996f6 --- /dev/null +++ b/Amalgam/src/Features/PacketManip/AntiAim/AntiAim.cpp @@ -0,0 +1,185 @@ +#include "AntiAim.h" + +#include "../../Players/PlayerUtils.h" + +bool CAntiAim::AntiAimOn() +{ + return Vars::AntiHack::AntiAim::Enabled.Value + && (Vars::AntiHack::AntiAim::PitchReal.Value + || Vars::AntiHack::AntiAim::PitchFake.Value + || Vars::AntiHack::AntiAim::YawReal.Value + || Vars::AntiHack::AntiAim::YawFake.Value + || Vars::AntiHack::AntiAim::RealYawMode.Value + || Vars::AntiHack::AntiAim::FakeYawMode.Value + || Vars::AntiHack::AntiAim::RealYawOffset.Value + || Vars::AntiHack::AntiAim::FakeYawOffset.Value); +} + +bool CAntiAim::YawOn() +{ + return Vars::AntiHack::AntiAim::Enabled.Value + && (Vars::AntiHack::AntiAim::YawReal.Value + || Vars::AntiHack::AntiAim::YawFake.Value + || Vars::AntiHack::AntiAim::RealYawMode.Value + || Vars::AntiHack::AntiAim::FakeYawMode.Value + || Vars::AntiHack::AntiAim::RealYawOffset.Value + || Vars::AntiHack::AntiAim::FakeYawOffset.Value); +} + +bool CAntiAim::ShouldRun(CTFPlayer* pLocal) +{ + const bool bPlayerReady = pLocal->IsAlive() && !pLocal->IsTaunting() && !pLocal->IsInBumperKart() && !pLocal->IsAGhost() && !G::IsAttacking; + const bool bMovementReady = pLocal->m_MoveType() <= 5 && !pLocal->IsCharging(); + + return bPlayerReady && bMovementReady && !G::Busy; +} + + + +void CAntiAim::FakeShotAngles(CUserCmd* pCmd) +{ + if (!Vars::AntiHack::AntiAim::InvalidShootPitch.Value || !G::IsAttacking || G::WeaponType != EWeaponType::HITSCAN) + return; + + G::SilentAngles = true; + pCmd->viewangles.x = CalculateCustomRealPitch(-pCmd->viewangles.x, false) + 180; + pCmd->viewangles.y += 180; +} + +float CAntiAim::EdgeDistance(CTFPlayer* pEntity, float flEdgeRayYaw, float flOffset) +{ + // Main ray tracing area + Vec3 forward, right; + Math::AngleVectors({ 0, flEdgeRayYaw, 0 }, &forward, &right, nullptr); + + Vec3 vCenter = pEntity->GetCenter() + right * flOffset; + Vec3 vEndPos = vCenter + forward * 300.f; + + CGameTrace trace; + CTraceFilterWorldAndPropsOnly filter = {}; + SDK::Trace(vCenter, vEndPos, MASK_SHOT | CONTENTS_GRATE, &filter, &trace); + + vEdgeTrace.push_back({ vCenter, trace.endpos }); + + return (trace.startpos - trace.endpos).Length2D(); +} + +bool CAntiAim::GetEdge(CTFPlayer* pEntity, const float flEdgeOrigYaw, bool bUpPitch) +{ + float flSize = pEntity->m_vecMaxs().y - pEntity->m_vecMins().y; + float flEdgeLeftDist = EdgeDistance(pEntity, flEdgeOrigYaw, -flSize); + float flEdgeRightDist = EdgeDistance(pEntity, flEdgeOrigYaw, flSize); + + if (flEdgeLeftDist > 299.f && flEdgeRightDist > 299.f) + return bUpPitch; + return bUpPitch ? flEdgeLeftDist > flEdgeRightDist : flEdgeLeftDist < flEdgeRightDist; +} + +void CAntiAim::RunOverlapping(CTFPlayer* pEntity, CUserCmd* pCmd, float& flRealYaw, bool bFake, float flEpsilon) +{ + if (!Vars::AntiHack::AntiAim::AntiOverlap.Value || bFake) + return; + + float flFakeYaw = GetBaseYaw(pEntity, pCmd, true) + GetYawOffset(pEntity, true); + const float flYawDiff = RAD2DEG(Math::AngleDiffRad(DEG2RAD(flRealYaw), DEG2RAD(flFakeYaw))); + if (fabsf(flYawDiff) < flEpsilon) + flRealYaw += flYawDiff > 0 ? flEpsilon : -flEpsilon; +} + +float CAntiAim::GetYawOffset(CTFPlayer* pEntity, bool bFake) +{ + const int iMode = bFake ? Vars::AntiHack::AntiAim::YawFake.Value : Vars::AntiHack::AntiAim::YawReal.Value; + const bool bUpPitch = bFake ? Vars::AntiHack::AntiAim::PitchFake.Value == 1 : Vars::AntiHack::AntiAim::PitchReal.Value == 1; + switch (iMode) + { + case 0: return 0.f; + case 1: return 90.f; + case 2: return -90.f; + case 3: return 180.f; + case 4: return fmod(I::GlobalVars->tickcount * Vars::AntiHack::AntiAim::SpinSpeed.Value + 180.f, 360.f) - 180.f; + case 5: return (GetEdge(pEntity, I::EngineClient->GetViewAngles().y, bUpPitch) ? 1 : -1) * (bFake ? -90 : 90); + } + return 0.f; +} + +float CAntiAim::GetBaseYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake) +{ + const int iMode = bFake ? Vars::AntiHack::AntiAim::FakeYawMode.Value : Vars::AntiHack::AntiAim::RealYawMode.Value; + const float flOffset = bFake ? Vars::AntiHack::AntiAim::FakeYawOffset.Value : Vars::AntiHack::AntiAim::RealYawOffset.Value; + switch (iMode) // 0 offset, 1 at player + { + case 0: return pCmd->viewangles.y + flOffset; + case 1: + { + float flSmallestAngleTo = 0.f; float flSmallestFovTo = 360.f; + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ENEMIES)) + { + auto pPlayer = pEntity->As(); + if (!pPlayer->IsAlive() || pPlayer->IsDormant()) + continue; + + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) && F::PlayerUtils.IsIgnored(pi.friendsID)) + continue; + + const Vec3 vAngleTo = Math::CalcAngle(pLocal->GetAbsOrigin(), pPlayer->GetAbsOrigin()); + const float flFOVTo = Math::CalcFov(I::EngineClient->GetViewAngles(), vAngleTo); + + if (flFOVTo < flSmallestFovTo) { flSmallestAngleTo = vAngleTo.y; flSmallestFovTo = flFOVTo; } + } + return (flSmallestFovTo == 360.f ? pCmd->viewangles.y + flOffset : flSmallestAngleTo + flOffset); + } + } + return pCmd->viewangles.y; +} + +float CAntiAim::GetYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake) +{ + float flYaw = GetBaseYaw(pLocal, pCmd, bFake) + GetYawOffset(pLocal, bFake); + RunOverlapping(pLocal, pCmd, flYaw, bFake); + return flYaw; +} + +float CAntiAim::CalculateCustomRealPitch(float flWishPitch, bool bFakeDown) +{ + return bFakeDown ? 720 + flWishPitch : -720 + flWishPitch; +} + +float CAntiAim::GetPitch(float flCurPitch) +{ + const int iFake = Vars::AntiHack::AntiAim::PitchFake.Value, iReal = Vars::AntiHack::AntiAim::PitchReal.Value; + switch (iReal) + { + case 1: return iFake ? CalculateCustomRealPitch(-89.f, iFake - 1) : -89.f; + case 2: return iFake ? CalculateCustomRealPitch(89.f, iFake - 1) : 89.f; + case 3: return iFake ? CalculateCustomRealPitch(0.f, iFake - 1) : 0.f; + } + + return iFake ? -89.f + (89.f * (iFake - 1)) : flCurPitch; +} + + + +void CAntiAim::Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket) +{ + vEdgeTrace.clear(); + G::AntiAim = pLocal && AntiAimOn() && ShouldRun(pLocal); + FakeShotAngles(pCmd); + + if (!G::AntiAim) + { + vRealAngles = { pCmd->viewangles.x, pCmd->viewangles.y }; + vFakeAngles = { pCmd->viewangles.x, pCmd->viewangles.y }; + return; + } + + Vec2& vAngles = *pSendPacket ? vFakeAngles : vRealAngles; + vAngles = { + GetPitch(pCmd->viewangles.x), + GetYaw(pLocal, pCmd, *pSendPacket) + }; + + SDK::FixMovement(pCmd, vAngles); + pCmd->viewangles.x = vAngles.x; + pCmd->viewangles.y = vAngles.y; +} \ No newline at end of file diff --git a/Amalgam/src/Features/PacketManip/AntiAim/AntiAim.h b/Amalgam/src/Features/PacketManip/AntiAim/AntiAim.h new file mode 100644 index 0000000..14bb78e --- /dev/null +++ b/Amalgam/src/Features/PacketManip/AntiAim/AntiAim.h @@ -0,0 +1,31 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CAntiAim +{ +private: + void FakeShotAngles(CUserCmd* pCmd); + + float EdgeDistance(CTFPlayer* pEntity, float flEdgeRayYaw, float flOffset); + void RunOverlapping(CTFPlayer* pEntity, CUserCmd* pCmd, float& flRealYaw, bool bFake, float flEpsilon = 45.f); + float GetYawOffset(CTFPlayer* pEntity, bool bFake); + float GetBaseYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake); + float GetYaw(CTFPlayer* pLocal, CUserCmd* pCmd, bool bFake); + + float CalculateCustomRealPitch(float flWishPitch, bool bFakeDown); + float GetPitch(float flCurPitch); + +public: + bool AntiAimOn(); + bool YawOn(); + bool ShouldRun(CTFPlayer* pLocal); + + bool GetEdge(CTFPlayer* pEntity, float flEdgeOrigYaw, bool bUpPitch); + void Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket); + + Vec2 vFakeAngles = {}; + Vec2 vRealAngles = {}; + std::vector> vEdgeTrace = {}; +}; + +ADD_FEATURE(CAntiAim, AntiAim) \ No newline at end of file diff --git a/Amalgam/src/Features/PacketManip/FakeLag/FakeLag.cpp b/Amalgam/src/Features/PacketManip/FakeLag/FakeLag.cpp new file mode 100644 index 0000000..13ca7c3 --- /dev/null +++ b/Amalgam/src/Features/PacketManip/FakeLag/FakeLag.cpp @@ -0,0 +1,96 @@ +#include "FakeLag.h" + +bool CFakeLag::IsAllowed(CTFPlayer* pLocal) +{ + const int iMaxSend = std::min(24 - G::ShiftedTicks, 22); + const bool bVar = Vars::CL_Move::Fakelag::Fakelag.Value || bPreservingBlast || bUnducking; + const bool bChargePrio = (iMaxSend > 0 && G::ChokeAmount < iMaxSend) || !G::ShiftedTicks; + const bool bAttacking = G::IsAttacking && Vars::CL_Move::Fakelag::UnchokeOnAttack.Value; + const bool bNotAir = Vars::CL_Move::Fakelag::Options.Value & (1 << 2) && !pLocal->OnSolid(); + + if (!bVar || !bChargePrio || bAttacking || bNotAir) + return false; + + if (bPreservingBlast || bUnducking) + return true; + + if (G::ShiftedGoal != G::ShiftedTicks) + return false; + + const bool bMoving = !(Vars::CL_Move::Fakelag::Options.Value & (1 << 0)) || pLocal->m_vecVelocity().Length2D() > 10.f; + if (!bMoving) + return false; + + switch (Vars::CL_Move::Fakelag::Fakelag.Value) + { + case 1: + case 2: + return G::ChokeAmount < G::ChokeGoal; + case 3: + { + const Vec3 vDelta = vLastPosition - pLocal->m_vecOrigin(); + return vDelta.Length2DSqr() < 4096.f; + } + } + + return false; +} + +void CFakeLag::PreserveBlastJump(CTFPlayer* pLocal) +{ + bPreservingBlast = false; + if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost() || !pLocal->IsPlayer() || G::ShiftedTicks == G::MaxShift) + return; + + const bool bVar = Vars::CL_Move::Fakelag::RetainBlastJump.Value && Vars::Misc::Movement::Bunnyhop.Value; + static bool bOldSolid = false; const bool bPlayerReady = pLocal->OnSolid() || bOldSolid; bOldSolid = pLocal->OnSolid(); + const bool bCanPreserve = pLocal->m_iClass() == TF_CLASS_SOLDIER && pLocal->InCond(TF_COND_BLASTJUMPING); + const bool bValid = G::Buttons & IN_JUMP && !pLocal->IsDucking(); + + bPreservingBlast = bVar && bPlayerReady && bCanPreserve && bValid; +} + +void CFakeLag::Unduck(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost()) + return; + + const bool bVar = Vars::CL_Move::Fakelag::Options.Value & (1 << 1); + const bool bPlayerReady = pLocal->IsPlayer() && pLocal->OnSolid() && pLocal->IsDucking() && !(pCmd->buttons & IN_DUCK); + + bUnducking = bVar && bPlayerReady; +} + +void CFakeLag::Prediction(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + PreserveBlastJump(pLocal); + Unduck(pLocal, pCmd); +} + +void CFakeLag::Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket) +{ + if (!pLocal) + return; + + Prediction(pLocal, pCmd); + + // Set the selected choke amount (if not random) + switch (Vars::CL_Move::Fakelag::Fakelag.Value) + { + case 1: G::ChokeGoal = Vars::CL_Move::Fakelag::PlainTicks.Value; break; + case 2: if (!G::ChokeGoal) G::ChokeGoal = SDK::StdRandomInt(Vars::CL_Move::Fakelag::RandomTicks.Value.Min, Vars::CL_Move::Fakelag::RandomTicks.Value.Max); break; + case 3: G::ChokeGoal = 22; break; + } + + // Are we even allowed to choke? + if (!IsAllowed(pLocal)) + { + vLastPosition = pLocal->m_vecOrigin(); + G::ChokeAmount = G::ChokeGoal = 0; + bUnducking = false; + return; + } + + *pSendPacket = false; + G::ChokeAmount++; +} \ No newline at end of file diff --git a/Amalgam/src/Features/PacketManip/FakeLag/FakeLag.h b/Amalgam/src/Features/PacketManip/FakeLag/FakeLag.h new file mode 100644 index 0000000..10dcac2 --- /dev/null +++ b/Amalgam/src/Features/PacketManip/FakeLag/FakeLag.h @@ -0,0 +1,19 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CFakeLag +{ + Vec3 vLastPosition; + bool bPreservingBlast = false; + bool bUnducking = false; + + bool IsAllowed(CTFPlayer* pLocal); + void Prediction(CTFPlayer* pLocal, CUserCmd* pCmd); + void PreserveBlastJump(CTFPlayer* pLocal); + void Unduck(CTFPlayer* pLocal, CUserCmd* pCmd); + +public: + void Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket); +}; + +ADD_FEATURE(CFakeLag, FakeLag) diff --git a/Amalgam/src/Features/PacketManip/PacketManip.cpp b/Amalgam/src/Features/PacketManip/PacketManip.cpp new file mode 100644 index 0000000..0d3cac0 --- /dev/null +++ b/Amalgam/src/Features/PacketManip/PacketManip.cpp @@ -0,0 +1,29 @@ +#include "PacketManip.h" + +#include "../Visuals/FakeAngle/FakeAngle.h" + +bool CPacketManip::WillTimeOut() +{ + return I::ClientState->chokedcommands >= 21; +} + +bool CPacketManip::AntiAimCheck(CTFPlayer* pLocal) +{ + return F::AntiAim.YawOn() && pLocal && F::AntiAim.ShouldRun(pLocal) && I::ClientState->chokedcommands < 3 && !((G::DoubleTap || G::Warp) && G::ShiftedTicks == G::ShiftedGoal); +} + +void CPacketManip::Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket) +{ + F::FakeAngle.DrawChams = Vars::CL_Move::Fakelag::Fakelag.Value || F::AntiAim.AntiAimOn(); + + *pSendPacket = true; + const bool bTimeout = WillTimeOut(); // prevent overchoking by just not running anything below if we believe it will cause us to time out + + if (!bTimeout) + F::FakeLag.Run(pLocal, pCmd, pSendPacket); + else + G::ChokeAmount = 0; + + if (!bTimeout && AntiAimCheck(pLocal) && !G::PSilentAngles) + *pSendPacket = false; +} \ No newline at end of file diff --git a/Amalgam/src/Features/PacketManip/PacketManip.h b/Amalgam/src/Features/PacketManip/PacketManip.h new file mode 100644 index 0000000..f06f56c --- /dev/null +++ b/Amalgam/src/Features/PacketManip/PacketManip.h @@ -0,0 +1,15 @@ +#pragma once +#include "../../SDK/SDK.h" +#include "FakeLag/FakeLag.h" +#include "AntiAim/AntiAim.h" + +class CPacketManip +{ + bool WillTimeOut(); + bool AntiAimCheck(CTFPlayer* pLocal); + +public: + void Run(CTFPlayer* pLocal, CUserCmd* pCmd, bool* pSendPacket); +}; + +ADD_FEATURE(CPacketManip, PacketManip) \ No newline at end of file diff --git a/Amalgam/src/Features/Players/PlayerCore.cpp b/Amalgam/src/Features/Players/PlayerCore.cpp new file mode 100644 index 0000000..88f7077 --- /dev/null +++ b/Amalgam/src/Features/Players/PlayerCore.cpp @@ -0,0 +1,170 @@ +#include "PlayerCore.h" + +#include "PlayerUtils.h" +#include "../Configs/Configs.h" + +void CPlayerlistCore::Run() +{ + static Timer saveTimer{ }; + if (saveTimer.Run(1000)) + { + LoadTags(); + SaveTags(); + LoadPlayers(); + SavePlayers(); + } +} + +void CPlayerlistCore::SavePlayers() +{ + if (!F::PlayerUtils.bSavePlayers) + return; + + try + { + boost::property_tree::ptree writeTree; + + // Put map entries into ptree + for (const auto& [friendsID, vTags] : F::PlayerUtils.mPlayerTags) + { + // don't fill with pointless info + if (!vTags.size()) + continue; + + boost::property_tree::ptree tagTree; + for (const auto& sTag : vTags) + { + boost::property_tree::ptree child; child.put("", sTag); + tagTree.push_back(std::make_pair("", child)); + } + + writeTree.put_child(std::to_string(friendsID), tagTree); + } + + // Save the file + write_json(F::Configs.sConfigPath + "\\Core\\Players.json", writeTree); + + F::PlayerUtils.bSavePlayers = false; + } + catch (...) {} +} + +void CPlayerlistCore::LoadPlayers() +{ + if (!F::PlayerUtils.bLoadPlayers) + return; + + try + { + if (std::filesystem::exists(F::Configs.sConfigPath + "\\Core\\Players.json")) + { + boost::property_tree::ptree readTree; + read_json(F::Configs.sConfigPath + "\\Core\\Players.json", readTree); + F::PlayerUtils.mPlayerTags.clear(); + + for (auto& player : readTree) + { + uint32_t friendsID = std::stoi(player.first); + + for (auto& tag : player.second) + { + std::string sTag = std::string(tag.first.data()).empty() ? tag.second.data() : tag.first.data(); // account for dumb old format + + PriorityLabel_t plTag; + if (F::PlayerUtils.GetTag(sTag, &plTag) && !plTag.Assignable) + continue; + + if (!F::PlayerUtils.HasTag(friendsID, sTag)) + F::PlayerUtils.AddTag(friendsID, sTag, false); + } + } + } + // support legacy format & convert over + if (std::filesystem::exists(F::Configs.sConfigPath + "\\Core\\Playerlist.json")) + { + boost::property_tree::ptree readTree; + read_json(F::Configs.sConfigPath + "\\Core\\Playerlist.json", readTree); + + for (auto& it : readTree) + { + uint32_t friendsID = std::stoi(it.first); + + int iPriority = 2; + if (auto getValue = it.second.get_optional("Mode")) { iPriority = std::max(*getValue, 0); } + + if (iPriority == 4) + F::PlayerUtils.AddTag(friendsID, "Cheater", false); + if (iPriority == 1) + F::PlayerUtils.AddTag(friendsID, "Ignored", false); + } + } + + F::PlayerUtils.bLoadPlayers = false; + } + catch (...) {} +} + +void CPlayerlistCore::SaveTags() +{ + if (!F::PlayerUtils.bSaveTags) + return; + + try + { + boost::property_tree::ptree writeTree; + + // Put map entries into ptree + for (const auto& [sTag, plTag] : F::PlayerUtils.mTags) + { + boost::property_tree::ptree tagTree; + tagTree.put_child("Color", F::Configs.ColorToTree(plTag.Color)); + tagTree.put("Priority", plTag.Priority); + tagTree.put("Label", plTag.Label); + + writeTree.put_child(sTag, tagTree); + } + + // Save the file + write_json(F::Configs.sConfigPath + "\\Core\\Tags.json", writeTree); + + F::PlayerUtils.bSaveTags = false; + } + catch (...) {} +} + +void CPlayerlistCore::LoadTags() +{ + if (!F::PlayerUtils.bLoadTags) + return; + + try + { + if (std::filesystem::exists(F::Configs.sConfigPath + "\\Core\\Tags.json")) + { + boost::property_tree::ptree readTree; + read_json(F::Configs.sConfigPath + "\\Core\\Tags.json", readTree); + F::PlayerUtils.mTags = { + { "Default", { { 200, 200, 200, 255 }, 0, false, false, true } }, + { "Ignored", { { 200, 200, 200, 255 }, -1, false, true, true } }, + { "Cheater", { { 255, 100, 100, 255 }, 1, false, true, true } }, + { "Friend", { { 100, 255, 100, 255 }, 0, true, false, true } } + }; + + for (auto& it : readTree) + { + PriorityLabel_t plTag = {}; + if (const auto getChild = it.second.get_child_optional("Color")) { F::Configs.TreeToColor(*getChild, plTag.Color); } + if (auto getValue = it.second.get_optional("Priority")) { plTag.Priority = *getValue; } + if (auto getValue = it.second.get_optional("Label")) { plTag.Label = *getValue; } + + std::string sTag = it.first; + F::PlayerUtils.mTags[sTag].Color = plTag.Color; + F::PlayerUtils.mTags[sTag].Priority = plTag.Priority; + F::PlayerUtils.mTags[sTag].Label = plTag.Label; + } + } + + F::PlayerUtils.bLoadTags = false; + } + catch (...) {} +} \ No newline at end of file diff --git a/Amalgam/src/Features/Players/PlayerCore.h b/Amalgam/src/Features/Players/PlayerCore.h new file mode 100644 index 0000000..13883fb --- /dev/null +++ b/Amalgam/src/Features/Players/PlayerCore.h @@ -0,0 +1,15 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CPlayerlistCore +{ + void SavePlayers(); + void LoadPlayers(); + void SaveTags(); + void LoadTags(); + +public: + void Run(); +}; + +ADD_FEATURE(CPlayerlistCore, PlayerCore) \ No newline at end of file diff --git a/Amalgam/src/Features/Players/PlayerUtils.cpp b/Amalgam/src/Features/Players/PlayerUtils.cpp new file mode 100644 index 0000000..70ffc65 --- /dev/null +++ b/Amalgam/src/Features/Players/PlayerUtils.cpp @@ -0,0 +1,272 @@ +#include "PlayerUtils.h" + +#include "../../SDK/Definitions/Types.h" +#include "../Logs/Logs.h" + +uint32_t GetFriendsID(int iIndex) +{ + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(iIndex, &pi) && !pi.fakeplayer) + return pi.friendsID; + return 0; +} + +bool CPlayerlistUtils::GetTag(std::string sTag, PriorityLabel_t* plTag) +{ + if (!sTag.length()) + return false; + + if (mTags.contains(sTag)) + { + *plTag = mTags[sTag]; + return true; + } + + return false; +} + + + +void CPlayerlistUtils::AddTag(uint32_t friendsID, std::string sTag, bool bSave, std::string sName) +{ + if (!friendsID) + return; + + if (!HasTag(friendsID, sTag)) + { + mPlayerTags[friendsID].push_back(sTag); + bSavePlayers = bSave; + if (sName.length()) + { + PriorityLabel_t plTag; + if (GetTag(sTag, &plTag)) + F::Logs.TagsChanged(sName, "Added", plTag.Color.ToHexA(), sTag); + } + } +} +void CPlayerlistUtils::AddTag(int iIndex, std::string sTag, bool bSave, std::string sName) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + AddTag(friendsID, sTag, bSave, sName); +} + +void CPlayerlistUtils::RemoveTag(uint32_t friendsID, std::string sTag, bool bSave, std::string sName) +{ + if (!friendsID) + return; + + auto uHash = FNV1A::Hash(sTag.c_str()); + auto& mTags = mPlayerTags[friendsID]; + for (auto it = mTags.begin(); it != mTags.end(); it++) + { + if (uHash = FNV1A::Hash(it->c_str())) + { + mTags.erase(it); + bSavePlayers = bSave; + if (sName.length()) + { + PriorityLabel_t plTag; + if (GetTag(sTag, &plTag)) + F::Logs.TagsChanged(sName, "Removed", plTag.Color.ToHexA(), sTag); + } + break; + } + } +} +void CPlayerlistUtils::RemoveTag(int iIndex, std::string sTag, bool bSave, std::string sName) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + RemoveTag(friendsID, sTag, bSave, sName); +} + +bool CPlayerlistUtils::HasTags(uint32_t friendsID) +{ + if (!friendsID) + return false; + + return mPlayerTags[friendsID].size(); +} +bool CPlayerlistUtils::HasTags(int iIndex) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + return HasTags(friendsID); + return false; +} + +bool CPlayerlistUtils::HasTag(uint32_t friendsID, std::string sTag) +{ + if (!friendsID) + return false; + + auto uHash = FNV1A::Hash(sTag.c_str()); + auto it = std::ranges::find_if(mPlayerTags[friendsID], [uHash](const auto& _sTag) { return uHash == FNV1A::Hash(_sTag.c_str()); }); + return it != mPlayerTags[friendsID].end(); +} +bool CPlayerlistUtils::HasTag(int iIndex, std::string sTag) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + return HasTag(friendsID, sTag); + return false; +} + + + +int CPlayerlistUtils::GetPriority(uint32_t friendsID) +{ + const int iDefault = mTags["Default"].Priority; + if (!friendsID) + return iDefault; + + if (HasTag(friendsID, "Ignored")) + return mTags["Ignored"].Priority; + + std::vector vPriorities; + for (const auto& sTag : mPlayerTags[friendsID]) + { + PriorityLabel_t plTag; + if (F::PlayerUtils.GetTag(sTag, &plTag) && !plTag.Label) + vPriorities.push_back(plTag.Priority); + } + if (H::Entities.IsFriend(friendsID)) + { + auto& plTag = mTags["Friend"]; + if (!plTag.Label) + vPriorities.push_back(plTag.Priority); + } + + if (vPriorities.size()) + { + std::sort(vPriorities.begin(), vPriorities.end(), std::greater()); + return *vPriorities.begin(); + } + return iDefault; +} +int CPlayerlistUtils::GetPriority(int iIndex) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + return GetPriority(friendsID); + return mTags["Default"].Priority; +} + +bool CPlayerlistUtils::GetSignificantTag(uint32_t friendsID, std::string* sTag, PriorityLabel_t* plTag, int iMode) +{ + if (!friendsID) + return false; + + std::vector> vLabels; + if (!iMode || iMode == 1) + { + if (HasTag(friendsID, "Ignored")) + { + *sTag = "Ignored"; + *plTag = mTags["Ignored"]; + return true; + } + + for (const auto& _sTag : mPlayerTags[friendsID]) + { + PriorityLabel_t _plTag; + if (F::PlayerUtils.GetTag(_sTag, &_plTag) && !_plTag.Label) + vLabels.push_back({ _sTag, _plTag }); + } + if (H::Entities.IsFriend(friendsID)) + { + auto& _plTag = mTags["Friend"]; + if (!_plTag.Label) + vLabels.push_back({ "Friend", _plTag }); + } + } + if ((!iMode || iMode == 2) && !vLabels.size()) + { + for (const auto& _sTag : mPlayerTags[friendsID]) + { + PriorityLabel_t _plTag; + if (F::PlayerUtils.GetTag(_sTag, &_plTag) && _plTag.Label) + vLabels.push_back({ _sTag, _plTag }); + } + if (H::Entities.IsFriend(friendsID)) + { + auto& _plTag = mTags["Friend"]; + if (_plTag.Label) + vLabels.push_back({ "Friend", _plTag }); + } + } + if (!vLabels.size()) + return false; + + std::sort(vLabels.begin(), vLabels.end(), [&](const auto& a, const auto& b) -> bool + { + // sort by priority if unequal + if (a.second.Priority != b.second.Priority) + return a.second.Priority > b.second.Priority; + + return a.first < b.first; + }); + *sTag = vLabels.begin()->first; + *plTag = vLabels.begin()->second; + return true; +} +bool CPlayerlistUtils::GetSignificantTag(int iIndex, std::string* sTag, PriorityLabel_t* plTag, int iMode) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + return GetSignificantTag(friendsID, sTag, plTag, iMode); + return false; +} + +bool CPlayerlistUtils::IsIgnored(uint32_t friendsID) +{ + if (!friendsID) + return false; + + const int iPriority = GetPriority(friendsID); + const int iIgnored = mTags["Ignored"].Priority; + return iPriority <= iIgnored; +} +bool CPlayerlistUtils::IsIgnored(int iIndex) +{ + if (const uint32_t friendsID = GetFriendsID(iIndex)) + return IsIgnored(friendsID); + return false; +} + + + +void CPlayerlistUtils::UpdatePlayers() +{ + static Timer updateTimer{}; + if (updateTimer.Run(1000)) + { + std::lock_guard lock(mutex); + vPlayerCache.clear(); + + auto pResource = H::Entities.GetPR(); + if (!pResource) + return; + + for (int n = 1; n <= I::EngineClient->GetMaxClients(); n++) + { + if (!pResource->GetValid(n) || !pResource->GetConnected(n)) + continue; + + bool bFake = true, bFriend = false; + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(n, &pi)) + { + bFake = pi.fakeplayer; + bFriend = H::Entities.IsFriend(n); + } + + vPlayerCache.push_back({ + pResource->GetPlayerName(n), + pResource->GetAccountID(n), + pResource->GetUserID(n), + pResource->GetTeam(n), + pResource->GetClass(n), + pResource->IsAlive(n), + n == I::EngineClient->GetLocalPlayer(), + bFriend, + bFake + }); + } + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/Players/PlayerUtils.h b/Amalgam/src/Features/Players/PlayerUtils.h new file mode 100644 index 0000000..30a719a --- /dev/null +++ b/Amalgam/src/Features/Players/PlayerUtils.h @@ -0,0 +1,74 @@ +#pragma once +#include "../../SDK/SDK.h" +#include + +struct ListPlayer +{ + const char* Name{}; + uint32_t FriendsID{}; + int UserID{}; + int Team{}; + int Class{}; + bool Alive{}; + bool Local{}; + bool Friend{}; + bool Fake{}; +}; + +struct PriorityLabel_t +{ + Color_t Color = { 255, 255, 255, 255 }; + int Priority = 0; + + bool Label = false; + bool Assignable = true; + bool Locked = false; // don't allow it to be removed +}; + +class CPlayerlistUtils +{ +public: + bool GetTag(std::string sTag, PriorityLabel_t* plTag); + + void AddTag(uint32_t friendsID, std::string sTag, bool bSave = true, std::string sName = ""); + void AddTag(int iIndex, std::string sTag, bool bSave = true, std::string sName = ""); + void RemoveTag(uint32_t friendsID, std::string sTag, bool bSave = true, std::string sName = ""); + void RemoveTag(int iIndex, std::string sTag, bool bSave = true, std::string sName = ""); + bool HasTags(uint32_t friendsID); + bool HasTags(int iIndex); + bool HasTag(uint32_t friendsID, std::string sTag); + bool HasTag(int iIndex, std::string sTag); + + int GetPriority(uint32_t friendsID); + int GetPriority(int iIndex); + bool GetSignificantTag(uint32_t friendsID, std::string* sTag, PriorityLabel_t* plTag, int iMode = 1); // iMode: 0 - Priorities & Labels, 1 - Priorities, 2 - Labels + bool GetSignificantTag(int iIndex, std::string* sTag, PriorityLabel_t* plTag, int iMode = 1); // iMode: 0 - Priorities & Labels, 1 - Priorities, 2 - Labels + bool IsIgnored(uint32_t friendsID); + bool IsIgnored(int iIndex); + + void UpdatePlayers(); + std::mutex mutex; + +public: + std::unordered_map> mPlayerTags = {}; + + std::unordered_map mTags = { + { "Default", { { 200, 200, 200, 255 }, 0, false, false, true } }, + { "Ignored", { { 200, 200, 200, 255 }, -1, false, true, true } }, + { "Cheater", { { 255, 100, 100, 255 }, 1, false, true, true } }, + { "Friend", { { 100, 255, 100, 255 }, 0, true, false, true } } + }; + + std::vector vPlayerCache = {}; + std::unordered_map mPriorityCache = {}; + + bool bLoadPlayers = true; + bool bSavePlayers = false; + bool bLoadTags = true; + bool bSaveTags = false; + + const std::vector vListPitch = { "None", "Up", "Down", "Zero", "Auto" }; + const std::vector vListYaw = { "None", "Forward", "Backward", "Left", "Right", "Invert", "Edge", "Auto" }; +}; + +ADD_FEATURE(CPlayerlistUtils, PlayerUtils) \ No newline at end of file diff --git a/Amalgam/src/Features/Resolver/Resolver.cpp b/Amalgam/src/Features/Resolver/Resolver.cpp new file mode 100644 index 0000000..e5558b6 --- /dev/null +++ b/Amalgam/src/Features/Resolver/Resolver.cpp @@ -0,0 +1,324 @@ +#include "Resolver.h" + +#include "../PacketManip/AntiAim/AntiAim.h" +#include "../Backtrack/Backtrack.h" + +static std::vector vYawRotations{ 0.0f, 180.0f, 90.0f, -90.0f}; + +void PResolver::UpdateSniperDots() +{ + mSniperDots.clear(); + for (auto& pEntity : H::Entities.GetGroup(EGroupType::MISC_DOTS)) + { + if (auto pOwner = pEntity->m_hOwnerEntity().Get()) + mSniperDots[pOwner] = pEntity->m_vecOrigin(); + } +} + +std::optional PResolver::GetPitchForSniperDot(CTFPlayer* pEntity) +{ + if (mSniperDots.contains(pEntity)) + { + const Vec3 vOrigin = mSniperDots[pEntity]; + const Vec3 vEyeOrigin = pEntity->GetEyePosition(); + const Vec3 vDelta = vOrigin - vEyeOrigin; + Vec3 vAngles; + Math::VectorAngles(vDelta, vAngles); + return vAngles.x; + } + return std::nullopt; +} + +std::optional PResolver::PredictBaseYaw(CTFPlayer* pLocal, CTFPlayer* pEntity) +{ + if (I::GlobalVars->tickcount - mResolverData[pEntity].pLastFireAngles.first.first > 66 || !mResolverData[pEntity].pLastFireAngles.first.first) + { // staleness & validity check + if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost()) + return std::nullopt; + return Math::CalcAngle(pEntity->m_vecOrigin(), pLocal->m_vecOrigin()).y; + } + + bool bFound = false; + float flSmallestAngleTo = 0.f; float flSmallestFovTo = 360.f; + for (auto pTarget : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pTarget->As(); + if (!pPlayer || pPlayer->IsAGhost() || !pPlayer->IsAlive() || pPlayer->m_iTeamNum() == pEntity->m_iTeamNum()) + continue; + + const Vec3 vAngleTo = Math::CalcAngle(pEntity->m_vecOrigin(), pPlayer->m_vecOrigin()); + const float flFOVTo = Math::CalcFov(mResolverData[pEntity].pLastFireAngles.second, vAngleTo); + + if (flFOVTo < flSmallestFovTo) + { + bFound = true; + flSmallestAngleTo = vAngleTo.y; + flSmallestFovTo = flFOVTo; + } + } + + if (!bFound) + return std::nullopt; + + return flSmallestAngleTo; +} + +bool PResolver::ShouldRun(CTFPlayer* pLocal) +{ + return Vars::AntiHack::Resolver::Resolver.Value && pLocal && pLocal->IsAlive() && !pLocal->IsAGhost() && G::WeaponType == EWeaponType::HITSCAN; +} + +bool PResolver::ShouldRunEntity(CTFPlayer* pEntity) +{ + if (!pEntity->OnSolid() && Vars::AntiHack::Resolver::IgnoreAirborne.Value) + return false; + if (!pEntity->IsAlive() || pEntity->IsAGhost() || pEntity->IsTaunting()) + return false; + + //if (pEntity->GetSimulationTime() == pEntity->GetOldSimulationTime()) + // return false; // last networked angles are the same as these, no need to change them + return true; +} + +bool PResolver::KeepOnShot(CTFPlayer* pEntity) +{ + if (abs(I::GlobalVars->tickcount - mResolverData[pEntity].pLastFireAngles.first.first) < 2) + return true; + if (mResolverData[pEntity].pLastFireAngles.first.second) + return true; // this person has not unchoked since shooting + return false; +} + +bool PResolver::IsOnShotPitchReliable(const float flPitch) +{ + if (flPitch > 180) + return flPitch > 273.f; + else + return flPitch < 87.f; +} + +float PResolver::GetRealPitch(const float flPitch) +{ + if (flPitch < 157.5f) + return 89.f; + else + return -89.f; +} + +void PResolver::SetAngles(const Vec3 vAngles, CTFPlayer* pEntity) +{ + if (auto pAnimState = pEntity->GetAnimState()) + { + pEntity->m_angEyeAnglesX() = vAngles.x; + pAnimState->m_flCurrentFeetYaw = vAngles.y; + pAnimState->m_flGoalFeetYaw = vAngles.y; + pAnimState->Update(vAngles.y, vAngles.x); + } +} + +int PResolver::GetPitchMode(CTFPlayer* pEntity) +{ + PlayerInfo_t pi{}; + if (!I::EngineClient->GetPlayerInfo(pEntity->entindex(), &pi)) + return 0; + return mResolverMode[pi.friendsID].first; +} + +int PResolver::GetYawMode(CTFPlayer* pEntity) +{ + PlayerInfo_t pi{}; + if (!I::EngineClient->GetPlayerInfo(pEntity->entindex(), &pi)) + return 0; + return mResolverMode[pi.friendsID].second; +} + +void PResolver::OnDormancy(CTFPlayer* pEntity) +{ + mResolverData[pEntity].pLastSniperPitch = {0, 0.f}; + mResolverData[pEntity].flPitchNoise = 0.f; + mResolverData[pEntity].iPitchNoiseSteps = 0; + mResolverData[pEntity].pLastFireAngles = {{0, false}, {}}; + mResolverData[pEntity].vOriginalAngles = {}; +} + +void PResolver::Aimbot(CTFPlayer* pEntity, const bool bHeadshot) +{ + if (abs(I::GlobalVars->tickcount - pWaiting.first) < 66) + return; + + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (!pNetChan) + return; + + const int iDelay = 6 + TIME_TO_TICKS(G::Lerp + pNetChan->GetLatency(FLOW_INCOMING) + pNetChan->GetLatency(FLOW_OUTGOING)); + pWaiting = {I::GlobalVars->tickcount + iDelay, {pEntity, bHeadshot}}; +} + +void PResolver::FrameStageNotify(CTFPlayer* pLocal) +{ + if (!ShouldRun(pLocal)) + return; + + UpdateSniperDots(); + + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (pPlayer->entindex() == I::EngineClient->GetLocalPlayer()) + continue; + + if (pPlayer->IsDormant()) + { + OnDormancy(pPlayer); + continue; + } + + mResolverData[pPlayer].vOriginalAngles = { pPlayer->m_angEyeAnglesX(), pPlayer->m_angEyeAnglesY() }; + + if (abs(I::GlobalVars->tickcount - mResolverData[pPlayer].pLastFireAngles.first.first) >= 2) + mResolverData[pPlayer].pLastFireAngles.first.second = (pPlayer->m_flSimulationTime() == pPlayer->m_flOldSimulationTime()) ? mResolverData[pPlayer].pLastFireAngles.first.second : false; + + if (!ShouldRunEntity(pPlayer)) + continue; + if (KeepOnShot(pPlayer)) + { + SetAngles(mResolverData[pPlayer].pLastFireAngles.second, pPlayer); + continue; + } + + Vec3 vAdjustedAngle = pPlayer->GetEyeAngles(); + + if (std::optional flPitch = GetPitchForSniperDot(pPlayer)) + { + vAdjustedAngle.x = flPitch.value(); + + // get noise + if (mResolverData[pPlayer].pLastSniperPitch.first) + { + const float flNoise = mResolverData[pPlayer].pLastSniperPitch.second - flPitch.value(); + mResolverData[pPlayer].flPitchNoise *= mResolverData[pPlayer].iPitchNoiseSteps; + mResolverData[pPlayer].flPitchNoise += flNoise; + mResolverData[pPlayer].iPitchNoiseSteps++; + mResolverData[pPlayer].flPitchNoise /= mResolverData[pPlayer].iPitchNoiseSteps; + } + + mResolverData[pPlayer].pLastSniperPitch = {I::GlobalVars->tickcount, flPitch.value()}; + } + else if (I::GlobalVars->tickcount - mResolverData[pPlayer].pLastSniperPitch.first < 66 && mResolverData[pPlayer].flPitchNoise < 5.f) + vAdjustedAngle.x = mResolverData[pPlayer].pLastSniperPitch.second; + else + { + switch (GetPitchMode(pPlayer)) + { + case 0: break; + case 1: vAdjustedAngle.x = -89.f; break; //up + case 2: vAdjustedAngle.x = 89.f; break; //down + case 3: vAdjustedAngle.x = 0.f; break; //zero + case 4: //auto + if (mResolverData[pPlayer].vOriginalAngles.x >= 90.f) + vAdjustedAngle.x = -89.f; + else if (mResolverData[pPlayer].vOriginalAngles.x <= -90.f) + vAdjustedAngle.x = 89.f; + break; + } + } + + const int iYawMode = GetYawMode(pPlayer); + if (iYawMode) + { + std::optional flTempYaw = PredictBaseYaw(pLocal, pPlayer); + if (!flTempYaw) { flTempYaw = Math::CalcAngle(pPlayer->m_vecOrigin(), pLocal->m_vecOrigin()).y; } + + const float flBaseYaw = flTempYaw.value(); + + switch (iYawMode) + { + case 0: break; + case 1: vAdjustedAngle.y = flBaseYaw; break; //forward + case 2: vAdjustedAngle.y = flBaseYaw + 180.f; break; //backwards + case 3: vAdjustedAngle.y = flBaseYaw - 90.f; break; //side1 + case 4: vAdjustedAngle.y = flBaseYaw + 90.f; break; //side2 + case 5: vAdjustedAngle.y += 180.f; break; //invert + case 6:{ //edge + // TODO: Fix this. Resolver will always correct inversely to the player's pitch if we do not fix the logic here. + const bool bEdge = vAdjustedAngle.x == 89 ? F::AntiAim.GetEdge(pPlayer, flBaseYaw, false) : !F::AntiAim.GetEdge(pPlayer, flBaseYaw, false); + vAdjustedAngle.y = flBaseYaw + (bEdge ? 90.f : -90.f); + break; + } + case 7:{ //auto + vAdjustedAngle.y = vYawRotations[mResolverData[pPlayer].iYawIndex]; + break; + } + } + } + + SetAngles(vAdjustedAngle, pPlayer); + } +} + +void PResolver::CreateMove() +{ + if (I::GlobalVars->tickcount > pWaiting.first && pWaiting.second.first) + { + mResolverData[pWaiting.second.first].iYawIndex++; + if (mResolverData[pWaiting.second.first].iYawIndex > 3) + mResolverData[pWaiting.second.first].iYawIndex = 0; + pWaiting = {0, {nullptr, false}}; + F::Backtrack.ResolverUpdate(pWaiting.second.first); + } +} + +void PResolver::FXFireBullet(int iIndex, const Vec3 vAngles) +{ + auto pEntity = I::ClientEntityList->GetClientEntity(iIndex); + if (!pEntity) + return; + + auto pPlayer = pEntity->As(); + + Vec3 vAngAdjusted = vAngles; + Vec3 vAngStore = vAngles; + + if (!IsOnShotPitchReliable(vAngles.x)) + { + float flAdjustedPitch = vAngles.x; + + vAngStore.x += 360.f; + vAngStore.x *= -1; + + vAngAdjusted.x = GetRealPitch(flAdjustedPitch); + + if (fabsf(flAdjustedPitch) > 89.f) + vAngStore.y += 180; // account for likely yaw faking + while (vAngStore.y > 360) + vAngStore.y -= 360.f; // hacky fix for previous line + vAngStore.x += 540; // (360+180) + SDK::Output("Resolver", std::format("Recieved {:.1f} {:.1f}", vAngles.x, vAngles.y).c_str(), {0, 222, 255, 255}); + SDK::Output("Resolver", std::format("Adjusted {:.1f} {:.1f}", vAngAdjusted.x, vAngAdjusted.y).c_str(), {0, 222, 255, 255}); + SDK::Output("Resolver", std::format("Adjusted 2 {:.1f} {:.1f}", vAngStore.x, vAngStore.y).c_str(), {0, 222, 255, 255}); + } + + mResolverData[pPlayer].pLastFireAngles = { { I::GlobalVars->tickcount, true }, vAngStore}; + SetAngles(vAngAdjusted, pPlayer); +} + +void PResolver::OnPlayerHurt(IGameEvent* pEvent) +{ + const bool bLocal = I::EngineClient->GetPlayerForUserID(pEvent->GetInt("attacker")) == I::EngineClient->GetLocalPlayer(); + if (!bLocal) + return; + + auto pVictim = I::ClientEntityList->GetClientEntity(I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid"))); + + if (pVictim == pWaiting.second.first) + { + if (pWaiting.second.second && G::CanHeadshot) + { // should be headshot + const bool bCrit = pEvent->GetBool("crit"); + if (!bCrit) + return; + } + pWaiting = {0, {nullptr, false}}; + } + return; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Resolver/Resolver.h b/Amalgam/src/Features/Resolver/Resolver.h new file mode 100644 index 0000000..06f8f69 --- /dev/null +++ b/Amalgam/src/Features/Resolver/Resolver.h @@ -0,0 +1,53 @@ +#pragma once +#include "../../SDK/SDK.h" + +struct ResolveData +{ + //config data + bool bEnabled = false; // should we resolve this player + + //bruteforce data + int iYawIndex = 0; + + //logical data + std::pair pLastSniperPitch = {0, 0.f}; + float flPitchNoise = 0.f; // noise around sniper dot pitch + int iPitchNoiseSteps = 0; + + //historical data + std::pair, Vec3> pLastFireAngles = { { 0, false }, {} }; + Vec2 vOriginalAngles = {0.f, 0.f}; +}; + +class PResolver +{ + void UpdateSniperDots(); + std::optional GetPitchForSniperDot(CTFPlayer* pEntity); + + std::optional PredictBaseYaw(CTFPlayer* pLocal, CTFPlayer* pEntity); + + bool ShouldRun(CTFPlayer* pLocal); + bool ShouldRunEntity(CTFPlayer* pEntity); + bool KeepOnShot(CTFPlayer* pEntity); + bool IsOnShotPitchReliable(const float flPitch); + float GetRealPitch(const float flPitch); + void SetAngles(const Vec3 vAngles, CTFPlayer* pEntity); + int GetPitchMode(CTFPlayer* pEntity); + int GetYawMode(CTFPlayer* pEntity); + void OnDormancy(CTFPlayer* pEntity); + + std::unordered_map mSniperDots; + std::unordered_map mResolverData; + std::pair> pWaiting = {0, {nullptr, false}}; + +public: + void Aimbot(CTFPlayer* pEntity, const bool bHeadshot); + void FrameStageNotify(CTFPlayer* pLocal); + void CreateMove(); + void FXFireBullet(int iIndex, const Vec3 vAngles); + void OnPlayerHurt(IGameEvent* pEvent); + + std::unordered_map> mResolverMode; +}; + +ADD_FEATURE(PResolver, Resolver) \ No newline at end of file diff --git a/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp new file mode 100644 index 0000000..987d735 --- /dev/null +++ b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp @@ -0,0 +1,390 @@ +#include "MovementSimulation.h" + +//we'll use this to set current player's command, without it CGameMovement::CheckInterval will try to access a nullptr +static CUserCmd DummyCmd = {}; + +void CMovementSimulation::Store(PlayerStorage& playerStorage) +{ + playerStorage.m_PlayerData.m_vecOrigin = playerStorage.m_pPlayer->m_vecOrigin(); + playerStorage.m_PlayerData.m_vecVelocity = playerStorage.m_pPlayer->m_vecVelocity(); + playerStorage.m_PlayerData.m_vecBaseVelocity = playerStorage.m_pPlayer->m_vecBaseVelocity(); + playerStorage.m_PlayerData.m_vecViewOffset = playerStorage.m_pPlayer->m_vecViewOffset(); + playerStorage.m_PlayerData.m_hGroundEntity = playerStorage.m_pPlayer->m_hGroundEntity(); + playerStorage.m_PlayerData.m_fFlags = playerStorage.m_pPlayer->m_fFlags(); + playerStorage.m_PlayerData.m_flDucktime = playerStorage.m_pPlayer->m_flDucktime(); + playerStorage.m_PlayerData.m_flDuckJumpTime = playerStorage.m_pPlayer->m_flDuckJumpTime(); + playerStorage.m_PlayerData.m_bDucked = playerStorage.m_pPlayer->m_bDucked(); + playerStorage.m_PlayerData.m_bDucking = playerStorage.m_pPlayer->m_bDucking(); + playerStorage.m_PlayerData.m_bInDuckJump = playerStorage.m_pPlayer->m_bInDuckJump(); + playerStorage.m_PlayerData.m_flModelScale = playerStorage.m_pPlayer->m_flModelScale(); + playerStorage.m_PlayerData.m_nButtons = playerStorage.m_pPlayer->m_nButtons(); + playerStorage.m_PlayerData.m_flLastMovementStunChange = playerStorage.m_pPlayer->m_flLastMovementStunChange(); + playerStorage.m_PlayerData.m_flStunLerpTarget = playerStorage.m_pPlayer->m_flStunLerpTarget(); + playerStorage.m_PlayerData.m_bStunNeedsFadeOut = playerStorage.m_pPlayer->m_bStunNeedsFadeOut(); + playerStorage.m_PlayerData.m_flPrevTauntYaw = playerStorage.m_pPlayer->m_flPrevTauntYaw(); + playerStorage.m_PlayerData.m_flTauntYaw = playerStorage.m_pPlayer->m_flTauntYaw(); + playerStorage.m_PlayerData.m_flCurrentTauntMoveSpeed = playerStorage.m_pPlayer->m_flCurrentTauntMoveSpeed(); + playerStorage.m_PlayerData.m_iKartState = playerStorage.m_pPlayer->m_iKartState(); + playerStorage.m_PlayerData.m_flVehicleReverseTime = playerStorage.m_pPlayer->m_flVehicleReverseTime(); + playerStorage.m_PlayerData.m_flHypeMeter = playerStorage.m_pPlayer->m_flHypeMeter(); + playerStorage.m_PlayerData.m_flMaxspeed = playerStorage.m_pPlayer->m_flMaxspeed(); + playerStorage.m_PlayerData.m_nAirDucked = playerStorage.m_pPlayer->m_nAirDucked(); + playerStorage.m_PlayerData.m_bJumping = playerStorage.m_pPlayer->m_bJumping(); + playerStorage.m_PlayerData.m_iAirDash = playerStorage.m_pPlayer->m_iAirDash(); + playerStorage.m_PlayerData.m_flWaterJumpTime = playerStorage.m_pPlayer->m_flWaterJumpTime(); + playerStorage.m_PlayerData.m_flSwimSoundTime = playerStorage.m_pPlayer->m_flSwimSoundTime(); + playerStorage.m_PlayerData.m_surfaceProps = playerStorage.m_pPlayer->m_surfaceProps(); + playerStorage.m_PlayerData.m_pSurfaceData = playerStorage.m_pPlayer->m_pSurfaceData(); + playerStorage.m_PlayerData.m_surfaceFriction = playerStorage.m_pPlayer->m_surfaceFriction(); + playerStorage.m_PlayerData.m_chTextureType = playerStorage.m_pPlayer->m_chTextureType(); + playerStorage.m_PlayerData.m_vecPunchAngle = playerStorage.m_pPlayer->m_vecPunchAngle(); + playerStorage.m_PlayerData.m_vecPunchAngleVel = playerStorage.m_pPlayer->m_vecPunchAngleVel(); + playerStorage.m_PlayerData.m_MoveType = playerStorage.m_pPlayer->m_MoveType(); + playerStorage.m_PlayerData.m_MoveCollide = playerStorage.m_pPlayer->m_MoveCollide(); + playerStorage.m_PlayerData.m_vecLadderNormal = playerStorage.m_pPlayer->m_vecLadderNormal(); + playerStorage.m_PlayerData.m_flGravity = playerStorage.m_pPlayer->m_flGravity(); + playerStorage.m_PlayerData.m_nWaterLevel = playerStorage.m_pPlayer->m_nWaterLevel(); + playerStorage.m_PlayerData.m_nWaterType = playerStorage.m_pPlayer->m_nWaterType(); + playerStorage.m_PlayerData.m_flFallVelocity = playerStorage.m_pPlayer->m_flFallVelocity(); + playerStorage.m_PlayerData.m_nPlayerCond = playerStorage.m_pPlayer->m_nPlayerCond(); + playerStorage.m_PlayerData.m_nPlayerCondEx = playerStorage.m_pPlayer->m_nPlayerCondEx(); + playerStorage.m_PlayerData.m_nPlayerCondEx2 = playerStorage.m_pPlayer->m_nPlayerCondEx2(); + playerStorage.m_PlayerData.m_nPlayerCondEx3 = playerStorage.m_pPlayer->m_nPlayerCondEx3(); + playerStorage.m_PlayerData.m_nPlayerCondEx4 = playerStorage.m_pPlayer->m_nPlayerCondEx4(); + playerStorage.m_PlayerData._condition_bits = playerStorage.m_pPlayer->_condition_bits(); +} + +void CMovementSimulation::Reset(PlayerStorage& playerStorage) +{ + playerStorage.m_pPlayer->m_vecOrigin() = playerStorage.m_PlayerData.m_vecOrigin; + playerStorage.m_pPlayer->m_vecVelocity() = playerStorage.m_PlayerData.m_vecVelocity; + playerStorage.m_pPlayer->m_vecBaseVelocity() = playerStorage.m_PlayerData.m_vecBaseVelocity; + playerStorage.m_pPlayer->m_vecViewOffset() = playerStorage.m_PlayerData.m_vecViewOffset; + playerStorage.m_pPlayer->m_hGroundEntity() = playerStorage.m_PlayerData.m_hGroundEntity; + playerStorage.m_pPlayer->m_fFlags() = playerStorage.m_PlayerData.m_fFlags; + playerStorage.m_pPlayer->m_flDucktime() = playerStorage.m_PlayerData.m_flDucktime; + playerStorage.m_pPlayer->m_flDuckJumpTime() = playerStorage.m_PlayerData.m_flDuckJumpTime; + playerStorage.m_pPlayer->m_bDucked() = playerStorage.m_PlayerData.m_bDucked; + playerStorage.m_pPlayer->m_bDucking() = playerStorage.m_PlayerData.m_bDucking; + playerStorage.m_pPlayer->m_bInDuckJump() = playerStorage.m_PlayerData.m_bInDuckJump; + playerStorage.m_pPlayer->m_flModelScale() = playerStorage.m_PlayerData.m_flModelScale; + playerStorage.m_pPlayer->m_nButtons() = playerStorage.m_PlayerData.m_nButtons; + playerStorage.m_pPlayer->m_flLastMovementStunChange() = playerStorage.m_PlayerData.m_flLastMovementStunChange; + playerStorage.m_pPlayer->m_flStunLerpTarget() = playerStorage.m_PlayerData.m_flStunLerpTarget; + playerStorage.m_pPlayer->m_bStunNeedsFadeOut() = playerStorage.m_PlayerData.m_bStunNeedsFadeOut; + playerStorage.m_pPlayer->m_flPrevTauntYaw() = playerStorage.m_PlayerData.m_flPrevTauntYaw; + playerStorage.m_pPlayer->m_flTauntYaw() = playerStorage.m_PlayerData.m_flTauntYaw; + playerStorage.m_pPlayer->m_flCurrentTauntMoveSpeed() = playerStorage.m_PlayerData.m_flCurrentTauntMoveSpeed; + playerStorage.m_pPlayer->m_iKartState() = playerStorage.m_PlayerData.m_iKartState; + playerStorage.m_pPlayer->m_flVehicleReverseTime() = playerStorage.m_PlayerData.m_flVehicleReverseTime; + playerStorage.m_pPlayer->m_flHypeMeter() = playerStorage.m_PlayerData.m_flHypeMeter; + playerStorage.m_pPlayer->m_flMaxspeed() = playerStorage.m_PlayerData.m_flMaxspeed; + playerStorage.m_pPlayer->m_nAirDucked() = playerStorage.m_PlayerData.m_nAirDucked; + playerStorage.m_pPlayer->m_bJumping() = playerStorage.m_PlayerData.m_bJumping; + playerStorage.m_pPlayer->m_iAirDash() = playerStorage.m_PlayerData.m_iAirDash; + playerStorage.m_pPlayer->m_flWaterJumpTime() = playerStorage.m_PlayerData.m_flWaterJumpTime; + playerStorage.m_pPlayer->m_flSwimSoundTime() = playerStorage.m_PlayerData.m_flSwimSoundTime; + playerStorage.m_pPlayer->m_surfaceProps() = playerStorage.m_PlayerData.m_surfaceProps; + playerStorage.m_pPlayer->m_pSurfaceData() = playerStorage.m_PlayerData.m_pSurfaceData; + playerStorage.m_pPlayer->m_surfaceFriction() = playerStorage.m_PlayerData.m_surfaceFriction; + playerStorage.m_pPlayer->m_chTextureType() = playerStorage.m_PlayerData.m_chTextureType; + playerStorage.m_pPlayer->m_vecPunchAngle() = playerStorage.m_PlayerData.m_vecPunchAngle; + playerStorage.m_pPlayer->m_vecPunchAngleVel() = playerStorage.m_PlayerData.m_vecPunchAngleVel; + playerStorage.m_pPlayer->m_MoveType() = playerStorage.m_PlayerData.m_MoveType; + playerStorage.m_pPlayer->m_MoveCollide() = playerStorage.m_PlayerData.m_MoveCollide; + playerStorage.m_pPlayer->m_vecLadderNormal() = playerStorage.m_PlayerData.m_vecLadderNormal; + playerStorage.m_pPlayer->m_flGravity() = playerStorage.m_PlayerData.m_flGravity; + playerStorage.m_pPlayer->m_nWaterLevel() = playerStorage.m_PlayerData.m_nWaterLevel; + playerStorage.m_pPlayer->m_nWaterType() = playerStorage.m_PlayerData.m_nWaterType; + playerStorage.m_pPlayer->m_flFallVelocity() = playerStorage.m_PlayerData.m_flFallVelocity; + playerStorage.m_pPlayer->m_nPlayerCond() = playerStorage.m_PlayerData.m_nPlayerCond; + playerStorage.m_pPlayer->m_nPlayerCondEx() = playerStorage.m_PlayerData.m_nPlayerCondEx; + playerStorage.m_pPlayer->m_nPlayerCondEx2() = playerStorage.m_PlayerData.m_nPlayerCondEx2; + playerStorage.m_pPlayer->m_nPlayerCondEx3() = playerStorage.m_PlayerData.m_nPlayerCondEx3; + playerStorage.m_pPlayer->m_nPlayerCondEx4() = playerStorage.m_PlayerData.m_nPlayerCondEx4; + playerStorage.m_pPlayer->_condition_bits() = playerStorage.m_PlayerData._condition_bits; +} + + + +void CMovementSimulation::FillVelocities() +{ + if (Vars::Aimbot::Projectile::StrafePrediction.Value) + { + auto FillVelocity = [this](CTFPlayer* pEntity, Vec3 vVelocity) + { + const int iEntIndex = pEntity->entindex(); + + if (!pEntity->IsAlive() || pEntity->IsAGhost() || pEntity->IsDormant() || vVelocity.IsZero()) + { + mVelocities[iEntIndex].clear(); + return; + } + + const float flSimTime = pEntity->m_flSimulationTime(), flOldSimTime = pEntity->m_flOldSimulationTime(); + if (TIME_TO_TICKS(flSimTime - flOldSimTime) <= 0) + return; + + mVelocities[iEntIndex].push_front({ vVelocity, flSimTime }); + + if (mVelocities[iEntIndex].size() > 66) + mVelocities[iEntIndex].pop_back(); + }; + + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + FillVelocity(pEntity->As(), pEntity->As()->m_vecVelocity()); + } + else + mVelocities.clear(); +} + + + +bool CMovementSimulation::Initialize(CBaseEntity* pEntity, PlayerStorage& playerStorageOut, bool useHitchance, bool cancelStrafe) +{ + if (!pEntity || !pEntity->IsPlayer() || !pEntity->As()->IsAlive()) + { + playerStorageOut.m_bInitFailed = playerStorageOut.m_bFailed = true; + return false; + } + + auto pPlayer = pEntity->As(); + playerStorageOut.m_pPlayer = pPlayer; + playerStorageOut.m_pPlayer->SetCurrentCmd(&DummyCmd); + + // store player restore data + Store(playerStorageOut); + + // store vars + m_bOldInPrediction = I::Prediction->m_bInPrediction; + m_bOldFirstTimePredicted = I::Prediction->m_bFirstTimePredicted; + m_flOldFrametime = I::GlobalVars->frametime; + + // the hacks that make it work + { + if (pPlayer->m_fFlags() & FL_DUCKING) + { + pPlayer->m_fFlags() &= ~FL_DUCKING; // breaks origin's z if FL_DUCKING is not removed + pPlayer->m_bDucked() = true; // (mins/maxs will be fine when ducking as long as m_bDucked is true) + pPlayer->m_flDucktime() = 0.f; + pPlayer->m_flDuckJumpTime() = 0.f; + pPlayer->m_bDucking() = false; + pPlayer->m_bInDuckJump() = false; + } + + if (pPlayer != H::Entities.GetLocal()) + pPlayer->m_hGroundEntity() = nullptr; // fix for velocity.z being set to 0 even if in air + + if (pPlayer->IsOnGround()) + { + pPlayer->m_vecOrigin().z += 0.03125f; // to prevent getting stuck in the ground + pPlayer->m_vecVelocity().z = std::min(pPlayer->m_vecVelocity().z, 0.f); // step fix + } + + pPlayer->m_flModelScale() -= 0.03125f; // fixes issues with corners + + //for some reason if xy vel is zero it doesn't predict + if (fabsf(pPlayer->m_vecVelocity().x) < 0.01f) + pPlayer->m_vecVelocity().x = 0.015f; + if (fabsf(pPlayer->m_vecVelocity().y) < 0.01f) + pPlayer->m_vecVelocity().y = 0.015f; + + pPlayer->m_vecBaseVelocity() = Vec3(); // i think residual basevelocity causes issues + } + + // setup move data + if (!SetupMoveData(playerStorageOut)) + { + playerStorageOut.m_bFailed = true; + return false; + } + + const int iStrafeSamples = pPlayer->OnSolid() ? Vars::Aimbot::Projectile::iGroundSamples.Value : Vars::Aimbot::Projectile::iAirSamples.Value; + + // calculate strafe if desired + bool bCalculated = cancelStrafe ? false : StrafePrediction(playerStorageOut, iStrafeSamples); + + // really hope this doesn't work like shit + if (useHitchance && bCalculated && !pPlayer->m_vecVelocity().IsZero() && Vars::Aimbot::Projectile::Hitchance.Value) + { + const auto& mVelocityRecords = mVelocities[playerStorageOut.m_pPlayer->entindex()]; + const auto iSamples = mVelocityRecords.size(); + + float flCurrentChance = 1.f, flAverageYaw = 0.f; + for (size_t i = 0; i < iSamples; i++) + { + if (mVelocityRecords.size() <= i + 2) + break; + + const auto& pRecord1 = mVelocityRecords[i], &pRecord2 = mVelocityRecords[i + 1]; + const float flYaw1 = Math::VelocityToAngles(pRecord1.first).y, flYaw2 = Math::VelocityToAngles(pRecord2.first).y; + const float flTime1 = pRecord1.second, flTime2 = pRecord2.second; + + float flYaw = (flYaw1 - flYaw2) / TIME_TO_TICKS(flTime1 - flTime2); + flYaw = fmodf(flYaw + 180.f, 360.f); + flYaw += flYaw < 0 ? 180.f : -180.f; + flAverageYaw += flYaw; + + if ((i + 1) % iStrafeSamples == 0 || i == iSamples - 1) + { + flAverageYaw /= i % iStrafeSamples + 1; + if (fabsf(playerStorageOut.m_flAverageYaw - flAverageYaw) > 0.5f) + flCurrentChance -= 1.f / ((iSamples - 1) / float(iStrafeSamples) + 1); + flAverageYaw = 0.f; + } + } + + if (flCurrentChance < Vars::Aimbot::Projectile::Hitchance.Value / 100) + { + SDK::Output("MovementSimulation", std::format("Hitchance ({}% < {}%)", flCurrentChance * 100, Vars::Aimbot::Projectile::Hitchance.Value).c_str(), { 125, 255, 83, 255 }, Vars::Debug::Logging.Value); + + playerStorageOut.m_bFailed = true; + return false; + } + } + + return true; +} + +bool CMovementSimulation::SetupMoveData(PlayerStorage& playerStorage) +{ + if (!playerStorage.m_pPlayer) + return false; + + playerStorage.m_MoveData.m_bFirstRunOfFunctions = false; + playerStorage.m_MoveData.m_bGameCodeMovedPlayer = false; + playerStorage.m_MoveData.m_nPlayerHandle = reinterpret_cast(playerStorage.m_pPlayer)->GetRefEHandle(); + + playerStorage.m_MoveData.m_vecAbsOrigin = playerStorage.m_pPlayer->m_vecOrigin(); + playerStorage.m_MoveData.m_vecVelocity = playerStorage.m_pPlayer->m_vecVelocity(); + playerStorage.m_MoveData.m_flMaxSpeed = playerStorage.m_pPlayer->TeamFortress_CalculateMaxSpeed(); + if (playerStorage.m_PlayerData.m_fFlags & FL_DUCKING) + playerStorage.m_MoveData.m_flMaxSpeed *= 0.3333f; + + playerStorage.m_MoveData.m_vecViewAngles = { 0.f, Math::VelocityToAngles(playerStorage.m_MoveData.m_vecVelocity).y, 0.f }; + + Vec3 vForward = {}, vRight = {}; + Math::AngleVectors(playerStorage.m_MoveData.m_vecViewAngles, &vForward, &vRight, nullptr); + playerStorage.m_MoveData.m_flForwardMove = (playerStorage.m_MoveData.m_vecVelocity.y - vRight.y / vRight.x * playerStorage.m_MoveData.m_vecVelocity.x) / (vForward.y - vRight.y / vRight.x * vForward.x); + playerStorage.m_MoveData.m_flSideMove = (playerStorage.m_MoveData.m_vecVelocity.x - vForward.x * playerStorage.m_MoveData.m_flForwardMove) / vRight.x; + if (playerStorage.m_pPlayer->m_vecVelocity().Length2D() <= playerStorage.m_MoveData.m_flMaxSpeed * 0.1f) + playerStorage.m_MoveData.m_flForwardMove = playerStorage.m_MoveData.m_flSideMove = 0.f; + + playerStorage.m_MoveData.m_flClientMaxSpeed = playerStorage.m_MoveData.m_flMaxSpeed; + playerStorage.m_MoveData.m_vecAngles = playerStorage.m_MoveData.m_vecOldAngles = playerStorage.m_MoveData.m_vecViewAngles; + if (auto pConstraintEntity = playerStorage.m_pPlayer->m_hConstraintEntity().Get()) + playerStorage.m_MoveData.m_vecConstraintCenter = pConstraintEntity->GetAbsOrigin(); + else + playerStorage.m_MoveData.m_vecConstraintCenter = playerStorage.m_pPlayer->m_vecConstraintCenter(); + playerStorage.m_MoveData.m_flConstraintRadius = playerStorage.m_pPlayer->m_flConstraintRadius(); + playerStorage.m_MoveData.m_flConstraintWidth = playerStorage.m_pPlayer->m_flConstraintWidth(); + playerStorage.m_MoveData.m_flConstraintSpeedFactor = playerStorage.m_pPlayer->m_flConstraintSpeedFactor(); + + return true; +} + +bool CMovementSimulation::GetYawDifference(const std::deque>& mVelocityRecords, size_t i, float* flYaw) +{ + if (mVelocityRecords.size() <= i + 2) + return false; + + const auto& pRecord1 = mVelocityRecords[i], &pRecord2 = mVelocityRecords[i + 1]; + const float flYaw1 = Math::VelocityToAngles(pRecord1.first).y, flYaw2 = Math::VelocityToAngles(pRecord2.first).y; + const float flTime1 = pRecord1.second, flTime2 = pRecord2.second; + + const int iTicks = std::max(TIME_TO_TICKS(flTime1 - flTime2), 1); + *flYaw = (flYaw1 - flYaw2) / iTicks; + *flYaw = fmodf(*flYaw + 180.f, 360.f); + *flYaw += *flYaw < 0 ? 180.f : -180.f; + + static int iSign = 0; + const int iLastSign = iSign; + const int iCurSign = iSign = *flYaw > 0 ? 1 : -1; + if (fabsf(*flYaw) < 640.f / pRecord1.first.Length2D() / iTicks) // dumb way to get straight bool + return false; + + return !i || iLastSign == iCurSign ? true : false; +} + +float CMovementSimulation::GetAverageYaw(const int iIndex, const int iSamples) +{ + const auto& mVelocityRecords = mVelocities[iIndex]; + + float flAverageYaw = 0.f; size_t i = 0; + for (; i < iSamples; i++) + { + float flYaw; + if (!GetYawDifference(mVelocityRecords, i, &flYaw)) + break; + + flAverageYaw += flYaw; + } + if (i < 2) // valid strafes too low + return 0.f; + + flAverageYaw /= i; + + SDK::Output("MovementSimulation", std::format("flAverageYaw calculated to {} from {}", flAverageYaw, i).c_str(), { 83, 255, 83, 255 }, Vars::Debug::Logging.Value); + + return flAverageYaw; +} + +bool CMovementSimulation::StrafePrediction(PlayerStorage& playerStorage, const int iSamples) +{ + if (playerStorage.m_pPlayer->OnSolid() ? !(Vars::Aimbot::Projectile::StrafePrediction.Value & (1 << 1)) : !(Vars::Aimbot::Projectile::StrafePrediction.Value & (1 << 0))) + return false; + + float flAverageYaw = GetAverageYaw(playerStorage.m_pPlayer->entindex(), iSamples); + + //if (playerStorage.m_pPlayer->OnSolid() && flAverageYaw) + // playerStorage.m_MoveData.m_vecViewAngles.y += 22.5f * (flAverageYaw > 0.f ? 1.f : -1.f); // fix for ground strafe delay + playerStorage.m_flAverageYaw = flAverageYaw; + + return true; +} + +void CMovementSimulation::RunTick(PlayerStorage& playerStorage) +{ + if (playerStorage.m_bFailed || !playerStorage.m_pPlayer || !playerStorage.m_pPlayer->IsPlayer()) + return; + + playerStorage.PredictionLines.push_back({ playerStorage.m_MoveData.m_vecAbsOrigin, Math::GetRotatedPosition(playerStorage.m_MoveData.m_vecAbsOrigin, Math::VelocityToAngles(playerStorage.m_MoveData.m_vecVelocity * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) }); + + //make sure frametime and prediction vars are right + I::Prediction->m_bInPrediction = true; + I::Prediction->m_bFirstTimePredicted = false; + I::GlobalVars->frametime = I::Prediction->m_bEnginePaused ? 0.f : TICK_INTERVAL; + + float flCorrection = 0.f; + if (playerStorage.m_flAverageYaw) + { + if (!playerStorage.m_pPlayer->OnSolid()) + flCorrection = 90.f * (playerStorage.m_flAverageYaw > 0.f ? 1.f : -1.f); + + playerStorage.m_MoveData.m_vecViewAngles.y += playerStorage.m_flAverageYaw + flCorrection; + } + //else + // playerStorage.m_MoveData.m_vecViewAngles.y = Math::VelocityToAngles(playerStorage.m_MoveData.m_vecVelocity).y; + + I::/*TF*/GameMovement->ProcessMovement(playerStorage.m_pPlayer, &playerStorage.m_MoveData); + + playerStorage.m_MoveData.m_vecViewAngles.y -= flCorrection; +} + +void CMovementSimulation::Restore(PlayerStorage& playerStorage) +{ + if (playerStorage.m_bInitFailed || !playerStorage.m_pPlayer) + return; + + playerStorage.m_pPlayer->SetCurrentCmd(nullptr); + + Reset(playerStorage); + + I::Prediction->m_bInPrediction = m_bOldInPrediction; + I::Prediction->m_bFirstTimePredicted = m_bOldFirstTimePredicted; + I::GlobalVars->frametime = m_flOldFrametime; + + const bool bInitFailed = playerStorage.m_bInitFailed, bFailed = playerStorage.m_bFailed; + memset(&playerStorage, 0, sizeof(PlayerStorage)); + playerStorage.m_bInitFailed = bInitFailed, playerStorage.m_bFailed = bFailed; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h new file mode 100644 index 0000000..f211dd7 --- /dev/null +++ b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h @@ -0,0 +1,94 @@ +#pragma once +#include "../../../SDK/SDK.h" + +struct PlayerData +{ + Vec3 m_vecOrigin = {}; + Vec3 m_vecVelocity = {}; + Vec3 m_vecBaseVelocity = {}; + Vec3 m_vecViewOffset = {}; + EHANDLE m_hGroundEntity = nullptr; + int m_fFlags = 0; + float m_flDucktime = 0.f; + float m_flDuckJumpTime = 0.f; + bool m_bDucked = false; + bool m_bDucking = false; + bool m_bInDuckJump = false; + float m_flModelScale = 0.f; + int m_nButtons = 0; + float m_flLastMovementStunChange = 0.f; + float m_flStunLerpTarget = 0.f; + bool m_bStunNeedsFadeOut = false; + float m_flPrevTauntYaw = 0.f; + float m_flTauntYaw = 0.f; + float m_flCurrentTauntMoveSpeed = 0.f; + int m_iKartState = 0; + float m_flVehicleReverseTime = 0.f; + float m_flHypeMeter = 0.f; + float m_flMaxspeed = 0.f; + int m_nAirDucked = 0; + bool m_bJumping = false; + int m_iAirDash = 0; + float m_flWaterJumpTime = 0.f; + float m_flSwimSoundTime = 0.f; + int m_surfaceProps = 0; + void* m_pSurfaceData = nullptr; + float m_surfaceFriction = 0.f; + char m_chTextureType = 0; + Vec3 m_vecPunchAngle = {}; + Vec3 m_vecPunchAngleVel = {}; + float m_flJumpTime = 0.f; + byte m_MoveType = 0; + byte m_MoveCollide = 0; + Vec3 m_vecLadderNormal = {}; + float m_flGravity = 0.f; + byte m_nWaterLevel = 0; + byte m_nWaterType = 0; + float m_flFallVelocity = 0.f; + int m_nPlayerCond = 0; + int m_nPlayerCondEx = 0; + int m_nPlayerCondEx2 = 0; + int m_nPlayerCondEx3 = 0; + int m_nPlayerCondEx4 = 0; + int _condition_bits = 0; +}; +struct PlayerStorage +{ + CTFPlayer* m_pPlayer = nullptr; + CMoveData m_MoveData = {}; + PlayerData m_PlayerData = {}; + + float m_flAverageYaw = 0.f; + + std::deque> PredictionLines; + + bool m_bFailed = false; + bool m_bInitFailed = false; +}; + +class CMovementSimulation +{ +private: + void Store(PlayerStorage& playerStorage); + void Reset(PlayerStorage& playerStorage); + + bool SetupMoveData(PlayerStorage& playerStorage); + bool GetYawDifference(const std::deque>& mPositionRecords, size_t i, float* flYaw); + float GetAverageYaw(const int iIndex, const int iSamples); + bool StrafePrediction(PlayerStorage& playerStorage, const int iSamples); + + bool m_bOldInPrediction = false; + bool m_bOldFirstTimePredicted = false; + float m_flOldFrametime = 0.f; + + std::unordered_map>> mVelocities; + +public: + void FillVelocities(); + + bool Initialize(CBaseEntity* pEntity, PlayerStorage& playerStorageOut, bool useHitchance = true, bool cancelStrafe = false); + void RunTick(PlayerStorage& playerStorage); + void Restore(PlayerStorage& playerStorage); +}; + +ADD_FEATURE(CMovementSimulation, MoveSim) \ No newline at end of file diff --git a/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp new file mode 100644 index 0000000..689c2e9 --- /dev/null +++ b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp @@ -0,0 +1,405 @@ +#include "ProjectileSimulation.h" + +bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, const Vec3& vAngles, ProjectileInfo& out, bool bTrace, bool bQuick, float flCharge) +{ + if (!pPlayer || !pPlayer->IsAlive() || pPlayer->IsAGhost() || pPlayer->IsTaunting() || !pWeapon) + return false; + + static auto sv_gravity = U::ConVars.FindVar("sv_gravity"); + static auto cl_flipviewmodels = U::ConVars.FindVar("cl_flipviewmodels"); + + const bool bDucking = pPlayer->m_fFlags() & FL_DUCKING; + const float flGravity = sv_gravity ? sv_gravity->GetFloat() : 800.f; + const bool bFlipped = cl_flipviewmodels ? cl_flipviewmodels->GetBool() : false; + + Vec3 pos, ang; + + if (Vars::Visuals::Trajectory::Overwrite.Value) + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { Vars::Visuals::Trajectory::OffX.Value, Vars::Visuals::Trajectory::OffY.Value, Vars::Visuals::Trajectory::OffZ.Value }, pos, ang, !bTrace ? true : Vars::Visuals::Trajectory::Pipes.Value, bQuick); + out = { TF_PROJECTILE_NONE, pos, ang, { Vars::Visuals::Trajectory::Hull.Value, Vars::Visuals::Trajectory::Hull.Value, Vars::Visuals::Trajectory::Hull.Value }, Vars::Visuals::Trajectory::Speed.Value, Vars::Visuals::Trajectory::Gravity.Value, Vars::Visuals::Trajectory::NoSpin.Value, Vars::Visuals::Trajectory::LifeTime.Value }; + return true; + } + + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT: + case TF_WEAPON_ROCKETLAUNCHER: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, int(SDK::AttribHookValue(0, "centerfire_projectile", pWeapon)) == 1 ? 0.f : 12.f, bDucking ? 8.f : -3.f }, pos, ang, !bTrace ? true : false, bQuick); + const float speed = pPlayer->IsPrecisionRune() ? 3000.f : SDK::AttribHookValue(1100.f, "mult_projectile_speed", pWeapon); + out = { TF_PROJECTILE_ROCKET, pos, ang, { 0.f, 0.f, 0.f }, bQuick ? 3783722.f : speed, 0.f, true }; + return true; + } + case TF_WEAPON_PARTICLE_CANNON: + case TF_WEAPON_RAYGUN: + case TF_WEAPON_DRG_POMSON: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, 8.f, bDucking ? 8.f : -3.f }, pos, ang, !bTrace ? true : false, bQuick); + if (pWeapon->m_iWeaponID() == TF_WEAPON_DRG_POMSON) + pos.z -= 13.f; + const float speed = pWeapon->m_iWeaponID() == TF_WEAPON_PARTICLE_CANNON ? 1100.f : 1200.f; + out = { TF_PROJECTILE_ENERGY_RING, pos, ang, { 1.f, 1.f, 1.f }, bQuick ? 3783722.f : speed, 0.f, true }; + return true; + } + case TF_WEAPON_GRENADELAUNCHER: // vphysics projectiles affected by server start gravity + case TF_WEAPON_CANNON: + { + const bool bCannon = pWeapon->m_iWeaponID() == TF_WEAPON_CANNON; + const float flMortar = bCannon ? SDK::AttribHookValue(0.f, "grenade_launcher_mortar_mode", pWeapon) : 0.f; + + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, pos, ang, true, bQuick); + const float speed = pPlayer->IsPrecisionRune() ? 3000.f : SDK::AttribHookValue(1200.f, "mult_projectile_speed", pWeapon); + const float lifetime = flMortar + ? pWeapon->As()->m_flDetonateTime() > 0.f ? pWeapon->As()->m_flDetonateTime() - I::GlobalVars->curtime : flMortar + : SDK::AttribHookValue(2.2f, "fuse_mult", pWeapon); + out = { bCannon ? TF_PROJECTILE_CANNONBALL : TF_PROJECTILE_PIPEBOMB, pos, ang, { 5.f, 5.f, 5.f }, speed, 1.f, pWeapon->m_iItemDefinitionIndex() == Demoman_m_TheLochnLoad, lifetime }; + return true; + } + case TF_WEAPON_PIPEBOMBLAUNCHER: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, pos, ang, true, bQuick); + const float charge = flCharge > 0.f && pWeapon->m_iItemDefinitionIndex() != Demoman_s_StickyJumper + ? SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon) * flCharge + : (pWeapon->As()->m_flChargeBeginTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As()->m_flChargeBeginTime() : 0.f); + const float speed = Math::RemapValClamped(charge, 0.f, SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon), 900.f, 2400.f); + out = { TF_PROJECTILE_PIPEBOMB_REMOTE, pos, ang, { 5.f, 5.f, 5.f }, speed, 1.f, false }; + return true; + } + case TF_WEAPON_FLAREGUN: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, 12.f, bDucking ? 8.f : -3.f }, pos, ang, !bTrace ? true : false, bQuick); + out = { TF_PROJECTILE_FLARE, pos, ang, { 1.f, 1.f, 1.f }, SDK::AttribHookValue(2000.f, "mult_projectile_speed", pWeapon), 0.000375f * flGravity /*0.3*/, true}; + return true; + } + case TF_WEAPON_FLAREGUN_REVENGE: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, 12.f, bDucking ? 8.f : -3.f }, pos, ang, !bTrace ? true : false, bQuick); + out = { TF_PROJECTILE_FLARE, pos, ang, { 1.f, 1.f, 1.f }, 3000.f, 0.0005625f * flGravity /*0.45*/, true }; + return true; + } + case TF_WEAPON_COMPOUND_BOW: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, 8.f, -3.f }, pos, ang, !bTrace ? true : false, bQuick); + const float charge = pWeapon->As()->m_flChargeBeginTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As()->m_flChargeBeginTime() : 0.f; + const float speed = Math::RemapValClamped(charge, 0.f, 1.f, 1800.f, 2600.f); + const float gravity = Math::RemapValClamped(charge, 0.f, 1.f, 0.000625f, 0.000125f) * flGravity /*0.5, 0.1*/; + out = { TF_PROJECTILE_ARROW, pos, ang, { 1.f, 1.f, 1.f }, speed, gravity, true, 10.f /*arrows have some lifetime check for whatever reason*/ }; + return true; + } + case TF_WEAPON_CROSSBOW: + case TF_WEAPON_SHOTGUN_BUILDING_RESCUE: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, 8.f, -3.f }, pos, ang, !bTrace ? true : false, bQuick); + out = { TF_PROJECTILE_ARROW, pos, ang, pWeapon->m_iWeaponID() == TF_WEAPON_CROSSBOW ? Vec3(3.f, 3.f, 3.f) : Vec3(1.f, 1.f, 1.f), 2400.f, 0.00025f * flGravity /*0.2*/, true, 10.f /*arrows have some lifetime check for whatever reason*/ }; + return true; + } + case TF_WEAPON_SYRINGEGUN_MEDIC: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 6.f, -8.f }, pos, ang, !bTrace ? true : false, bQuick); + out = { TF_PROJECTILE_SYRINGE, pos, ang, { 1.f, 1.f, 1.f }, 1000.f, 0.000375f * flGravity /*0.3*/, true }; + return true; + } + case TF_WEAPON_FLAMETHROWER: // this inherits player velocity, possibly account for + { + static auto tf_flamethrower_boxsize = U::ConVars.FindVar("tf_flamethrower_boxsize"); + const float flHull = tf_flamethrower_boxsize ? tf_flamethrower_boxsize->GetFloat() : 12.f; + + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 40.f, bFlipped ? -5.f : 5.f /*doesn't flip*/, 0.f}, pos, ang, true, bQuick); + out = { TF_PROJECTILE_FLAME_ROCKET, pos, ang, { flHull, flHull, flHull }, 1000.f, 0.f, true, 0.33f }; + return true; + } + case TF_WEAPON_FLAME_BALL: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 70.f, bFlipped ? -7.f : 7.f /*doesn't flip*/, -9.f}, pos, ang, !bTrace ? true : false, bQuick); + out = { TF_PROJECTILE_BALLOFFIRE, pos, ang, { 1.f, 1.f, 1.f /*damaging hull much bigger, shouldn't matter here*/ }, 3000.f, 0.f, true, 0.2f }; + return true; + } + case TF_WEAPON_CLEAVER: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, pos, ang, true, bQuick); + out = { TF_PROJECTILE_CLEAVER, pos, ang, { 1.f, 1.f, 10.f /*weird, probably still inaccurate*/ }, 3000.f, 2.f, !bTrace ? true : false, 1.55f }; + return true; + } + case TF_WEAPON_BAT_WOOD: + case TF_WEAPON_BAT_GIFTWRAP: + { + const bool bWrapAssassin = pWeapon->m_iWeaponID() == TF_WEAPON_BAT_GIFTWRAP; + + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 0.f, 0.f, 0.f }, pos, ang, true, bQuick); + Vec3 forward; Math::AngleVectors(ang, &forward); + pos = (bQuick ? pPlayer->GetAbsOrigin() : pPlayer->m_vecOrigin()) + (Vec3(0, 0, 50) + forward * 32.f) * pPlayer->m_flModelScale(); // why? + out = { bWrapAssassin ? TF_PROJECTILE_FESTIVE_ARROW : TF_PROJECTILE_THROWABLE, pos, ang, { 3.f, 3.f, 3.f }, 2000.f, 1.f, false, bWrapAssassin ? 2.3f : 100.f }; + return true; + } + case TF_WEAPON_JAR: + case TF_WEAPON_JAR_MILK: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, pos, ang, true, bQuick); + out = { TF_PROJECTILE_JAR, pos, ang, { 3.f, 3.f, 3.f }, 1000.f, 1.f, false, 2.2f }; + return true; + } + case TF_WEAPON_JAR_GAS: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, pos, ang, true, bQuick); + out = { TF_PROJECTILE_JAR_GAS, pos, ang, { 3.f, 3.f, 3.f }, 2000.f, 1.f, false, 2.2f }; + return true; + } + case TF_WEAPON_GRAPPLINGHOOK: + { + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 23.5f, -8.f, -3.f }, pos, ang, false, bQuick); + static auto tf_grapplinghook_projectile_speed = U::ConVars.FindVar("tf_grapplinghook_projectile_speed"); + static auto tf_grapplinghook_max_distance = U::ConVars.FindVar("tf_grapplinghook_max_distance"); + const float speed = tf_grapplinghook_projectile_speed ? tf_grapplinghook_projectile_speed->GetFloat() : 1500.f; + const float lifetime = (tf_grapplinghook_max_distance ? tf_grapplinghook_max_distance->GetFloat() : 2000.f) / speed; + out = { TF_PROJECTILE_GRAPPLINGHOOK, pos, ang, { 1.2f, 1.2f, 1.2f }, speed, 0.f, false, lifetime }; + return true; + } + } + + switch (pWeapon->m_iItemDefinitionIndex()) + { + case Heavy_s_RoboSandvich: + case Heavy_s_Sandvich: + case Heavy_s_FestiveSandvich: + case Heavy_s_Fishcake: + case Heavy_s_TheDalokohsBar: + case Heavy_s_SecondBanana: + SDK::GetProjectileFireSetup(pPlayer, vAngles, { 0.f, 0.f, -8.f }, pos, ang, true, bQuick); + ang -= Vec3(10, 0, 0); + out = { TF_PROJECTILE_BREAD_MONSTER, pos, ang, bQuick ? Vec3(4.f, 4.f, 4.f) : Vec3(17.f, 17.f, 17.f), 500.f, 0.00125f * flGravity /*1*/, false}; + return true; + } + + return false; +} + +bool CProjectileSimulation::GetInfo(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, const Vec3& vAngles, ProjectileInfo& out, bool bTrace, bool bQuick, float flCharge) +{ + const float flOldCurrentTime = I::GlobalVars->curtime; + if (bQuick) + I::GlobalVars->curtime = TICKS_TO_TIME(pPlayer->m_nTickBase()); + const bool bReturn = GetInfoMain(pPlayer, pWeapon, vAngles, out, bTrace, bQuick, flCharge); + I::GlobalVars->curtime = flOldCurrentTime; + + if (!bReturn) + return false; + + const Vec3 vStart = bQuick ? pPlayer->GetEyePosition() : pPlayer->GetShootPos(); + const Vec3 vEnd = out.m_vPos; + + CGameTrace trace = {}; + CTraceFilterProjectile filter = {}; + filter.pSkip = pPlayer; + SDK::TraceHull(vStart, vEnd, out.m_vHull * -1.f, out.m_vHull, MASK_SOLID, &filter, &trace); + return !trace.DidHit(); +} + +bool CProjectileSimulation::Initialize(const ProjectileInfo& info, bool bSimulate) +{ + if (!env) + env = I::Physics->CreateEnvironment(); + + if (!obj) + { + //it doesn't matter what the size is for non drag affected projectiles + //pipes use the size below so it works out just fine + auto col{ I::PhysicsCollision->BBoxToCollide({ -2.f, -2.f, -2.f }, { 2.f, 2.f, 2.f }) }; + + auto params{ g_PhysDefaultObjectParams }; + + params.damping = 0.f; + params.rotdamping = 0.f; + params.inertia = 0.f; + params.rotInertiaLimit = 0.f; + params.enableCollisions = false; + + obj = env->CreatePolyObject(col, 0, info.m_vPos, info.m_vAng, ¶ms); + + obj->Wake(); + } + + if (!env || !obj) + return false; + + //set drag + { + float drag = 0.f; + Vec3 drag_basis = {}; + Vec3 ang_drag_basis = {}; + + //these values were dumped from the server by firing the projectiles with 0 0 0 angles + //they are calculated in CPhysicsObject::RecomputeDragBases + switch (info.m_iType) + { + case TF_PROJECTILE_NONE: + drag = Vars::Visuals::Trajectory::Drag.Value; + drag_basis = { Vars::Visuals::Trajectory::DragBasisX.Value, Vars::Visuals::Trajectory::DragBasisY.Value, Vars::Visuals::Trajectory::DragBasisZ.Value }; + ang_drag_basis = { Vars::Visuals::Trajectory::AngDragBasisX.Value, Vars::Visuals::Trajectory::AngDragBasisY.Value, Vars::Visuals::Trajectory::AngDragBasisZ.Value }; + break; + case TF_PROJECTILE_PIPEBOMB: + drag = 1.f; + drag_basis = { 0.003902f, 0.009962f, 0.009962f }; + ang_drag_basis = { 0.003618f, 0.001514f, 0.001514f }; + break; + case TF_PROJECTILE_PIPEBOMB_REMOTE: + case TF_PROJECTILE_PIPEBOMB_PRACTICE: + drag = 1.f; + drag_basis = { 0.007491f, 0.007491f, 0.007306f }; + ang_drag_basis = { 0.002777f, 0.002842f, 0.002812f }; + break; + case TF_PROJECTILE_CANNONBALL: + drag = 1.f; + drag_basis = { 0.020971f, 0.019420f, 0.020971f }; + ang_drag_basis = { 0.012997f, 0.013496f, 0.013714f }; + break; + case TF_PROJECTILE_CLEAVER: // guesstimate + drag = 1.f; + drag_basis = { 0.020971f, 0.f, 0.f }; + break; + case TF_PROJECTILE_THROWABLE: // guesstimate + drag = 1.f; + drag_basis = { 0.008500f, 0.f, 0.f }; + break; + case TF_PROJECTILE_FESTIVE_ARROW: // guesstimate + drag = 1.f; + drag_basis = { 0.015500f, 0.f, 0.f }; + break; + case TF_PROJECTILE_JAR: // guesstimate (there are different drags for different models, though shouldn't matter here) + drag = 1.f; + drag_basis = { 0.005500f, 0.005000f, 0.f }; + break; + case TF_PROJECTILE_JAR_GAS: // who + drag = 1.f; + drag_basis = { 0.027101f, 0.067938f, 0.f }; + } + + obj->SetDragCoefficient(&drag, &drag); + + obj->m_dragBasis = drag_basis; + obj->m_angDragBasis = ang_drag_basis; + } + + //set position and velocity + { + Vec3 forward, up; + + Math::AngleVectors(info.m_vAng, &forward, nullptr, &up); + + Vec3 vel = { forward * info.m_flVelocity }; + Vec3 ang_vel; + + switch (info.m_iType) + { + case TF_PROJECTILE_NONE: + vel += up * Vars::Visuals::Trajectory::UpVelocity.Value; + ang_vel = { Vars::Visuals::Trajectory::AngVelocityX.Value, Vars::Visuals::Trajectory::AngVelocityY.Value, Vars::Visuals::Trajectory::AngVelocityZ.Value }; + break; + case TF_PROJECTILE_PIPEBOMB: + case TF_PROJECTILE_PIPEBOMB_REMOTE: + case TF_PROJECTILE_PIPEBOMB_PRACTICE: + case TF_PROJECTILE_CANNONBALL: + vel += up * 200.f; + ang_vel = { 600.f, -1200.f, 0.f }; + break; + case TF_PROJECTILE_CLEAVER: + vel += up * 300.f; + ang_vel = { 300.f, 0.f, 0.f }; + break; + case TF_PROJECTILE_THROWABLE: + case TF_PROJECTILE_FESTIVE_ARROW: + vel += up * 200.f; + ang_vel = { 100.f, 0.f, 0.f }; + break; + case TF_PROJECTILE_JAR: + case TF_PROJECTILE_JAR_GAS: + vel += up * 200.f; + ang_vel = { 300.f, 0.f, 0.f }; + } + + if (info.m_bNoSpin) + ang_vel.Zero(); + + if (bSimulate && obj->m_dragBasis.IsZero()) // don't include vphysics projectiles + vel.z += 400.f * info.m_flGravity * TICK_INTERVAL; // i don't know why this makes it more accurate but it does + + obj->SetPosition(info.m_vPos, info.m_vAng, true); + obj->SetVelocity(&vel, &ang_vel); + } + + //set env params + { + float max_vel = 1000000.f; + float max_ang_vel = 1000000.f; + + //only pipes need k_flMaxVelocity and k_flMaxAngularVelocity + switch (info.m_iType) + { + case TF_PROJECTILE_NONE: + if (Vars::Visuals::Trajectory::MaxVelocity.Value) + max_vel = Vars::Visuals::Trajectory::MaxVelocity.Value; + if (Vars::Visuals::Trajectory::MaxAngularVelocity.Value) + max_ang_vel = Vars::Visuals::Trajectory::MaxAngularVelocity.Value; + break; + case TF_PROJECTILE_PIPEBOMB: + case TF_PROJECTILE_PIPEBOMB_REMOTE: + case TF_PROJECTILE_PIPEBOMB_PRACTICE: + case TF_PROJECTILE_CANNONBALL: + max_vel = k_flMaxVelocity; + max_ang_vel = k_flMaxAngularVelocity; + } + + physics_performanceparams_t params{}; + params.Defaults(); + + params.maxVelocity = max_vel; + params.maxAngularVelocity = max_ang_vel; + + env->SetPerformanceSettings(¶ms); + env->SetAirDensity(2.f); + env->SetGravity({ 0.f, 0.f, -(800.f * info.m_flGravity) }); + + env->ResetSimulationClock(); // not needed? + } + + return true; +} + +void CProjectileSimulation::RunTick(ProjectileInfo& info) +{ + if (!env) + return; + + info.PredictionLines.push_back({ GetOrigin(), Math::GetRotatedPosition(GetOrigin(), Math::VelocityToAngles(GetVelocity() * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) }); + + env->Simulate(TICK_INTERVAL); + + /* // params.maxVelocity limits velocity uniformly + Vec3 vVelocity, vAngular; + obj->GetVelocity(&vVelocity, &vAngular); + static auto sv_maxvelocity = U::ConVars.FindVar("sv_maxvelocity"); + const float flMaxVel = sv_maxvelocity ? sv_maxvelocity->GetFloat() : 3500.f; + vVelocity = { std::clamp(vVelocity.x, -flMaxVel, flMaxVel), std::clamp(vVelocity.y, -flMaxVel, flMaxVel), std::clamp(vVelocity.z, -flMaxVel, flMaxVel) }; + obj->SetVelocity(&vVelocity, &vAngular); + */ +} + +Vec3 CProjectileSimulation::GetOrigin() +{ + if (!obj) + return {}; + + Vec3 out; + obj->GetPosition(&out, nullptr); + return out; +} + +Vec3 CProjectileSimulation::GetVelocity() +{ + if (!obj) + return {}; + + Vec3 out; + obj->GetVelocity(&out, nullptr); + return out; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h new file mode 100644 index 0000000..82b8968 --- /dev/null +++ b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h @@ -0,0 +1,52 @@ +#pragma once +#include "../../../SDK/SDK.h" + +struct ProjectileInfo +{ + ProjectileType_t m_iType{}; + + Vec3 m_vPos = {}; + Vec3 m_vAng = {}; + Vec3 m_vHull = {}; + + float m_flVelocity = 0.f; + float m_flGravity = 0.f; + + bool m_bNoSpin = false; + + float m_flLifetime = 100.f; + + std::deque> PredictionLines = {}; +}; + +class CProjectileSimulation +{ + bool GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, const Vec3& vAngles, ProjectileInfo& out, bool bTrace, bool bQuick, float flCharge); + + const objectparams_t g_PhysDefaultObjectParams = + { + NULL, + 1.0, //mass + 1.0, // inertia + 0.1f, // damping + 0.1f, // rotdamping + 0.05f, // rotIntertiaLimit + "DEFAULT", + NULL,// game data + 0.f, // volume (leave 0 if you don't have one or call physcollision->CollideVolume() to compute it) + 1.0f, // drag coefficient + true,// enable collisions? + }; + +public: + bool GetInfo(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, const Vec3& vAngles, ProjectileInfo& out, bool bTrace = true, bool bQuick = false, float flCharge = -1.f); + bool Initialize(const ProjectileInfo& info, bool bSimulate = true); + void RunTick(ProjectileInfo& info); + Vec3 GetOrigin(); + Vec3 GetVelocity(); + + IPhysicsEnvironment* env = nullptr; + IPhysicsObject* obj = nullptr; +}; + +ADD_FEATURE(CProjectileSimulation, ProjSim) \ No newline at end of file diff --git a/Amalgam/src/Features/TickHandler/TickHandler.cpp b/Amalgam/src/Features/TickHandler/TickHandler.cpp new file mode 100644 index 0000000..840d491 --- /dev/null +++ b/Amalgam/src/Features/TickHandler/TickHandler.cpp @@ -0,0 +1,214 @@ +#include "TickHandler.h" + +#include "../NetworkFix/NetworkFix.h" +#include "../PacketManip/AntiAim/AntiAim.h" +#include "../Aimbot/AutoRocketJump/AutoRocketJump.h" + +void CTickshiftHandler::Reset() +{ + bSpeedhack = G::DoubleTap = G::Recharge = G::Warp = false; + G::ShiftedTicks = G::ShiftedGoal = 0; +} + +void CTickshiftHandler::Recharge(CUserCmd* pCmd, CTFPlayer* pLocal) +{ + bool bPassive = G::Recharge = false; + + static float iPassiveTick = 0.f; + if (Vars::CL_Move::Doubletap::PassiveRecharge.Value && I::GlobalVars->tickcount >= iPassiveTick) + { + bPassive = true; + iPassiveTick = I::GlobalVars->tickcount + 67 - Vars::CL_Move::Doubletap::PassiveRecharge.Value; + } + + if (iDeficit && G::ShiftedTicks < G::MaxShift) + { + bPassive = true; + iDeficit--; + } + else if (iDeficit) + iDeficit = 0; + + if (!Vars::CL_Move::Doubletap::RechargeTicks.Value && !bPassive + || G::DoubleTap || G::Warp || G::ShiftedTicks == G::MaxShift || bSpeedhack) + return; + + G::Recharge = true; + if (bGoalReached) + G::ShiftedGoal = G::ShiftedTicks + 1; +} + +void CTickshiftHandler::Teleport(CUserCmd* pCmd) +{ + G::Warp = false; + if (!G::ShiftedTicks || G::DoubleTap || G::Recharge || bSpeedhack) + return; + + G::Warp = Vars::CL_Move::Doubletap::Warp.Value; + if (G::Warp && bGoalReached) + G::ShiftedGoal = std::max(G::ShiftedTicks - Vars::CL_Move::Doubletap::WarpRate.Value + 1, 0); +} + +void CTickshiftHandler::Doubletap(const CUserCmd* pCmd, CTFPlayer* pLocal) +{ + if (G::ShiftedTicks < std::min(Vars::CL_Move::Doubletap::TickLimit.Value - 1, G::MaxShift) + || G::WaitForShift || G::Warp || G::Recharge || bSpeedhack + || !G::CanPrimaryAttack || (G::WeaponType == EWeaponType::MELEE ? !(pCmd->buttons & IN_ATTACK) : !G::IsAttacking) || F::AutoRocketJump.iFrame != -1) + return; + + G::DoubleTap = Vars::CL_Move::Doubletap::Doubletap.Value; + if (G::DoubleTap && Vars::CL_Move::Doubletap::AntiWarp.Value) + G::AntiWarp = true; + if (G::DoubleTap && bGoalReached) + G::ShiftedGoal = G::ShiftedTicks - std::min(Vars::CL_Move::Doubletap::TickLimit.Value - 1, G::MaxShift); +} + +int CTickshiftHandler::GetTicks(CTFPlayer* pLocal) +{ + if (G::DoubleTap && G::ShiftedGoal < G::ShiftedTicks) + return G::ShiftedTicks - G::ShiftedGoal; + + if (!!Vars::CL_Move::Doubletap::Doubletap.Value + || G::ShiftedTicks < std::min(Vars::CL_Move::Doubletap::TickLimit.Value - 1, G::MaxShift) + || G::WaitForShift || G::Warp || G::Recharge || bSpeedhack || F::AutoRocketJump.iFrame != -1) + return 0; + + return std::min(Vars::CL_Move::Doubletap::TickLimit.Value - 1, G::MaxShift); +} + +bool CTickshiftHandler::ValidWeapon(CTFWeaponBase* pWeapon) +{ + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_PDA: + case TF_WEAPON_PDA_ENGINEER_BUILD: + case TF_WEAPON_PDA_ENGINEER_DESTROY: + case TF_WEAPON_PDA_SPY: + case TF_WEAPON_PDA_SPY_BUILD: + case TF_WEAPON_BUILDER: + case TF_WEAPON_INVIS: + case TF_WEAPON_GRAPPLINGHOOK: + case TF_WEAPON_JAR_MILK: + case TF_WEAPON_LUNCHBOX: + case TF_WEAPON_BUFF_ITEM: + case TF_WEAPON_ROCKETPACK: + case TF_WEAPON_JAR_GAS: + case TF_WEAPON_LASER_POINTER: + case TF_WEAPON_MEDIGUN: + case TF_WEAPON_SNIPERRIFLE: + case TF_WEAPON_SNIPERRIFLE_DECAP: + case TF_WEAPON_SNIPERRIFLE_CLASSIC: + case TF_WEAPON_COMPOUND_BOW: + case TF_WEAPON_JAR: + return false; + } + + return true; +} + +void CTickshiftHandler::Speedhack(CUserCmd* pCmd) +{ + bSpeedhack = Vars::CL_Move::SpeedEnabled.Value; + if (!bSpeedhack) + return; + + G::DoubleTap = G::Warp = G::Recharge = false; +} + +void CTickshiftHandler::CLMoveFunc(float accumulated_extra_samples, bool bFinalTick) +{ + static auto CL_Move = U::Hooks.m_mHooks["CL_Move"]; + + G::ShiftedTicks--; + if (G::ShiftedTicks < 0) + return; + if (G::WaitForShift > 0) + G::WaitForShift--; + + if (G::ShiftedTicks < std::min(Vars::CL_Move::Doubletap::TickLimit.Value - 1, G::MaxShift)) + G::WaitForShift = 1; + + bGoalReached = bFinalTick && G::ShiftedTicks == G::ShiftedGoal; + + if (CL_Move) + CL_Move->Original()(accumulated_extra_samples, bFinalTick); +} + +void CTickshiftHandler::MoveMain(float accumulated_extra_samples, bool bFinalTick) +{ + if (auto pWeapon = H::Entities.GetWeapon()) + { + const int iWeaponID = pWeapon->m_iWeaponID(); + if (iWeaponID != TF_WEAPON_PIPEBOMBLAUNCHER && iWeaponID != TF_WEAPON_CANNON) + { + if (!ValidWeapon(pWeapon)) + G::WaitForShift = 2; + else if (G::IsAttacking || !G::CanPrimaryAttack || pWeapon->IsInReload()) + G::WaitForShift = Vars::CL_Move::Doubletap::TickLimit.Value; + } + } + else + G::WaitForShift = 2; + + static auto sv_maxusrcmdprocessticks = U::ConVars.FindVar("sv_maxusrcmdprocessticks"); + G::MaxShift = sv_maxusrcmdprocessticks ? sv_maxusrcmdprocessticks->GetInt() : 24; + if (F::AntiAim.YawOn()) + G::MaxShift -= 3; + + while (G::ShiftedTicks > G::MaxShift) + CLMoveFunc(accumulated_extra_samples, false); // skim any excess ticks + + G::ShiftedTicks++; // since we now have full control over CL_Move, increment. + if (G::ShiftedTicks <= 0) + { + G::ShiftedTicks = 0; + return; + } + + if (bSpeedhack) + { + for (int i = 0; i < Vars::CL_Move::SpeedFactor.Value; i++) + CLMoveFunc(accumulated_extra_samples, i == Vars::CL_Move::SpeedFactor.Value); + return; + } + + G::ShiftedGoal = std::clamp(G::ShiftedGoal, 0, G::MaxShift); + if (G::ShiftedTicks > G::ShiftedGoal) // normal use/doubletap/teleport + { + while (G::ShiftedTicks > G::ShiftedGoal) + CLMoveFunc(accumulated_extra_samples, G::ShiftedTicks - 1 == G::ShiftedGoal); + G::AntiWarp = false; + if (G::Warp) + iDeficit = 0; + + G::DoubleTap = G::Warp = false; + } + // else recharge +} + +void CTickshiftHandler::MovePre(CTFPlayer* pLocal) +{ + CUserCmd* pCmd = G::CurrentUserCmd; + if (!pLocal || !pCmd) + return; + + Recharge(pCmd, pLocal); + Teleport(pCmd); + Speedhack(pCmd); +} + +void CTickshiftHandler::MovePost(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (!pLocal) + return; + + Doubletap(pCmd, pLocal); +} + +void CTickshiftHandler::Run(float accumulated_extra_samples, bool bFinalTick, CTFPlayer* pLocal) +{ + F::NetworkFix.FixInputDelay(bFinalTick); + + MovePre(pLocal); + MoveMain(accumulated_extra_samples, bFinalTick); +} \ No newline at end of file diff --git a/Amalgam/src/Features/TickHandler/TickHandler.h b/Amalgam/src/Features/TickHandler/TickHandler.h new file mode 100644 index 0000000..863c27e --- /dev/null +++ b/Amalgam/src/Features/TickHandler/TickHandler.h @@ -0,0 +1,31 @@ +#pragma once +#include "../../SDK/SDK.h" + +class CTickshiftHandler +{ + // logic + void Recharge(CUserCmd* pCmd, CTFPlayer* pLocal); + void Teleport(CUserCmd* pCmd); + void Doubletap(const CUserCmd* pCmd, CTFPlayer* pLocal); + void Speedhack(CUserCmd* pCmd); + bool ValidWeapon(CTFWeaponBase* pWeapon); + + // utils + void CLMoveFunc(float accumulated_extra_samples, bool bFinalTick); + + void MovePre(CTFPlayer* pLocal); + void MoveMain(float accumulated_extra_samples, bool bFinalTick); + + bool bSpeedhack = false; + bool bGoalReached = true; + +public: + int GetTicks(CTFPlayer* pLocal); + void Run(float accumulated_extra_samples, bool bFinalTick, CTFPlayer* pLocal); + void MovePost(CTFPlayer* pLocal, CUserCmd* pCmd); + void Reset(); + + int iDeficit = 0; +}; + +ADD_FEATURE(CTickshiftHandler, Ticks) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Chams/Chams.cpp b/Amalgam/src/Features/Visuals/Chams/Chams.cpp new file mode 100644 index 0000000..7742500 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Chams/Chams.cpp @@ -0,0 +1,509 @@ +#include "Chams.h" + +#include "../Materials/Materials.h" +#include "../FakeAngle/FakeAngle.h" +#include "../../Backtrack/Backtrack.h" + +Chams_t CChams::GetStruct(std::vector VisibleMaterial, std::vector OccludedMaterial, Color_t VisibleColor, Color_t OccludedColor) +{ + return Chams_t{ + VisibleMaterial, + OccludedMaterial, + VisibleColor, + OccludedColor + }; +} + +bool CChams::GetPlayerChams(CTFPlayer* pEntity, CTFPlayer* pLocal, Chams_t* pChams, bool bFriendly, bool bEnemy) +{ + if (Vars::Chams::Player::Local.Value && pEntity == pLocal) + { + *pChams = GetStruct(Vars::Chams::Player::VisibleMaterial.Value, Vars::Chams::Player::OccludedMaterial.Value, Vars::Chams::Player::VisibleColor.Value, Vars::Chams::Player::OccludedColor.Value); + return true; + } + else if (Vars::Chams::Player::Friend.Value && H::Entities.IsFriend(pEntity->entindex())) + { + *pChams = GetStruct(Vars::Chams::Player::VisibleMaterial.Value, Vars::Chams::Player::OccludedMaterial.Value, Vars::Chams::Player::VisibleColor.Value, Vars::Chams::Player::OccludedColor.Value); + return true; + } + + const bool bTeam = pEntity->m_iTeamNum() == pLocal->m_iTeamNum(); + *pChams = bTeam + ? GetStruct(Vars::Chams::Friendly::VisibleMaterial.Value, Vars::Chams::Friendly::OccludedMaterial.Value, Vars::Chams::Friendly::VisibleColor.Value, Vars::Chams::Friendly::OccludedColor.Value) + : GetStruct(Vars::Chams::Enemy::VisibleMaterial.Value, Vars::Chams::Enemy::OccludedMaterial.Value, Vars::Chams::Enemy::VisibleColor.Value, Vars::Chams::Enemy::OccludedColor.Value); + return bTeam ? bFriendly : bEnemy; +} + +bool CChams::GetChams(CTFPlayer* pLocal, CBaseEntity* pEntity, Chams_t* pChams) +{ + if (pEntity->IsDormant() || !pEntity->ShouldDraw()) + return false; + + switch (pEntity->GetClassID()) + { + // player chams + case ETFClassID::CTFPlayer: + return GetPlayerChams(pEntity->As(), pLocal, pChams, Vars::Chams::Friendly::Players.Value, Vars::Chams::Enemy::Players.Value); + case ETFClassID::CTFWeaponBase: + SDK::Output("Chams", "ETFClassID::CTFWeaponBase"); + break; + case ETFClassID::CTFWearable: + { + auto pOwner = pEntity->m_hOwnerEntity().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Players.Value, Vars::Chams::Enemy::Players.Value); + } + // building chams + case ETFClassID::CObjectSentrygun: + case ETFClassID::CObjectDispenser: + case ETFClassID::CObjectTeleporter: + { + auto pOwner = pEntity->As()->m_hBuilder().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Buildings.Value, Vars::Chams::Enemy::Buildings.Value); + } + // ragdoll chams + case ETFClassID::CRagdollPropAttached: + case ETFClassID::CRagdollProp: + case ETFClassID::CTFRagdoll: + { + /* + // don't interfere with ragdolls + if (Vars::Visuals::Ragdolls::Type.Value) + { + if (Vars::Visuals::Ragdolls::EnemyOnly.Value && pEntity && pLocal && pEntity->m_iTeamNum() == pLocal->m_iTeamNum()) + return false; + else + return false; + } + */ + auto pOwner = pEntity->As()->m_hPlayer().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Ragdolls.Value, Vars::Chams::Enemy::Ragdolls.Value); + } + // projectile chams + case ETFClassID::CBaseGrenade: + case ETFClassID::CTFWeaponBaseGrenadeProj: + case ETFClassID::CTFWeaponBaseMerasmusGrenade: + case ETFClassID::CTFGrenadePipebombProjectile: + case ETFClassID::CTFStunBall: + case ETFClassID::CTFBall_Ornament: + case ETFClassID::CTFProjectile_Jar: + case ETFClassID::CTFProjectile_Cleaver: + case ETFClassID::CTFProjectile_JarGas: + case ETFClassID::CTFProjectile_JarMilk: + case ETFClassID::CTFProjectile_SpellBats: + case ETFClassID::CTFProjectile_SpellKartBats: + case ETFClassID::CTFProjectile_SpellMeteorShower: + case ETFClassID::CTFProjectile_SpellMirv: + case ETFClassID::CTFProjectile_SpellPumpkin: + case ETFClassID::CTFProjectile_SpellSpawnBoss: + case ETFClassID::CTFProjectile_SpellSpawnHorde: + case ETFClassID::CTFProjectile_SpellSpawnZombie: + case ETFClassID::CTFProjectile_SpellTransposeTeleport: + case ETFClassID::CTFProjectile_Throwable: + case ETFClassID::CTFProjectile_ThrowableBreadMonster: + case ETFClassID::CTFProjectile_ThrowableBrick: + case ETFClassID::CTFProjectile_ThrowableRepel: + { + auto pOwner = pEntity->As()->m_hThrower().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Projectiles.Value, Vars::Chams::Enemy::Projectiles.Value); + } + case ETFClassID::CTFBaseRocket: + case ETFClassID::CTFFlameRocket: + case ETFClassID::CTFProjectile_Arrow: + case ETFClassID::CTFProjectile_GrapplingHook: + case ETFClassID::CTFProjectile_HealingBolt: + case ETFClassID::CTFProjectile_Rocket: + //case ETFClassID::CTFProjectile_BallOfFire: // lifetime too short + case ETFClassID::CTFProjectile_MechanicalArmOrb: + case ETFClassID::CTFProjectile_SentryRocket: // not drawn, no weapon + case ETFClassID::CTFProjectile_SpellFireball: + case ETFClassID::CTFProjectile_SpellLightningOrb: + case ETFClassID::CTFProjectile_SpellKartOrb: + case ETFClassID::CTFProjectile_EnergyBall: + case ETFClassID::CTFProjectile_Flare: + { + auto pWeapon = pEntity->As()->m_hLauncher().Get(); + if (!pWeapon) + return false; + + auto pOwner = pWeapon->As()->m_hOwner().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Projectiles.Value, Vars::Chams::Enemy::Projectiles.Value); + } + case ETFClassID::CTFBaseProjectile: + case ETFClassID::CTFProjectile_EnergyRing: // not drawn, shoulddraw check, small anyways + //case ETFClassID::CTFProjectile_Syringe: // not drawn + { + auto pWeapon = pEntity->As()->m_hLauncher().Get(); + if (!pWeapon) + return false; + + auto pOwner = pWeapon->As()->m_hOwner().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Projectiles.Value, Vars::Chams::Enemy::Projectiles.Value); + } + // npc chams + case ETFClassID::CHeadlessHatman: + case ETFClassID::CTFTankBoss: + case ETFClassID::CMerasmus: + case ETFClassID::CZombie: + case ETFClassID::CEyeballBoss: + *pChams = GetStruct(Vars::Chams::World::VisibleMaterial.Value, Vars::Chams::World::OccludedMaterial.Value, Vars::Chams::World::VisibleColor.Value, Vars::Chams::World::OccludedColor.Value); + return Vars::Chams::World::NPCs.Value; + // pickup chams + case ETFClassID::CTFAmmoPack: + case ETFClassID::CCurrencyPack: + case ETFClassID::CHalloweenGiftPickup: + *pChams = GetStruct(Vars::Chams::World::VisibleMaterial.Value, Vars::Chams::World::OccludedMaterial.Value, Vars::Chams::World::VisibleColor.Value, Vars::Chams::World::OccludedColor.Value); + return Vars::Chams::World::Pickups.Value; + case ETFClassID::CBaseAnimating: + { + if (H::Entities.IsAmmo(pEntity) || H::Entities.IsHealth(pEntity) || H::Entities.IsSpellbook(pEntity)) + { + *pChams = GetStruct(Vars::Chams::World::VisibleMaterial.Value, Vars::Chams::World::OccludedMaterial.Value, Vars::Chams::World::VisibleColor.Value, Vars::Chams::World::OccludedColor.Value); + return Vars::Chams::World::Pickups.Value; + } + break; + } + // bomb chams + case ETFClassID::CTFPumpkinBomb: + case ETFClassID::CTFGenericBomb: + *pChams = GetStruct(Vars::Chams::World::VisibleMaterial.Value, Vars::Chams::World::OccludedMaterial.Value, Vars::Chams::World::VisibleColor.Value, Vars::Chams::World::OccludedColor.Value); + return Vars::Chams::World::Bombs.Value; + } + + // player chams + if (auto pWeapon = pEntity->As()) + { + auto pOwner = pWeapon->m_hOwnerEntity().Get(); + if (!pOwner) + return false; + + return GetPlayerChams(pOwner->As(), pLocal, pChams, Vars::Chams::Friendly::Players.Value, Vars::Chams::Enemy::Players.Value); + } + + return false; +} + +void CChams::StencilBegin(IMatRenderContext* pRenderContext, bool bTwoModels) +{ + if (!bTwoModels) + return; + + pRenderContext->SetStencilEnable(true); +} +void CChams::StencilVisible(IMatRenderContext* pRenderContext, bool bTwoModels) +{ + if (!bTwoModels) + return; + + pRenderContext->ClearBuffers(false, false, false); + pRenderContext->SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS); + pRenderContext->SetStencilPassOperation(STENCILOPERATION_REPLACE); + pRenderContext->SetStencilFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilZFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilReferenceValue(1); + pRenderContext->SetStencilWriteMask(0xFF); + pRenderContext->SetStencilTestMask(0x0); +} +void CChams::StencilOccluded(IMatRenderContext* pRenderContext) +{ + pRenderContext->ClearBuffers(false, false, false); + pRenderContext->SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL); + pRenderContext->SetStencilPassOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilZFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilReferenceValue(0); + pRenderContext->SetStencilWriteMask(0x0); + pRenderContext->SetStencilTestMask(0xFF); + pRenderContext->DepthRange(0.f, 0.2f); +} +void CChams::StencilEnd(IMatRenderContext* pRenderContext, bool bTwoModels) +{ + if (!bTwoModels) + return; + + pRenderContext->SetStencilEnable(false); + pRenderContext->DepthRange(0.f, 1.f); +} + +void CChams::DrawModel(CBaseEntity* pEntity, Chams_t chams, IMatRenderContext* pRenderContext, bool bTwoModels) +{ + mEntities[pEntity->entindex()] = true; + bRendering = true; + + auto visibleMaterials = chams.VisibleMaterial.size() ? chams.VisibleMaterial : std::vector{ "None" }; + auto occludedMaterials = chams.OccludedMaterial.size() ? chams.OccludedMaterial : std::vector{ "None" }; + + StencilBegin(pRenderContext, bTwoModels); + + StencilVisible(pRenderContext, bTwoModels); + for (auto it = visibleMaterials.begin(); it != visibleMaterials.end(); it++) + { + auto material = F::Materials.GetMaterial(*it); + + F::Materials.SetColor(material, chams.VisibleColor, it + 1 == visibleMaterials.end()); // only apply color to last material + I::ModelRender->ForcedMaterialOverride(material); + pEntity->DrawModel(STUDIO_RENDER); + } + if (bTwoModels) + { + StencilOccluded(pRenderContext); + for (auto it = occludedMaterials.begin(); it != occludedMaterials.end(); it++) + { + auto material = F::Materials.GetMaterial(*it); + + F::Materials.SetColor(material, chams.OccludedColor, it + 1 == occludedMaterials.end()); + I::ModelRender->ForcedMaterialOverride(material); + pEntity->DrawModel(STUDIO_RENDER); + } + } + + StencilEnd(pRenderContext, bTwoModels); + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + I::ModelRender->ForcedMaterialOverride(nullptr); + + bRendering = false; +} + + + +void CChams::RenderMain(CTFPlayer* pLocal) +{ + const auto pRenderContext = I::MaterialSystem->GetRenderContext(); + if (!pLocal || !pRenderContext) + return; + + // main + for (int n = 1; n < I::ClientEntityList->GetHighestEntityIndex(); n++) + { + auto pEntity = I::ClientEntityList->GetClientEntity(n)->As(); + if (!pEntity) + continue; + + Chams_t chams = {}; + if (GetChams(pLocal, pEntity, &chams) && SDK::IsOnScreen(pEntity)) + DrawModel(pEntity, chams, pRenderContext); + } + + // backtrack / fakeangle + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (!pPlayer->ShouldDraw() || pPlayer->IsDormant()) + continue; + + bRendering = bExtra = true; + + const float flOldInvisibility = pPlayer->m_flInvisibility(); + if (flOldInvisibility > 0.999f) + pPlayer->m_flInvisibility() = 0.f; + + pPlayer->DrawModel(STUDIO_RENDER); + + if (flOldInvisibility > 0.999f) + pPlayer->m_flInvisibility() = flOldInvisibility; + + bRendering = bExtra = false; + } +} + +void CChams::RenderBacktrack(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + if (!Vars::Backtrack::Enabled.Value || !Vars::Chams::Backtrack::Enabled.Value) + return; + + const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]; + if (!ModelRender_DrawModelExecute) + return; + + auto pEntity = I::ClientEntityList->GetClientEntity(pInfo.entity_index)->As(); + if (!pEntity || !pEntity->IsPlayer() || !pEntity->IsAlive()) + return; + + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + if (!pLocal || !pWeapon || G::WeaponType == EWeaponType::PROJECTILE) + return; + if (pEntity == pLocal || + pWeapon->m_iItemDefinitionIndex() != Soldier_t_TheDisciplinaryAction && pWeapon->m_iWeaponID() != TF_WEAPON_MEDIGUN && pEntity->m_iTeamNum() == pLocal->m_iTeamNum() || + pWeapon->m_iWeaponID() == TF_WEAPON_MEDIGUN && pEntity->m_iTeamNum() != pLocal->m_iTeamNum()) + return; + + + + auto drawModel = [ModelRender_DrawModelExecute, pEntity](Vec3& vOrigin, std::vector materials, Color_t color, const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) + { + if (!SDK::IsOnScreen(pEntity, vOrigin)) + return; + + for (auto it = materials.begin(); it != materials.end(); it++) + { + auto material = F::Materials.GetMaterial(*it); + + F::Materials.SetColor(material, color, it + 1 == materials.end()); + I::ModelRender->ForcedMaterialOverride(material ? material : nullptr); + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, pBoneToWorld); + } + + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + I::ModelRender->ForcedMaterialOverride(nullptr); + }; + + + + auto& vMaterials = Vars::Chams::Backtrack::VisibleMaterial.Value; + auto& sColor = Vars::Chams::Backtrack::VisibleColor.Value; + + auto pRecords = F::Backtrack.GetRecords(pEntity); + auto vRecords = F::Backtrack.GetValidRecords(pRecords); + if (!vRecords.size()) + return; + + switch (Vars::Chams::Backtrack::Draw.Value) + { + case 0: // last + { + auto vLastRec = vRecords.end() - 1; + if (vLastRec != vRecords.end() && pEntity->GetAbsOrigin().DistTo(vLastRec->vOrigin) > 0.1f) + drawModel(vLastRec->vOrigin, vMaterials, sColor, pState, pInfo, reinterpret_cast(&vLastRec->BoneMatrix)); + break; + } + case 1: // last + first + { + auto vFirstRec = vRecords.begin(); + if (vFirstRec != vRecords.end() && pEntity->GetAbsOrigin().DistTo(vFirstRec->vOrigin) > 0.1f) + drawModel(vFirstRec->vOrigin, vMaterials, sColor, pState, pInfo, reinterpret_cast(&vFirstRec->BoneMatrix)); + auto vLastRec = vRecords.end() - 1; + if (vLastRec != vRecords.end() && pEntity->GetAbsOrigin().DistTo(vLastRec->vOrigin) > 0.1f) + drawModel(vLastRec->vOrigin, vMaterials, sColor, pState, pInfo, reinterpret_cast(&vLastRec->BoneMatrix)); + break; + } + case 2: // all + { + for (auto& record : vRecords) + { + if (pEntity->GetAbsOrigin().DistTo(record.vOrigin) < 0.1f) + continue; + + drawModel(record.vOrigin, vMaterials, sColor, pState, pInfo, reinterpret_cast(&record.BoneMatrix)); + } + } + } +} +void CChams::RenderFakeAngle(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + if (!Vars::Chams::FakeAngle::Enabled.Value || pInfo.entity_index != I::EngineClient->GetLocalPlayer() || !F::FakeAngle.DrawChams || !F::FakeAngle.BonesSetup) + return; + + const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]; + if (!ModelRender_DrawModelExecute) + return; + + + + auto& vMaterials = Vars::Chams::FakeAngle::VisibleMaterial.Value; + auto& sColor = Vars::Chams::FakeAngle::VisibleColor.Value; + + for (auto it = vMaterials.begin(); it != vMaterials.end(); it++) + { + auto material = F::Materials.GetMaterial(*it); + + F::Materials.SetColor(material, sColor, it + 1 == vMaterials.end()); + I::ModelRender->ForcedMaterialOverride(material ? material : nullptr); + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, F::FakeAngle.BoneMatrix); + } + + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + I::ModelRender->ForcedMaterialOverride(nullptr); +} +void CChams::RenderHandler(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + if (!bExtra) + { + if (const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]) + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, pBoneToWorld); + } + else + { + RenderBacktrack(pState, pInfo, pBoneToWorld); + RenderFakeAngle(pState, pInfo, pBoneToWorld); + } +} + +bool CChams::RenderViewmodel(void* ecx, int flags, int* iReturn) +{ + if (!Vars::Chams::Viewmodel::Weapon.Value) + return false; + + const auto CBaseAnimating_DrawModel = U::Hooks.m_mHooks["CBaseAnimating_DrawModel"]; + if (!CBaseAnimating_DrawModel) + return false; + + + + auto& vMaterials = Vars::Chams::Viewmodel::VisibleMaterial.Value; + auto& sColor = Vars::Chams::Viewmodel::VisibleColor.Value; + + for (auto it = vMaterials.begin(); it != vMaterials.end(); it++) + { + auto material = F::Materials.GetMaterial(*it); + + F::Materials.SetColor(material, sColor, it + 1 == vMaterials.end()); + I::ModelRender->ForcedMaterialOverride(material ? material : nullptr); + *iReturn = CBaseAnimating_DrawModel->Original()(ecx, flags); + } + + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + I::ModelRender->ForcedMaterialOverride(nullptr); + + return true; +} +bool CChams::RenderViewmodel(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + if (!Vars::Chams::Viewmodel::Hands.Value) + return false; + + const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]; + if (!ModelRender_DrawModelExecute) + return false; + + + + auto& vMaterials = Vars::Chams::Viewmodel::VisibleMaterial.Value; + auto& sColor = Vars::Chams::Viewmodel::VisibleColor.Value; + + for (auto it = vMaterials.begin(); it != vMaterials.end(); it++) + { + auto material = F::Materials.GetMaterial(*it); + + F::Materials.SetColor(material, sColor, it + 1 == vMaterials.end()); + I::ModelRender->ForcedMaterialOverride(material ? material : nullptr); + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, pBoneToWorld); + } + + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + I::ModelRender->ForcedMaterialOverride(nullptr); + + return true; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Chams/Chams.h b/Amalgam/src/Features/Visuals/Chams/Chams.h new file mode 100644 index 0000000..2213123 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Chams/Chams.h @@ -0,0 +1,38 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CChams +{ + Chams_t GetStruct( + std::vector VisibleMaterial = { "Original" }, + std::vector OccludedMaterial = {}, + Color_t VisibleColor = { 255, 255, 255, 255 }, + Color_t OccludedColor = { 255, 255, 255, 255 } + ); + bool GetPlayerChams(CTFPlayer* pEntity, CTFPlayer* pLocal, Chams_t* pChams, bool bFriendly, bool bEnemy); + bool GetChams(CTFPlayer* pLocal, CBaseEntity* pEntity, Chams_t* pChams); + + void StencilBegin(IMatRenderContext* pRenderContext, bool bTwoModels = false); + void StencilVisible(IMatRenderContext* pRenderContext, bool bTwoModels = false); + void StencilOccluded(IMatRenderContext* pRenderContext); + void StencilEnd(IMatRenderContext* pRenderContext, bool bTwoModels = false); + + void DrawModel(CBaseEntity* pEntity, Chams_t chams, IMatRenderContext* pRenderContext, bool bTwoModels = true); + + void RenderBacktrack(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld); + void RenderFakeAngle(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld); + +public: + void RenderMain(CTFPlayer* pLocal); + void RenderHandler(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld); + + bool RenderViewmodel(void* ecx, int flags, int* iReturn); + bool RenderViewmodel(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld); + + bool bRendering = false; + bool bExtra = false; + + std::unordered_map mEntities = {}; +}; + +ADD_FEATURE(CChams, Chams) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/ESP/ESP.cpp b/Amalgam/src/Features/Visuals/ESP/ESP.cpp new file mode 100644 index 0000000..afe4f0a --- /dev/null +++ b/Amalgam/src/Features/Visuals/ESP/ESP.cpp @@ -0,0 +1,771 @@ +#include "ESP.h" + +#include "../../Backtrack/Backtrack.h" +#include "../../Players/PlayerUtils.h" + +MAKE_SIGNATURE(CTFPlayerSharedUtils_GetEconItemViewByLoadoutSlot, "client.dll", "48 89 6C 24 ? 56 41 54 41 55 41 56 41 57 48 83 EC", 0x0); +MAKE_SIGNATURE(CEconItemView_GetItemName, "client.dll", "40 53 48 83 EC ? 48 8B D9 C6 81 ? ? ? ? ? E8 ? ? ? ? 48 8B 8B", 0x0); + +void CESP::Run(CTFPlayer* pLocal) +{ + if (!Vars::ESP::Draw.Value) + return; + + DrawWorld(); + DrawBuildings(pLocal); + DrawPlayers(pLocal); +} + +bool CESP::GetDrawBounds(CBaseEntity* pEntity, int& x, int& y, int& w, int& h) +{ + Vec3 vMins = pEntity->m_vecMins(), vMaxs = pEntity->m_vecMaxs(); + + auto& transform = const_cast(pEntity->RenderableToWorldTransform()); + if (pEntity && pEntity->entindex() == I::EngineClient->GetLocalPlayer()) + { + Vec3 vAngles = I::EngineClient->GetViewAngles(); + vAngles.x = vAngles.z = 0.f; + Math::AngleMatrix(vAngles, transform); + Math::MatrixSetColumn(pEntity->GetAbsOrigin(), 3, transform); + } + + float flLeft, flRight, flTop, flBottom; + if (!SDK::IsOnScreen(pEntity, transform, &flLeft, &flRight, &flTop, &flBottom)) + return false; + + x = flLeft + (flRight - flLeft) / 8.f; + y = flBottom; + w = flRight - flLeft - (flRight - flLeft) / 8.f * 2.f; + h = flTop - flBottom; + + return !(x > H::Draw.m_nScreenW || x + w < 0 || y > H::Draw.m_nScreenH || y + h < 0); +} + +void CESP::DrawPlayers(CTFPlayer* pLocal) +{ + if (!Vars::ESP::Player.Value) + return; + + auto pResource = H::Entities.GetPR(); + if (!pResource) + return; + + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + + const int nIndex = pPlayer->entindex(); + if (!pPlayer->IsAlive() || pPlayer->IsAGhost()) + continue; + + if (pPlayer->IsDormant()) + { + if (!Vars::ESP::DormantAlpha.Value) + continue; + if (Vars::ESP::DormantPriority.Value) + { + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(nIndex, &pi) && F::PlayerUtils.GetPriority(pi.friendsID) <= F::PlayerUtils.mTags["Default"].Priority) + continue; + } + } + + if (nIndex != I::EngineClient->GetLocalPlayer()) + { + if (!(Vars::ESP::Draw.Value & 1 << 2 && H::Entities.IsFriend(nIndex))) + { + if (!(Vars::ESP::Draw.Value & 1 << 0) && pPlayer->m_iTeamNum() != pLocal->m_iTeamNum()) + continue; + if (!(Vars::ESP::Draw.Value & 1 << 1) && pPlayer->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + } + } + else if (!(Vars::ESP::Draw.Value & 1 << 3) || !I::Input->CAM_IsThirdPerson()) + continue; + + I::MatSystemSurface->DrawSetAlphaMultiplier((pPlayer->IsDormant() ? Vars::ESP::DormantAlpha.Value : Vars::ESP::ActiveAlpha.Value) / 255.f); + + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pPlayer, x, y, w, h)) + { + int lOffset = 0, rOffset = 0, bOffset = 2, tOffset = 0; + const auto& fFont = H::Fonts.GetFont(FONT_ESP); + + const Color_t drawColor = H::Color.GetEntityDrawColor(pLocal, pPlayer, Vars::Colors::Relative.Value); //GetTeamColor(pPlayer->m_iTeamNum(), Vars::Colors::Relative.Value); + const int iMaxHealth = pPlayer->m_iMaxHealth(), iHealth = pPlayer->IsDormant() ? pResource->GetHealth(pPlayer->entindex()) : pPlayer->m_iHealth(), iClassNum = pPlayer->m_iClass(); + + // Bones + if (Vars::ESP::Player.Value & 1 << 11) + { + DrawBones(pPlayer, { 8, 7, 6, 4 }, drawColor); + DrawBones(pPlayer, { 11, 10, 9, 4 }, drawColor); + DrawBones(pPlayer, { 0, 4, 1 }, drawColor); + DrawBones(pPlayer, { 14, 13, 1 }, drawColor); + DrawBones(pPlayer, { 17, 16, 1 }, drawColor); + } + + // Box + if (Vars::ESP::Player.Value & 1 << 10) + H::Draw.LineRectOutline(x, y, w, h, drawColor, { 0, 0, 0, 255 }); + + // Health bar + if (Vars::ESP::Player.Value & 1 << 1) + { + float flRatio = std::clamp(float(iHealth) / iMaxHealth, 0.f, 1.f); + Color_t cColor = Vars::Colors::HealthBar.Value.StartColor.Lerp(Vars::Colors::HealthBar.Value.EndColor, flRatio); + H::Draw.FillRectPercent(x - 6, y, 2, h, flRatio, cColor, { 0, 0, 0, 255 }, ALIGN_BOTTOM, true); + + if (iHealth > iMaxHealth) + { + const float flMaxOverheal = floorf(iMaxHealth / 10.f) * 5; + flRatio = std::clamp((iHealth - iMaxHealth) / flMaxOverheal, 0.f, 1.f); + cColor = Vars::Colors::Overheal.Value; + H::Draw.FillRectPercent(x - 6, y, 2, h, flRatio, cColor, { 0, 0, 0, 0 }, ALIGN_BOTTOM, true); + } + + lOffset += 5; + } + + // Health text + if (Vars::ESP::Player.Value & 1 << 2) + H::Draw.String(fFont, x - 5 - lOffset, y + h - h * (float(std::min(iHealth, iMaxHealth)) / iMaxHealth) - 2, iHealth > iMaxHealth ? Vars::Colors::Overheal.Value : Vars::Menu::Theme::Active.Value, ALIGN_TOPRIGHT, "%d", iHealth); + + // Ubercharge bar/text + if (iClassNum == TF_CLASS_MEDIC) + { + if (auto pMedGun = pPlayer->GetWeaponFromSlot(SLOT_SECONDARY)) + { + if (Vars::ESP::Player.Value & 1 << 3) + { + const float flMaxUber = (pMedGun->m_iItemDefinitionIndex() == Medic_s_TheVaccinator ? 400.f : 100.f); + const float flUber = std::min(pMedGun->As()->m_flChargeLevel() * flMaxUber, flMaxUber); + float ratio = flUber / flMaxUber; + + H::Draw.FillRectPercent(x, y + h + 4, w, 2, ratio, Vars::Colors::UberBar.Value); + + bOffset += 5; + } + + if (Vars::ESP::Player.Value & 1 << 4) + H::Draw.String(fFont, x + w + 4, y + h, Vars::Menu::Theme::Active.Value, ALIGN_TOPLEFT, L"%.f%%", std::clamp(pMedGun->As()->m_flChargeLevel() * 100.f, 0.f, 100.f)); + } + } + + // Name + priority text + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(nIndex, &pi)) + { + const int middle = x + w / 2; + if (Vars::ESP::Player.Value & 1 << 0) + { + tOffset += fFont.m_nTall + 2; + H::Draw.String(fFont, middle, y - tOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, SDK::ConvertUtf8ToWide(pi.name).data()); + } + + if (Vars::ESP::Player.Value & 1 << 12) + { + std::string sTag; PriorityLabel_t plTag; + if (F::PlayerUtils.GetSignificantTag(pi.friendsID, &sTag, &plTag, 1)) + { + tOffset += fFont.m_nTall + 2; + H::Draw.String(fFont, middle, y - tOffset, plTag.Color, ALIGN_TOP, sTag.c_str()); + } + } + + if (Vars::ESP::Player.Value & 1 << 13) + { + std::vector> vLabels = {}; + for (const auto& sTag : F::PlayerUtils.mPlayerTags[pi.friendsID]) + { + PriorityLabel_t plTag; + if (F::PlayerUtils.GetTag(sTag, &plTag) && plTag.Label) + vLabels.push_back({ sTag, plTag }); + } + if (H::Entities.IsFriend(nIndex)) + { + const auto& plTag = F::PlayerUtils.mTags["Friend"]; + if (plTag.Label) + vLabels.push_back({ "Friend", plTag }); + } + + if (vLabels.size()) + { + std::sort(vLabels.begin(), vLabels.end(), [&](const auto& a, const auto& b) -> bool + { + // sort by priority if unequal + if (a.second.Priority != b.second.Priority) + return a.second.Priority > b.second.Priority; + + return a.first < b.first; + }); + + for (const auto& pLabel : vLabels) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, pLabel.second.Color, ALIGN_TOPLEFT, pLabel.first.c_str()); + rOffset += fFont.m_nTall; + } + } + } + } + + // Class icon + if (Vars::ESP::Player.Value & 1 << 5) + { + const int size = 18 * Vars::Menu::DPI.Value; + H::Draw.Texture(x + w / 2, y - tOffset, size, size, iClassNum - 1, ALIGN_BOTTOM); + } + + // Class text + if (Vars::ESP::Player.Value & 1 << 6) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOPLEFT, L"%ls", GetPlayerClass(iClassNum)); + rOffset += fFont.m_nTall; + } + + // Distance + if (Vars::ESP::Player.Value & 1 << 9) + { + if (pPlayer != pLocal) + { + const Vec3 vDelta = pPlayer->GetAbsOrigin() - pLocal->GetAbsOrigin(); + const int iDistance = round(vDelta.Length2D() / 41.f); + + H::Draw.String(fFont, x + w / 2, y + h + bOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, L"%dM", iDistance); + bOffset += fFont.m_nTall; + } + } + + auto pWeapon = pPlayer->m_hActiveWeapon().Get()->As(); + if (pWeapon) + { + // Weapon text + if (Vars::ESP::Player.Value & 1 << 8) + { + static auto getEconItemViewByLoadoutSlot = reinterpret_cast(S::CTFPlayerSharedUtils_GetEconItemViewByLoadoutSlot()); + static auto getItemName = reinterpret_cast(S::CEconItemView_GetItemName()); + + int iWeaponSlot = pWeapon->m_iSlot(); + int iPlayerClass = pPlayer->m_iClass(); + + const char* szItemName = ""; + + switch (iPlayerClass) + { + case TF_CLASS_SPY: + { + switch (iWeaponSlot) + { + // Primary (gun) + case 0: iWeaponSlot = 1; break; + // Sapper ???? + case 1: iWeaponSlot = 4; break; + // Knife + //case 2: + // Disguise kit + case 3: iWeaponSlot = 5; break; + } + break; + } + case TF_CLASS_ENGINEER: + { + switch (iWeaponSlot) + { + case 3: iWeaponSlot = 5; break; + case 4: iWeaponSlot = 6; break; + } + break; + } + } + + void* pCurItemData = getEconItemViewByLoadoutSlot(pPlayer, iWeaponSlot, 0); + if (pCurItemData) + { + szItemName = getItemName(pCurItemData); + H::Draw.String(fFont, x + (w / 2), y + h + bOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, "%ls", szItemName); + bOffset += fFont.m_nTall; + } + } + + // Weapon icons + if (Vars::ESP::Player.Value & 1 << 7) + { + if (CHudTexture* pIcon = pWeapon->GetWeaponIcon()) + { + const float iw = pIcon->Width(), ih = pIcon->Height(); + const float scale = std::clamp(float(w) / std::max(iw, ih * 2), 0.25f, 0.75f) * Vars::Menu::DPI.Value; + H::Draw.DrawHudTexture(x + float(w) / 2.f - iw / 2.f * scale, y + h + 1 + bOffset, scale, pIcon, Vars::Menu::Theme::Active.Value); + } + } + } + + // Player conditions + { + // Lagcomp cond, idea from nitro + if (Vars::ESP::Player.Value & 1 << 17 && !pPlayer->IsDormant() && pPlayer != pLocal) + { + if (F::Backtrack.mLagCompensation[pPlayer]) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, { 255, 95, 95, 255 }, ALIGN_TOPLEFT, "LAGCOMP"); + rOffset += fFont.m_nTall; + } + } + + // Ping warning, idea from nitro + if (Vars::ESP::Player.Value & 1 << 18 && pPlayer != pLocal) + { + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (pNetChan && !pNetChan->IsLoopback()) + { + int iPing = pResource->GetPing(pPlayer->entindex()); + if (iPing && (iPing >= 200 || iPing <= 5)) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, { 255, 95, 95, 255 }, ALIGN_TOPLEFT, "%dMS", iPing); + rOffset += fFont.m_nTall; + } + } + } + + // Idea from rijin + if (Vars::ESP::Player.Value & 1 << 19 && pPlayer != pLocal) + { + const int iKills = pResource->GetKills(pPlayer->entindex()); + const int iDeaths = pResource->GetDeaths(pPlayer->entindex()); + if (iKills >= 20) + { + const int iKDR = iKills / std::max(iDeaths, 1); + if (iKDR >= 10) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, { 255, 95, 95, 255 }, ALIGN_TOPLEFT, "HIGH K/D [%d/%d]", iKills, iDeaths); + rOffset += fFont.m_nTall; + } + } + } + + { + auto drawCond = [&rOffset, &fFont](const char* text, Color_t color, int x, int y) + { + H::Draw.String(fFont, x, y + rOffset, color, ALIGN_TOPLEFT, text); + rOffset += fFont.m_nTall; + }; + + // Buffs + if (Vars::ESP::Player.Value & 1 << 14) + { + if (pPlayer->IsCritBoosted()) + drawCond("CRITS", { 255, 107, 108, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_ENERGY_BUFF) || + pPlayer->InCond(TF_COND_NOHEALINGDAMAGEBUFF)) + drawCond("MINI-CRITS", { 254, 202, 87, 255 }, x + w + 4, y); + + if (pPlayer->m_iHealth() > pPlayer->m_iMaxHealth()) + drawCond("HP", Vars::Colors::Overheal.Value, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_HEALTH_BUFF) || pPlayer->InCond(TF_COND_MEGAHEAL) || pPlayer->IsBuffedByKing()) + drawCond("HP+", Vars::Colors::Overheal.Value, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_INVULNERABLE) || + pPlayer->InCond(TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED) || + pPlayer->InCond(TF_COND_INVULNERABLE_USER_BUFF) || + pPlayer->InCond(TF_COND_INVULNERABLE_CARD_EFFECT)) + drawCond("UBER", Vars::Colors::UberBar.Value, x + w + 4, y); + else if (pPlayer->InCond(TF_COND_PHASE)) + drawCond("BONK", { 254, 202, 87, 255 }, x + w + 4, y); + + /* vaccinator effects */ + if (pPlayer->InCond(TF_COND_MEDIGUN_UBER_BULLET_RESIST) || pPlayer->InCond(TF_COND_BULLET_IMMUNE)) + drawCond("BULLET+", { 255, 107, 108, 255 }, x + w + 4, y); + else if (pPlayer->InCond(TF_COND_MEDIGUN_SMALL_BULLET_RESIST)) + drawCond("BULLET", { 255, 107, 108, 255 }, x + w + 4, y); + if (pPlayer->InCond(TF_COND_MEDIGUN_UBER_BLAST_RESIST) || pPlayer->InCond(TF_COND_BLAST_IMMUNE)) + drawCond("BLAST+", { 255, 107, 108, 255 }, x + w + 4, y); + else if (pPlayer->InCond(TF_COND_MEDIGUN_SMALL_BLAST_RESIST)) + drawCond("BLAST", { 255, 107, 108, 255 }, x + w + 4, y); + if (pPlayer->InCond(TF_COND_MEDIGUN_UBER_FIRE_RESIST) || pPlayer->InCond(TF_COND_FIRE_IMMUNE)) + drawCond("FIRE+", { 255, 107, 108, 255 }, x + w + 4, y); + else if (pPlayer->InCond(TF_COND_MEDIGUN_SMALL_FIRE_RESIST)) + drawCond("FIRE", { 255, 107, 108, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_OFFENSEBUFF)) + drawCond("BANNER", drawColor, x + w + 4, y); + if (pPlayer->InCond(TF_COND_DEFENSEBUFF)) + drawCond("BATTALIONS", drawColor, x + w + 4, y); + if (pPlayer->InCond(TF_COND_REGENONDAMAGEBUFF)) + drawCond("CONCH", drawColor, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_BLASTJUMPING)) + drawCond("BLASTJUMP", { 254, 202, 87, 255 }, x + w + 4, y); + } + + // Debuffs + if (Vars::ESP::Player.Value & 1 << 15) + { + if (pPlayer->InCond(TF_COND_URINE)) + drawCond("JARATE", { 254, 202, 87, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_MARKEDFORDEATH) || pPlayer->InCond(TF_COND_MARKEDFORDEATH_SILENT)) + drawCond("MARKED", { 254, 202, 87, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_BURNING)) + drawCond("BURN", { 254, 202, 87, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_MAD_MILK)) + drawCond("MILK", { 254, 202, 87, 255 }, x + w + 4, y); + } + + // Misc + if (Vars::ESP::Player.Value & 1 << 16) + { + if (Vars::Visuals::Removals::Taunts.Value && pPlayer->InCond(TF_COND_TAUNTING)) // i dont really see a need for this condition unless you have this enabled + drawCond("TAUNT", { 255, 100, 200, 255 }, x + w + 4, y); + + if (pPlayer->m_bFeignDeathReady()) + drawCond("DR", { 254, 202, 87, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_AIMING)) + { + if (pWeapon) + { + if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN) + drawCond("REV", { 128, 128, 128, 255 }, x + w + 4, y); + + if (pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW) + { + if ((I::GlobalVars->curtime - pWeapon->As()->m_flChargeBeginTime()) >= 1.f) + drawCond("CHARGED", { 254, 202, 87, 255 }, x + w + 4, y); + else + drawCond("CHARGING", { 254, 202, 87, 255 }, x + w + 4, y); + } + + if (pWeapon->m_iWeaponID() == TF_WEAPON_PARTICLE_CANNON) + drawCond("CHARGING", { 254, 202, 87, 255 }, x + w + 4, y); + } + } + + if (pPlayer->InCond(TF_COND_ZOOMED)) + drawCond("ZOOM", { 254, 202, 87, 255 }, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_STEALTHED) || pPlayer->InCond(TF_COND_STEALTHED_BLINK) || pPlayer->InCond(TF_COND_STEALTHED_USER_BUFF) || pPlayer->InCond(TF_COND_STEALTHED_USER_BUFF_FADING)) + drawCond(std::format("CLOAK {:.0f}%%", pPlayer->GetInvisPercentage()).c_str(), Vars::Colors::Cloak.Value, x + w + 4, y); + + if (pPlayer->InCond(TF_COND_DISGUISING) || pPlayer->InCond(TF_COND_DISGUISE_WEARINGOFF) || pPlayer->InCond(TF_COND_DISGUISED)) + drawCond("DISGUISE", { 254, 202, 87, 255 }, x + w + 4, y); + } + } + } + } + } + + I::MatSystemSurface->DrawSetAlphaMultiplier(1.f); +} + +void CESP::DrawBuildings(CTFPlayer* pLocal) +{ + if (!Vars::ESP::Building.Value) + return; + + I::MatSystemSurface->DrawSetAlphaMultiplier(Vars::ESP::ActiveAlpha.Value); + + for (auto pEntity : H::Entities.GetGroup(EGroupType::BUILDINGS_ALL)) + { + auto pBuilding = pEntity->As(); + + auto pOwner = pBuilding->m_hBuilder().Get(); + if (pOwner) + { + int nIndex = pOwner->entindex(); + if (nIndex != I::EngineClient->GetLocalPlayer()) + { + if (!(Vars::ESP::Draw.Value & 1 << 2 && H::Entities.IsFriend(nIndex))) + { + if (!(Vars::ESP::Draw.Value & 1 << 0) && pOwner->m_iTeamNum() != pLocal->m_iTeamNum()) + continue; + if (!(Vars::ESP::Draw.Value & 1 << 1) && pOwner->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + } + } + else if (!(Vars::ESP::Draw.Value & 1 << 3)) + continue; + } + else + { + if (!(Vars::ESP::Draw.Value & 1 << 0) && pBuilding->m_iTeamNum() != pLocal->m_iTeamNum()) + continue; + if (!(Vars::ESP::Draw.Value & 1 << 1) && pBuilding->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + } + + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pBuilding, x, y, w, h)) + { + int lOffset = 0, rOffset = 0, /*bOffset = 0, */tOffset = 0; + const auto& fFont = H::Fonts.GetFont(FONT_ESP); + + const Color_t drawColor = H::Color.GetEntityDrawColor(pLocal, pOwner ? pOwner : pBuilding, Vars::Colors::Relative.Value); //GetTeamColor(pBuilding->m_iTeamNum(), Vars::ESP::Main::Relative.Value); + const int iMaxHealth = pBuilding->m_iMaxHealth(), iHealth = std::min(pBuilding->m_iHealth(), iMaxHealth); + + const bool bIsMini = pBuilding->m_bMiniBuilding(); + + // Box + if (Vars::ESP::Building.Value & 1 << 4) + H::Draw.LineRectOutline(x, y, w, h, drawColor, { 0, 0, 0, 255 }); + + // Health bar + if (Vars::ESP::Building.Value & 1 << 1) + { + const float flRatio = float(iHealth) / iMaxHealth; + Color_t cColor = Vars::Colors::HealthBar.Value.StartColor.Lerp(Vars::Colors::HealthBar.Value.EndColor, flRatio); + H::Draw.FillRectPercent(x - 6, y, 2, h, flRatio, cColor, { 0, 0, 0, 255 }, ALIGN_BOTTOM, true); + + lOffset += 5; + } + + // Health text + if (Vars::ESP::Building.Value & 1 << 2) + H::Draw.String(fFont, x - 5 - lOffset, y + h - h * (float(iHealth) / iMaxHealth) - 2, Vars::Menu::Theme::Active.Value, ALIGN_TOPRIGHT, "%d", iHealth); + + // Name + if (Vars::ESP::Building.Value & 1 << 0) + { + const wchar_t* szName; + + switch (pBuilding->GetClassID()) + { + case ETFClassID::CObjectSentrygun: + szName = bIsMini ? L"Mini-Sentry" : L"Sentry"; + break; + case ETFClassID::CObjectDispenser: + szName = L"Dispenser"; + break; + case ETFClassID::CObjectTeleporter: + szName = pBuilding->m_iObjectMode() ? L"Teleporter Exit" : L"Teleporter Entrance"; + break; + default: szName = L"Unknown"; break; + } + + tOffset += fFont.m_nTall + 2; + H::Draw.String(fFont, x + w / 2, y - tOffset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, szName); + } + + // Distance + if (Vars::ESP::Building.Value & 1 << 3) + { + const Vec3 vDelta = pBuilding->GetAbsOrigin() - pLocal->GetAbsOrigin(); + const int iDistance = round(vDelta.Length2D() / 41.f); + + H::Draw.String(fFont, x + (w / 2), y + h, Vars::Menu::Theme::Active.Value, ALIGN_TOP, L"%dM", iDistance); + } + + // Building owner + if (Vars::ESP::Building.Value & 1 << 5 && !pBuilding->m_bWasMapPlaced() && pOwner) + { + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(pOwner->entindex(), &pi)) + { + tOffset += fFont.m_nTall + 2; + H::Draw.String(fFont, x + w / 2, y - tOffset, { 254, 202, 87, 255 }, ALIGN_TOP, L"%ls", SDK::ConvertUtf8ToWide(pi.name).data()); + } + } + + // Building level + if (Vars::ESP::Building.Value & 1 << 6 && !bIsMini) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, { 254, 202, 87, 255 }, ALIGN_TOPLEFT, L"%d/%d", pBuilding->m_iUpgradeLevel(), pBuilding->m_iHighestUpgradeLevel()); + rOffset += fFont.m_nTall; + } + + // Building conditions + if (Vars::ESP::Building.Value & 1 << 7) + { + std::vector condStrings{}; + + const float flConstructed = pBuilding->m_flPercentageConstructed() * 100.f; + if (flConstructed < 100.f && static_cast(flConstructed) != 0) + { + H::Draw.String(fFont, x + w + 4, y + rOffset, { 254, 202, 87, 255 }, ALIGN_TOPLEFT, L"BUILDING: %0.f%%", flConstructed); + rOffset += fFont.m_nTall; + } + + if (pBuilding->IsSentrygun() && pBuilding->As()->m_bPlayerControlled()) + condStrings.emplace_back(L"WRANGLED"); + + if (pBuilding->m_bHasSapper()) + condStrings.emplace_back(L"SAPPED"); + else if (pBuilding->m_bDisabled()) + condStrings.emplace_back(L"DISABLED"); + + if (pBuilding->IsSentrygun() && !pBuilding->m_bBuilding()) + { + int iShells; + int iMaxShells; + int iRockets; + int iMaxRockets; + + pBuilding->As()->GetAmmoCount(iShells, iMaxShells, iRockets, iMaxRockets); + + if (iShells == 0) + condStrings.emplace_back(L"NO AMMO"); + if (!bIsMini && iRockets == 0) + condStrings.emplace_back(L"NO ROCKETS"); + } + + if (!condStrings.empty()) + { + for (auto& condString : condStrings) + { + H::Draw.String(fFont, x + y + 2, y + rOffset, { 254, 202, 87, 255 }, ALIGN_TOPLEFT, condString.data()); + rOffset += fFont.m_nTall; + } + } + } + } + } + + I::MatSystemSurface->DrawSetAlphaMultiplier(1.f); +} + +void CESP::DrawWorld() +{ + Vec3 vScreen = {}; + const auto& fFont = H::Fonts.GetFont(FONT_ESP); + const int nTextTopOffset = fFont.m_nTall * (5 / 4); + + I::MatSystemSurface->DrawSetAlphaMultiplier(Vars::ESP::ActiveAlpha.Value); + + if (Vars::ESP::Draw.Value & 1 << 4) + { + for (auto NPC : H::Entities.GetGroup(EGroupType::WORLD_NPC)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(NPC, x, y, w, h)) + { + const wchar_t* szName; + switch (NPC->GetClassID()) + { + case ETFClassID::CHeadlessHatman: + szName = L"Horseless Headless Horsemann"; break; + case ETFClassID::CTFTankBoss: + szName = L"Tank"; break; + case ETFClassID::CMerasmus: + szName = L"Merasmus"; break; + case ETFClassID::CZombie: + szName = L"Skeleton"; break; + case ETFClassID::CEyeballBoss: + szName = L"Monoculus"; break; + default: + szName = L"Unknown"; break; + } + + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::NPC.Value, ALIGN_TOP, szName); + } + } + } + + if (Vars::ESP::Draw.Value & 1 << 5) + { + for (auto pHealth : H::Entities.GetGroup(EGroupType::WORLD_HEALTH)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pHealth, x, y, w, h)) + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::Health.Value, ALIGN_CENTER, L"Health"); + } + } + + if (Vars::ESP::Draw.Value & 1 << 6) + { + for (auto pAmmo : H::Entities.GetGroup(EGroupType::WORLD_AMMO)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pAmmo, x, y, w, h)) + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::Ammo.Value, ALIGN_CENTER, L"Ammo"); + } + } + + if (Vars::ESP::Draw.Value & 1 << 7) + { + for (auto pCash : H::Entities.GetGroup(EGroupType::WORLD_MONEY)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pCash, x, y, w, h)) + { + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::Money.Value, ALIGN_TOP, L"Money"); + } + } + } + + if (Vars::ESP::Draw.Value & 1 << 8) + { + for (auto pBomb : H::Entities.GetGroup(EGroupType::WORLD_BOMBS)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pBomb, x, y, w, h)) + { + const wchar_t* szName; + switch (pBomb->GetClassID()) + { + case ETFClassID::CTFPumpkinBomb: + szName = L"Pumpkin Bomb"; break; + case ETFClassID::CTFGenericBomb: + szName = L"Bomb"; break; + default: + szName = L"Unknown"; break; + } + + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::Bomb.Value, ALIGN_TOP, szName); + } + } + } + + if (Vars::ESP::Draw.Value & 1 << 9) + { + for (auto pBook : H::Entities.GetGroup(EGroupType::WORLD_SPELLBOOK)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pBook, x, y, w, h)) + { + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::Halloween.Value, ALIGN_TOP, L"Spellbook"); + } + } + } + + if (Vars::ESP::Draw.Value & 1 << 10) + { + for (auto pGargy : H::Entities.GetGroup(EGroupType::WORLD_GARGOYLE)) + { + int x = 0, y = 0, w = 0, h = 0; + if (GetDrawBounds(pGargy, x, y, w, h)) + { + H::Draw.String(fFont, x + w / 2, y - nTextTopOffset, Vars::Colors::Halloween.Value, ALIGN_TOP, L"Gargoyle"); + } + } + } + + I::MatSystemSurface->DrawSetAlphaMultiplier(1.f); +} + +const wchar_t* CESP::GetPlayerClass(int iClassNum) +{ + static const wchar_t* szClasses[] = { + L"Unknown", L"Scout", L"Sniper", L"Soldier", L"Demoman", + L"Medic", L"Heavy", L"Pyro", L"Spy", L"Engineer" + }; + + return iClassNum < 10 && iClassNum > 0 ? szClasses[iClassNum] : szClasses[0]; +} + +void CESP::DrawBones(CTFPlayer* pPlayer, std::vector vecBones, Color_t clr) +{ + const size_t nMax = vecBones.size(), nLast = nMax - 1; + for (size_t n = 0; n < nMax; n++) + { + if (n == nLast) + continue; + + const auto vBone = pPlayer->GetHitboxPos(vecBones[n]); + const auto vParent = pPlayer->GetHitboxPos(vecBones[n + 1]); + + Vec3 vScreenBone, vScreenParent; + if (SDK::W2S(vBone, vScreenBone) && SDK::W2S(vParent, vScreenParent)) + H::Draw.Line(vScreenBone.x, vScreenBone.y, vScreenParent.x, vScreenParent.y, clr); + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/ESP/ESP.h b/Amalgam/src/Features/Visuals/ESP/ESP.h new file mode 100644 index 0000000..06ed4a0 --- /dev/null +++ b/Amalgam/src/Features/Visuals/ESP/ESP.h @@ -0,0 +1,19 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CESP +{ +private: + static const wchar_t* GetPlayerClass(int nClassNum); + + void DrawPlayers(CTFPlayer* pLocal); + void DrawBuildings(CTFPlayer* pLocal); + void DrawWorld(); + static void DrawBones(CTFPlayer* pPlayer, std::vector vecBones, Color_t clr); + +public: + void Run(CTFPlayer* pLocal); + bool GetDrawBounds(CBaseEntity* pEntity, int& x, int& y, int& w, int& h); +}; + +ADD_FEATURE(CESP, ESP) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/FakeAngle/FakeAngle.cpp b/Amalgam/src/Features/Visuals/FakeAngle/FakeAngle.cpp new file mode 100644 index 0000000..1f1585c --- /dev/null +++ b/Amalgam/src/Features/Visuals/FakeAngle/FakeAngle.cpp @@ -0,0 +1,35 @@ +#include "FakeAngle.h" + +#include "../../PacketManip/AntiAim/AntiAim.h" + +void CFakeAngle::Run(CTFPlayer* pLocal) +{ + if (!pLocal || !pLocal->IsAlive() || pLocal->IsAGhost()) + return; + + auto pAnimState = pLocal->GetAnimState(); + if (!pAnimState) + return; + + F::AntiAim.vFakeAngles.x = std::clamp(F::AntiAim.vFakeAngles.x, -89.f, 89.f); + + float flOldFrameTime = I::GlobalVars->frametime; + int nOldSequence = pLocal->m_nSequence(); + float flOldCycle = pLocal->m_flCycle(); + auto& pOldPoseParams = pLocal->m_flPoseParameter(); + char pOldAnimState[sizeof(CTFPlayerAnimState)] = {}; + memcpy(pOldAnimState, pAnimState, sizeof(CTFPlayerAnimState)); + + I::GlobalVars->frametime = 0.f; + pAnimState->m_flCurrentFeetYaw = F::AntiAim.vFakeAngles.y; + pAnimState->m_flEyeYaw = F::AntiAim.vFakeAngles.y; + pAnimState->Update(F::AntiAim.vFakeAngles.y, F::AntiAim.vFakeAngles.x); + + BonesSetup = pLocal->SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, I::GlobalVars->curtime); + + I::GlobalVars->frametime = flOldFrameTime; + pLocal->m_nSequence() = nOldSequence; + pLocal->m_flCycle() = flOldCycle; + pLocal->m_flPoseParameter() = pOldPoseParams; + memcpy(pAnimState, pOldAnimState, sizeof(CTFPlayerAnimState)); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/FakeAngle/FakeAngle.h b/Amalgam/src/Features/Visuals/FakeAngle/FakeAngle.h new file mode 100644 index 0000000..19c0b73 --- /dev/null +++ b/Amalgam/src/Features/Visuals/FakeAngle/FakeAngle.h @@ -0,0 +1,15 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CFakeAngle +{ +public: + void Run(CTFPlayer* pLocal); + + matrix3x4 BoneMatrix[128]; + bool BonesSetup = false; + + bool DrawChams = false; +}; + +ADD_FEATURE(CFakeAngle, FakeAngle) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Glow/Glow.cpp b/Amalgam/src/Features/Visuals/Glow/Glow.cpp new file mode 100644 index 0000000..3d59506 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Glow/Glow.cpp @@ -0,0 +1,691 @@ +#include "Glow.h" + +#include "../Materials/Materials.h" +#include "../FakeAngle/FakeAngle.h" +#include "../../Backtrack/Backtrack.h" + +Glow_t CGlow::GetStruct(bool Stencil, bool Blur, int StencilScale, int BlurScale) +{ + return Glow_t{ + Stencil, + Blur, + StencilScale, + BlurScale + }; +} + +bool CGlow::GetPlayerGlow(CTFPlayer* pEntity, CTFPlayer* pLocal, Glow_t* pGlow, Color_t* pColor, bool bFriendly, bool bEnemy) +{ + if (Vars::Glow::Player::Local.Value && pEntity == pLocal) + { + *pGlow = GetStruct(Vars::Glow::Player::Stencil.Value, Vars::Glow::Player::Blur.Value, Vars::Glow::Player::StencilScale.Value, Vars::Glow::Player::BlurScale.Value); + *pColor = H::Color.GetEntityDrawColor(pLocal, pEntity, Vars::Colors::Relative.Value); + return true; + } + else if (Vars::Glow::Player::Friend.Value && H::Entities.IsFriend(pEntity->entindex())) + { + *pGlow = GetStruct(Vars::Glow::Player::Stencil.Value, Vars::Glow::Player::Blur.Value, Vars::Glow::Player::StencilScale.Value, Vars::Glow::Player::BlurScale.Value); + *pColor = H::Color.GetEntityDrawColor(pLocal, pEntity, Vars::Colors::Relative.Value); + return true; + } + + const bool bTeam = pEntity->m_iTeamNum() == pLocal->m_iTeamNum(); + *pGlow = bTeam + ? GetStruct(Vars::Glow::Friendly::Stencil.Value, Vars::Glow::Friendly::Blur.Value, Vars::Glow::Friendly::StencilScale.Value, Vars::Glow::Friendly::BlurScale.Value) + : GetStruct(Vars::Glow::Enemy::Stencil.Value, Vars::Glow::Enemy::Blur.Value, Vars::Glow::Enemy::StencilScale.Value, Vars::Glow::Enemy::BlurScale.Value); + *pColor = H::Color.GetEntityDrawColor(pLocal, pEntity, Vars::Colors::Relative.Value); + return bTeam ? bFriendly : bEnemy; +} + +bool CGlow::GetGlow(CTFPlayer* pLocal, CBaseEntity* pEntity, Glow_t* pGlow, Color_t* pColor) +{ + if (pEntity->IsDormant() || !pEntity->ShouldDraw()) + return false; + + switch (pEntity->GetClassID()) + { + // player glow + case ETFClassID::CTFPlayer: + return GetPlayerGlow(pEntity->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Players.Value, Vars::Glow::Enemy::Players.Value); + case ETFClassID::CTFWearable: + { + auto pOwner = pEntity->m_hOwnerEntity().Get(); + if (!pOwner) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Players.Value, Vars::Glow::Enemy::Players.Value); + } + // building glow + case ETFClassID::CObjectSentrygun: + case ETFClassID::CObjectDispenser: + case ETFClassID::CObjectTeleporter: + { + auto pOwner = pEntity->As()->m_hBuilder().Get(); + if (!pOwner) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Buildings.Value, Vars::Glow::Enemy::Buildings.Value); + } + // ragdoll glow + case ETFClassID::CRagdollPropAttached: + case ETFClassID::CRagdollProp: + case ETFClassID::CTFRagdoll: + { + auto pOwner = pEntity->As()->m_hPlayer().Get(); + if (!pOwner) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Ragdolls.Value, Vars::Glow::Enemy::Ragdolls.Value); + } + // projectile glow + case ETFClassID::CBaseGrenade: + case ETFClassID::CTFWeaponBaseGrenadeProj: + case ETFClassID::CTFWeaponBaseMerasmusGrenade: + case ETFClassID::CTFGrenadePipebombProjectile: + case ETFClassID::CTFStunBall: + case ETFClassID::CTFBall_Ornament: + case ETFClassID::CTFProjectile_Jar: + case ETFClassID::CTFProjectile_Cleaver: + case ETFClassID::CTFProjectile_JarGas: + case ETFClassID::CTFProjectile_JarMilk: + case ETFClassID::CTFProjectile_SpellBats: + case ETFClassID::CTFProjectile_SpellKartBats: + case ETFClassID::CTFProjectile_SpellMeteorShower: + case ETFClassID::CTFProjectile_SpellMirv: + case ETFClassID::CTFProjectile_SpellPumpkin: + case ETFClassID::CTFProjectile_SpellSpawnBoss: + case ETFClassID::CTFProjectile_SpellSpawnHorde: + case ETFClassID::CTFProjectile_SpellSpawnZombie: + case ETFClassID::CTFProjectile_SpellTransposeTeleport: + case ETFClassID::CTFProjectile_Throwable: + case ETFClassID::CTFProjectile_ThrowableBreadMonster: + case ETFClassID::CTFProjectile_ThrowableBrick: + case ETFClassID::CTFProjectile_ThrowableRepel: + { + auto pOwner = pEntity->As()->m_hThrower().Get(); + if (!pOwner) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Projectiles.Value, Vars::Glow::Enemy::Projectiles.Value); + } + case ETFClassID::CTFBaseRocket: + case ETFClassID::CTFFlameRocket: + case ETFClassID::CTFProjectile_Arrow: + case ETFClassID::CTFProjectile_GrapplingHook: + case ETFClassID::CTFProjectile_HealingBolt: + case ETFClassID::CTFProjectile_Rocket: + //case ETFClassID::CTFProjectile_BallOfFire: // lifetime too short + case ETFClassID::CTFProjectile_MechanicalArmOrb: + case ETFClassID::CTFProjectile_SentryRocket: // not drawn, no weapon + case ETFClassID::CTFProjectile_SpellFireball: + case ETFClassID::CTFProjectile_SpellLightningOrb: + case ETFClassID::CTFProjectile_SpellKartOrb: + case ETFClassID::CTFProjectile_EnergyBall: + case ETFClassID::CTFProjectile_Flare: + { + auto pWeapon = pEntity->As()->m_hLauncher().Get(); + if (!pWeapon) + return false; + + auto pOwner = pWeapon->As()->m_hOwner().Get(); + if (!pOwner) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Projectiles.Value, Vars::Glow::Enemy::Projectiles.Value); + } + case ETFClassID::CTFBaseProjectile: + case ETFClassID::CTFProjectile_EnergyRing: // not drawn, shoulddraw check, small anyways + //case ETFClassID::CTFProjectile_Syringe: // not drawn + { + auto pWeapon = pEntity->As()->m_hLauncher().Get(); + if (!pWeapon) + return false; + + auto pOwner = pWeapon->As()->m_hOwner().Get(); + if (!pOwner) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Projectiles.Value, Vars::Glow::Enemy::Projectiles.Value); + } + // npc glow + case ETFClassID::CHeadlessHatman: + case ETFClassID::CTFTankBoss: + case ETFClassID::CMerasmus: + case ETFClassID::CZombie: + case ETFClassID::CEyeballBoss: + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::NPC.Value; + return Vars::Glow::World::NPCs.Value; + // pickup glow + case ETFClassID::CTFAmmoPack: + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Ammo.Value; + return Vars::Glow::World::Pickups.Value; + case ETFClassID::CCurrencyPack: + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Money.Value; + return Vars::Glow::World::Pickups.Value; + case ETFClassID::CHalloweenGiftPickup: + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Halloween.Value; + return Vars::Glow::World::Halloween.Value; + case ETFClassID::CBaseAnimating: + { + if (H::Entities.IsAmmo(pEntity)) + { + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Ammo.Value; + return Vars::Glow::World::Pickups.Value; + } + if (H::Entities.IsHealth(pEntity)) + { + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Health.Value; + return Vars::Glow::World::Pickups.Value; + } + if (H::Entities.IsSpellbook(pEntity)) + { + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Halloween.Value; + return Vars::Glow::World::Halloween.Value; + } + break; + } + // bomb glow + case ETFClassID::CTFPumpkinBomb: + case ETFClassID::CTFGenericBomb: + *pGlow = GetStruct(Vars::Glow::World::Stencil.Value, Vars::Glow::World::Blur.Value, Vars::Glow::World::StencilScale.Value, Vars::Glow::World::BlurScale.Value); + *pColor = Vars::Colors::Bomb.Value; + return Vars::Glow::World::Bombs.Value; + } + + // player glow + if (auto pWeapon = pEntity->As()) + { + auto pOwner = pWeapon->m_hOwnerEntity().Get(); + if (!pOwner || !pOwner->IsPlayer()) + return false; + + return GetPlayerGlow(pOwner->As(), pLocal, pGlow, pColor, Vars::Glow::Friendly::Players.Value, Vars::Glow::Enemy::Players.Value); + } + + return false; +} + +void CGlow::SetupBegin(Glow_t glow, IMatRenderContext* pRenderContext, IMaterial* m_pMatBlurY) +{ + if (IMaterialVar* pVar = m_pMatBlurY->FindVar("$bloomamount", nullptr)) + pVar->SetFloatValue(glow.BlurScale); + + StencilBegin(pRenderContext); + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); +} +void CGlow::SetupMid(IMatRenderContext* pRenderContext, IMaterial* m_pMatGlowColor, int w, int h) +{ + I::ModelRender->ForcedMaterialOverride(m_pMatGlowColor); + + pRenderContext->PushRenderTargetAndViewport(); + pRenderContext->SetRenderTarget(m_pRenderBuffer1); + pRenderContext->Viewport(0, 0, w, h); + pRenderContext->ClearColor4ub(0, 0, 0, 0); + pRenderContext->ClearBuffers(true, false, false); +} +void CGlow::SetupEnd(Glow_t glow, IMatRenderContext* pRenderContext, IMaterial* m_pMatBlurX, IMaterial* m_pMatBlurY, IMaterial* m_pMatHaloAddToScreen, int w, int h) +{ + StencilEnd(pRenderContext); + pRenderContext->PopRenderTargetAndViewport(); + if (glow.Blur) + { + pRenderContext->PushRenderTargetAndViewport(); + { + pRenderContext->Viewport(0, 0, w, h); + pRenderContext->SetRenderTarget(m_pRenderBuffer2); + pRenderContext->DrawScreenSpaceRectangle(m_pMatBlurX, 0, 0, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->SetRenderTarget(m_pRenderBuffer1); + pRenderContext->DrawScreenSpaceRectangle(m_pMatBlurY, 0, 0, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + } + pRenderContext->PopRenderTargetAndViewport(); + } + + StencilPreDraw(pRenderContext); + if (glow.Stencil) + { + int side = float(glow.StencilScale + 1) / 2; + int corner = float(glow.StencilScale) / 2; + if (corner) + { + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, -corner, -corner, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, corner, corner, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, corner, -corner, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, -corner, corner, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + } + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, -side, 0, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, 0, -side, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, 0, side, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, side, 0, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + } + if (glow.Blur) + pRenderContext->DrawScreenSpaceRectangle(m_pMatHaloAddToScreen, 0, 0, w, h, 0.f, 0.f, w - 1, h - 1, w, h); + + StencilEnd(pRenderContext); + + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + I::ModelRender->ForcedMaterialOverride(nullptr); +} + +void CGlow::StencilBegin(IMatRenderContext* pRenderContext) +{ + pRenderContext->ClearBuffers(false, false, false); + pRenderContext->SetStencilEnable(true); + pRenderContext->SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS); + pRenderContext->SetStencilPassOperation(STENCILOPERATION_REPLACE); + pRenderContext->SetStencilFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilZFailOperation(STENCILOPERATION_REPLACE); + pRenderContext->SetStencilReferenceValue(1); + pRenderContext->SetStencilWriteMask(0xFF); + pRenderContext->SetStencilTestMask(0x0); +} +void CGlow::StencilPreDraw(IMatRenderContext* pRenderContext) +{ + pRenderContext->SetStencilEnable(true); + pRenderContext->SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL); + pRenderContext->SetStencilPassOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilZFailOperation(STENCILOPERATION_KEEP); + pRenderContext->SetStencilReferenceValue(0); + pRenderContext->SetStencilWriteMask(0x0); + pRenderContext->SetStencilTestMask(0xFF); +} +void CGlow::StencilEnd(IMatRenderContext* pRenderContext) +{ + pRenderContext->SetStencilEnable(false); +} + +void CGlow::DrawModel(CBaseEntity* pEntity, bool bModel) +{ + bRendering = true; + + if (bModel) + I::RenderView->SetBlend(0.f); + const float flOldInvisibility = pEntity->IsPlayer() ? pEntity->As()->m_flInvisibility() : -1.f; + if (flOldInvisibility > 0.999f) + pEntity->As()->m_flInvisibility() = 0.f; + + pEntity->DrawModel(bModel ? STUDIO_RENDER : (STUDIO_RENDER | STUDIO_NOSHADOWS)); + + if (flOldInvisibility > 0.999f) + pEntity->As()->m_flInvisibility() = flOldInvisibility; + if (bModel) + I::RenderView->SetBlend(1.f); + + bRendering = false; +} + + + +void CGlow::RenderMain(CTFPlayer* pLocal) +{ + mEntities.clear(); + const int w = H::Draw.m_nScreenW, h = H::Draw.m_nScreenH; + if (!pLocal || w < 1 || h < 1 || w > 4096 || h > 2160) + return; + + const auto pRenderContext = I::MaterialSystem->GetRenderContext(); + auto m_pMatGlowColor = F::Materials.mGlowMaterials["GlowColor"].pMaterial; + auto m_pMatBlurX = F::Materials.mGlowMaterials["BlurX"].pMaterial; + auto m_pMatBlurY = F::Materials.mGlowMaterials["BlurY"].pMaterial; + auto m_pMatHaloAddToScreen = F::Materials.mGlowMaterials["HaloAddToScreen"].pMaterial; + if (!pRenderContext || !m_pMatGlowColor || !m_pMatBlurX || !m_pMatBlurY || !m_pMatHaloAddToScreen) + return F::Materials.ReloadMaterials(); + + + + for (int n = 1; n < I::ClientEntityList->GetHighestEntityIndex(); n++) + { + auto pEntity = I::ClientEntityList->GetClientEntity(n)->As(); + if (!pEntity) + continue; + + Glow_t glow = {}; Color_t color = {}; + if (GetGlow(pLocal, pEntity, &glow, &color) && SDK::IsOnScreen(pEntity)) + mEntities[glow].push_back({ pEntity, color }); + } + + // main + for (const auto& [glow, entities] : mEntities) + { + SetupBegin(glow, pRenderContext, m_pMatBlurY); + for (auto& info : entities) + DrawModel(info.m_pEntity, true); + + StencilEnd(pRenderContext); + + SetupMid(pRenderContext, m_pMatGlowColor, w, h); + for (auto& info : entities) + { + I::RenderView->SetColorModulation(float(info.m_Color.r) / 255.f, float(info.m_Color.g) / 255.f, float(info.m_Color.b) / 255.f); + I::RenderView->SetBlend(float(info.m_Color.a) / 255.f); + DrawModel(info.m_pEntity, false); + } + + SetupEnd(glow, pRenderContext, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen, w, h); + } + + // backtrack / fakeangle + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (!pPlayer->ShouldDraw() || pPlayer->IsDormant()) + continue; + + bRendering = bExtra = true; + + const float flOldInvisibility = pPlayer->m_flInvisibility(); + if (flOldInvisibility > 0.999f) + pPlayer->m_flInvisibility() = 0.f; + + pPlayer->DrawModel(STUDIO_RENDER); + + if (flOldInvisibility > 0.999f) + pPlayer->m_flInvisibility() = flOldInvisibility; + + bRendering = bExtra = false; + } +} + +void CGlow::RenderBacktrack(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld, + int w, int h, IMatRenderContext* pRenderContext, IMaterial* m_pMatGlowColor, IMaterial* m_pMatBlurX, IMaterial* m_pMatBlurY, IMaterial* m_pMatHaloAddToScreen) +{ + if (!Vars::Backtrack::Enabled.Value || !Vars::Glow::Backtrack::Enabled.Value || !Vars::Glow::Backtrack::Stencil.Value && !Vars::Glow::Backtrack::Blur.Value) + return; + + const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]; + if (!ModelRender_DrawModelExecute) + return; + + auto pEntity = I::ClientEntityList->GetClientEntity(pInfo.entity_index)->As(); + if (!pEntity || !pEntity->IsPlayer() || !pEntity->IsAlive()) + return; + + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + if (!pLocal || !pWeapon || G::WeaponType == EWeaponType::PROJECTILE) + return; + if (pEntity == pLocal || + pWeapon->m_iItemDefinitionIndex() != Soldier_t_TheDisciplinaryAction && pWeapon->m_iWeaponID() != TF_WEAPON_MEDIGUN && pEntity->m_iTeamNum() == pLocal->m_iTeamNum() || + pWeapon->m_iWeaponID() == TF_WEAPON_MEDIGUN && pEntity->m_iTeamNum() != pLocal->m_iTeamNum()) + return; + + + + auto drawModel = [ModelRender_DrawModelExecute, pEntity](Vec3& vOrigin, const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) + { + if (!SDK::IsOnScreen(pEntity, vOrigin)) + return; + + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, pBoneToWorld); + }; + auto drawModels = [drawModel, pEntity, pState, pInfo](bool bModel) + { + if (bModel) + I::RenderView->SetBlend(0.f); + + const auto& pRecords = F::Backtrack.GetRecords(pEntity); + auto vRecords = F::Backtrack.GetValidRecords(pRecords); + if (!vRecords.size()) + return; + + switch (Vars::Glow::Backtrack::Draw.Value) + { + case 0: // last + { + auto vLastRec = vRecords.end() - 1; + if (vLastRec != vRecords.end() && pEntity->GetAbsOrigin().DistTo(vLastRec->vOrigin) > 0.1f) + drawModel(vLastRec->vOrigin, pState, pInfo, reinterpret_cast(&vLastRec->BoneMatrix)); + break; + } + case 1: // last + first + { + auto vFirstRec = vRecords.begin(); + if (vFirstRec != vRecords.end() && pEntity->GetAbsOrigin().DistTo(vFirstRec->vOrigin) > 0.1f) + drawModel(vFirstRec->vOrigin, pState, pInfo, reinterpret_cast(&vFirstRec->BoneMatrix)); + auto vLastRec = vRecords.end() - 1; + if (vLastRec != vRecords.end() && pEntity->GetAbsOrigin().DistTo(vLastRec->vOrigin) > 0.1f) + drawModel(vLastRec->vOrigin, pState, pInfo, reinterpret_cast(&vLastRec->BoneMatrix)); + break; + } + case 2: // all + { + for (auto& record : vRecords) + { + if (pEntity->GetAbsOrigin().DistTo(record.vOrigin) < 0.1f) + continue; + + drawModel(record.vOrigin, pState, pInfo, reinterpret_cast(&record.BoneMatrix)); + } + } + } + + if (bModel) + I::RenderView->SetBlend(1.f); + }; + + + + auto glow = GetStruct(Vars::Glow::Backtrack::Stencil.Value, Vars::Glow::Backtrack::Blur.Value, Vars::Glow::Backtrack::StencilScale.Value, Vars::Glow::Backtrack::BlurScale.Value); + + SetupBegin(glow, pRenderContext, m_pMatBlurY); + drawModels(true); + + StencilEnd(pRenderContext); + + SetupMid(pRenderContext, m_pMatGlowColor, w, h); + auto color = H::Color.GetEntityDrawColor(pLocal, pEntity, Vars::Colors::Relative.Value); + I::RenderView->SetColorModulation(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + I::RenderView->SetBlend(float(color.a) / 255.f); + drawModels(false); + + SetupEnd(glow, pRenderContext, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen, w, h); +} +void CGlow::RenderFakeAngle(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld, + int w, int h, IMatRenderContext* pRenderContext, IMaterial* m_pMatGlowColor, IMaterial* m_pMatBlurX, IMaterial* m_pMatBlurY, IMaterial* m_pMatHaloAddToScreen) +{ + if (!Vars::Glow::FakeAngle::Enabled.Value || !Vars::Glow::FakeAngle::Stencil.Value && !Vars::Glow::FakeAngle::Blur.Value || pInfo.entity_index != I::EngineClient->GetLocalPlayer() || !F::FakeAngle.DrawChams || !F::FakeAngle.BonesSetup) + return; + + const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]; + if (!ModelRender_DrawModelExecute) + return; + + + + auto drawModel = [ModelRender_DrawModelExecute, pState, pInfo](bool bModel) + { + if (bModel) + I::RenderView->SetBlend(0.f); + + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, F::FakeAngle.BoneMatrix); + + if (bModel) + I::RenderView->SetBlend(1.f); + }; + + + + auto glow = GetStruct(Vars::Glow::FakeAngle::Stencil.Value, Vars::Glow::FakeAngle::Blur.Value, Vars::Glow::FakeAngle::StencilScale.Value, Vars::Glow::FakeAngle::BlurScale.Value); + + SetupBegin(glow, pRenderContext, m_pMatBlurY); + drawModel(true); + + StencilEnd(pRenderContext); + + SetupMid(pRenderContext, m_pMatGlowColor, w, h); + auto& color = Vars::Colors::Local.Value; + I::RenderView->SetColorModulation(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + I::RenderView->SetBlend(float(color.a) / 255.f); + drawModel(false); + + SetupEnd(glow, pRenderContext, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen, w, h); +} +void CGlow::RenderHandler(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + if (!bExtra) + { + if (const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]) + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, pBoneToWorld); + } + else + { + const int w = H::Draw.m_nScreenW, h = H::Draw.m_nScreenH; + if (w < 1 || h < 1 || w > 4096 || h > 2160) + return; + + const auto pRenderContext = I::MaterialSystem->GetRenderContext(); + auto m_pMatGlowColor = F::Materials.mGlowMaterials["GlowColor"].pMaterial; + auto m_pMatBlurX = F::Materials.mGlowMaterials["BlurX"].pMaterial; + auto m_pMatBlurY = F::Materials.mGlowMaterials["BlurY"].pMaterial; + auto m_pMatHaloAddToScreen = F::Materials.mGlowMaterials["HaloAddToScreen"].pMaterial; + if (!pRenderContext || !m_pMatGlowColor || !m_pMatBlurX || !m_pMatBlurY || !m_pMatHaloAddToScreen) + return F::Materials.ReloadMaterials(); + + RenderBacktrack(pState, pInfo, pBoneToWorld, w, h, pRenderContext, m_pMatGlowColor, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen); + RenderFakeAngle(pState, pInfo, pBoneToWorld, w, h, pRenderContext, m_pMatGlowColor, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen); + } +} + +void CGlow::RenderViewmodel(void* ecx, int flags) +{ + if (!Vars::Glow::Viewmodel::Weapon.Value || !Vars::Glow::Viewmodel::Stencil.Value && !Vars::Glow::Viewmodel::Blur.Value) + return; + + const int w = H::Draw.m_nScreenW, h = H::Draw.m_nScreenH; + if (w < 1 || h < 1 || w > 4096 || h > 2160) + return; + + const auto pRenderContext = I::MaterialSystem->GetRenderContext(); + auto m_pMatGlowColor = F::Materials.mGlowMaterials["GlowColor"].pMaterial; + auto m_pMatBlurX = F::Materials.mGlowMaterials["BlurX"].pMaterial; + auto m_pMatBlurY = F::Materials.mGlowMaterials["BlurY"].pMaterial; + auto m_pMatHaloAddToScreen = F::Materials.mGlowMaterials["HaloAddToScreen"].pMaterial; + if (!pRenderContext || !m_pMatGlowColor || !m_pMatBlurX || !m_pMatBlurY || !m_pMatHaloAddToScreen) + return F::Materials.ReloadMaterials(); + + const auto CBaseAnimating_DrawModel = U::Hooks.m_mHooks["CBaseAnimating_DrawModel"]; + if (!CBaseAnimating_DrawModel) + return; + + + + auto drawModel = [CBaseAnimating_DrawModel, ecx, flags](bool bModel) + { + if (bModel) + I::RenderView->SetBlend(0.f); + + CBaseAnimating_DrawModel->Original()(ecx, flags); + + if (bModel) + I::RenderView->SetBlend(1.f); + }; + + + + auto glow = GetStruct(Vars::Glow::Viewmodel::Stencil.Value, Vars::Glow::Viewmodel::Blur.Value, Vars::Glow::Viewmodel::StencilScale.Value, Vars::Glow::Viewmodel::BlurScale.Value); + + SetupBegin(glow, pRenderContext, m_pMatBlurY); + drawModel(true); + + StencilEnd(pRenderContext); + + SetupMid(pRenderContext, m_pMatGlowColor, w, h); + auto& color = Vars::Colors::Local.Value; + I::RenderView->SetColorModulation(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + I::RenderView->SetBlend(float(color.a) / 255.f); + drawModel(false); + + SetupEnd(glow, pRenderContext, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen, w, h); +} +void CGlow::RenderViewmodel(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + if (!Vars::Glow::Viewmodel::Hands.Value || !Vars::Glow::Viewmodel::Stencil.Value && !Vars::Glow::Viewmodel::Blur.Value) + return; + + const int w = H::Draw.m_nScreenW, h = H::Draw.m_nScreenH; + if (w < 1 || h < 1 || w > 4096 || h > 2160) + return; + + const auto pRenderContext = I::MaterialSystem->GetRenderContext(); + auto m_pMatGlowColor = F::Materials.mGlowMaterials["GlowColor"].pMaterial; + auto m_pMatBlurX = F::Materials.mGlowMaterials["BlurX"].pMaterial; + auto m_pMatBlurY = F::Materials.mGlowMaterials["BlurY"].pMaterial; + auto m_pMatHaloAddToScreen = F::Materials.mGlowMaterials["HaloAddToScreen"].pMaterial; + if (!pRenderContext || !m_pMatGlowColor || !m_pMatBlurX || !m_pMatBlurY || !m_pMatHaloAddToScreen) + return F::Materials.ReloadMaterials(); + + const auto ModelRender_DrawModelExecute = U::Hooks.m_mHooks["ModelRender_DrawModelExecute"]; + if (!ModelRender_DrawModelExecute) + return; + + + + auto drawModel = [ModelRender_DrawModelExecute, pState, pInfo, pBoneToWorld](bool bModel) + { + if (bModel) + I::RenderView->SetBlend(0.f); + + ModelRender_DrawModelExecute->Original()(I::ModelRender, pState, pInfo, pBoneToWorld); + + if (bModel) + I::RenderView->SetBlend(1.f); + }; + + + + auto glow = GetStruct(Vars::Glow::Viewmodel::Stencil.Value, Vars::Glow::Viewmodel::Blur.Value, Vars::Glow::Viewmodel::StencilScale.Value, Vars::Glow::Viewmodel::BlurScale.Value); + + SetupBegin(glow, pRenderContext, m_pMatBlurY); + drawModel(true); + + StencilEnd(pRenderContext); + + SetupMid(pRenderContext, m_pMatGlowColor, w, h); + auto& color = Vars::Colors::Local.Value; + I::RenderView->SetColorModulation(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + I::RenderView->SetBlend(float(color.a) / 255.f); + drawModel(false); + + SetupEnd(glow, pRenderContext, m_pMatBlurX, m_pMatBlurY, m_pMatHaloAddToScreen, w, h); +} + + + +void CGlow::Init() +{ + m_pRtFullFrame = I::MaterialSystem->FindTexture("_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET); + m_pRtFullFrame->IncrementReferenceCount(); + + m_pRenderBuffer1 = I::MaterialSystem->CreateNamedRenderTargetTextureEx( + "glow_buffer_1", + m_pRtFullFrame->GetActualWidth(), + m_pRtFullFrame->GetActualHeight(), + RT_SIZE_LITERAL, + IMAGE_FORMAT_RGB888, + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_EIGHTBITALPHA, + CREATERENDERTARGETFLAGS_HDR + ); + m_pRenderBuffer1->IncrementReferenceCount(); + + m_pRenderBuffer2 = I::MaterialSystem->CreateNamedRenderTargetTextureEx( + "glow_buffer_2", + m_pRtFullFrame->GetActualWidth(), + m_pRtFullFrame->GetActualHeight(), + RT_SIZE_LITERAL, + IMAGE_FORMAT_RGB888, + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_EIGHTBITALPHA, + CREATERENDERTARGETFLAGS_HDR + ); + m_pRenderBuffer2->IncrementReferenceCount(); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Glow/Glow.h b/Amalgam/src/Features/Visuals/Glow/Glow.h new file mode 100644 index 0000000..bacaa4f --- /dev/null +++ b/Amalgam/src/Features/Visuals/Glow/Glow.h @@ -0,0 +1,72 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#include + +class CGlow +{ + Glow_t GetStruct( + bool Stencil = false, + bool Blur = false, + int StencilScale = 1, + int BlurScale = 1 + ); + bool GetPlayerGlow(CTFPlayer* pEntity, CTFPlayer* pLocal, Glow_t* pGlow, Color_t* pColor, bool bFriendly, bool bEnemy); + bool GetGlow(CTFPlayer* pLocal, CBaseEntity* pEntity, Glow_t* pGlow, Color_t* pColor); + + void SetupBegin(Glow_t glow, IMatRenderContext* pRenderContext, IMaterial* m_pMatBlurY); + void SetupMid(IMatRenderContext* pRenderContext, IMaterial* m_pMatGlowColor, int w, int h); + void SetupEnd(Glow_t glow, IMatRenderContext* pRenderContext, IMaterial* m_pMatBlurX, IMaterial* m_pMatBlurY, IMaterial* m_pMatHaloAddToScreen, int w, int h); + + void StencilBegin(IMatRenderContext* pRenderContext); + void StencilPreDraw(IMatRenderContext* pRenderContext); + void StencilEnd(IMatRenderContext* pRenderContext); + + void DrawModel(CBaseEntity* pEntity, bool bModel = false); + + void RenderBacktrack(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld, + int w, int h, IMatRenderContext* pRenderContext, IMaterial* m_pMatGlowColor, IMaterial* m_pMatBlurX, IMaterial* m_pMatBlurY, IMaterial* m_pMatHaloAddToScreen); + void RenderFakeAngle(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld, + int w, int h, IMatRenderContext* pRenderContext, IMaterial* m_pMatGlowColor, IMaterial* m_pMatBlurX, IMaterial* m_pMatBlurY, IMaterial* m_pMatHaloAddToScreen); + + ITexture* m_pRtFullFrame; + ITexture* m_pRenderBuffer1; + ITexture* m_pRenderBuffer2; + + + + struct GlowHasher_t + { + std::size_t operator()(const Glow_t& k) const + { + std::size_t seed = 0; + + boost::hash_combine(seed, boost::hash_value(k.Stencil)); + boost::hash_combine(seed, boost::hash_value(k.Blur)); + boost::hash_combine(seed, boost::hash_value(k.StencilScale)); + boost::hash_combine(seed, boost::hash_value(k.BlurScale)); + + return seed; + } + }; + struct GlowInfo_t + { + CBaseEntity* m_pEntity; + Color_t m_Color; + }; + std::unordered_map, GlowHasher_t> mEntities = {}; + +public: + void RenderMain(CTFPlayer* pLocal); + void RenderHandler(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld); + + void RenderViewmodel(void* ecx, int flags); + void RenderViewmodel(const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld); + + void Init(); + + bool bRendering = false; + bool bExtra = false; +}; + +ADD_FEATURE(CGlow, Glow) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/LocalConditions/LocalConditions.cpp b/Amalgam/src/Features/Visuals/LocalConditions/LocalConditions.cpp new file mode 100644 index 0000000..dc72d4a --- /dev/null +++ b/Amalgam/src/Features/Visuals/LocalConditions/LocalConditions.cpp @@ -0,0 +1,355 @@ +#include "LocalConditions.h" + +std::vector LCESP::GetPlayerConditions(CTFPlayer* pEntity) const +{ + std::vector szCond{}; + + if (Vars::Menu::Indicators.Value & (1 << 4)) + { + if (pEntity->InCond(TF_COND_CRITBOOSTED)) + szCond.emplace_back(L"KRITS"); + else if (pEntity->InCond(TF_COND_CRITBOOSTED_PUMPKIN) || + pEntity->InCond(TF_COND_CRITBOOSTED_USER_BUFF) || + pEntity->InCond(TF_COND_CRITBOOSTED_DEMO_CHARGE) || + pEntity->InCond(TF_COND_CRITBOOSTED_FIRST_BLOOD) || + pEntity->InCond(TF_COND_CRITBOOSTED_BONUS_TIME) || + pEntity->InCond(TF_COND_CRITBOOSTED_CTF_CAPTURE) || + pEntity->InCond(TF_COND_CRITBOOSTED_ON_KILL) || + pEntity->InCond(TF_COND_CRITBOOSTED_RAGE_BUFF) || + pEntity->InCond(TF_COND_CRITBOOSTED_CARD_EFFECT) || + pEntity->InCond(TF_COND_CRITBOOSTED_RUNE_TEMP)) + szCond.emplace_back(L"CRITS"); + + if (pEntity->InCond(TF_COND_ENERGY_BUFF) || + pEntity->InCond(TF_COND_NOHEALINGDAMAGEBUFF)) + szCond.emplace_back(L"MINI CRITS"); + + if (pEntity->InCond(TF_COND_MINICRITBOOSTED_ON_KILL)) + szCond.emplace_back(L"MINI CRITS ON KILL"); + + if (pEntity->InCond(TF_COND_OFFENSEBUFF)) + szCond.emplace_back(L"OFFENSE BUFF"); + + if (pEntity->InCond(TF_COND_TMPDAMAGEBONUS)) + szCond.emplace_back(L"DAMAGE BONUS"); + + if (pEntity->InCond(TF_COND_INVULNERABLE) || + pEntity->InCond(TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED) || + pEntity->InCond(TF_COND_INVULNERABLE_USER_BUFF) || + pEntity->InCond(TF_COND_INVULNERABLE_CARD_EFFECT)) + szCond.emplace_back(L"INVULNERABLE"); + + if (pEntity->InCond(TF_COND_INVULNERABLE_WEARINGOFF)) + szCond.emplace_back(L"INVULNERABLE-"); + + if (pEntity->InCond(TF_COND_DEFENSEBUFF)) + szCond.emplace_back(L"DEFENSE BUFF"); + + if (pEntity->InCond(TF_COND_DEFENSEBUFF_HIGH)) + szCond.emplace_back(L"DEFENSE BUFF+"); + + if (pEntity->InCond(TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK)) + szCond.emplace_back(L"DEFENSE BUFF-"); + + if (pEntity->InCond(TF_COND_RADIUSHEAL) || + pEntity->InCond(TF_COND_HEALTH_BUFF) || + pEntity->InCond(TF_COND_RADIUSHEAL_ON_DAMAGE) || + pEntity->InCond(TF_COND_HALLOWEEN_HELL_HEAL)) + szCond.emplace_back(L"HEAL"); + + if (pEntity->InCond(TF_COND_MEGAHEAL) || + pEntity->InCond(TF_COND_HALLOWEEN_QUICK_HEAL)) + szCond.emplace_back(L"HEAL+"); + + if (pEntity->InCond(TF_COND_REGENONDAMAGEBUFF)) + szCond.emplace_back(L"HEALTH ON DAMAGE"); + + if (pEntity->InCond(TF_COND_HEALTH_OVERHEALED)) + szCond.emplace_back(L"OVERHEAL"); + + + + if (pEntity->InCond(TF_COND_MEDIGUN_UBER_BULLET_RESIST) || + pEntity->InCond(TF_COND_MEDIGUN_SMALL_BULLET_RESIST) || + pEntity->InCond(TF_COND_BULLET_IMMUNE)) + szCond.emplace_back(L"BULLET"); + + if (pEntity->InCond(TF_COND_MEDIGUN_UBER_BLAST_RESIST) || + pEntity->InCond(TF_COND_MEDIGUN_SMALL_BLAST_RESIST) || + pEntity->InCond(TF_COND_BLAST_IMMUNE)) + szCond.emplace_back(L"BLAST"); + + if (pEntity->InCond(TF_COND_MEDIGUN_UBER_FIRE_RESIST) || + pEntity->InCond(TF_COND_MEDIGUN_SMALL_FIRE_RESIST) || + pEntity->InCond(TF_COND_FIRE_IMMUNE)) + szCond.emplace_back(L"FIRE"); + + + + if (pEntity->m_bFeignDeathReady()) + szCond.emplace_back(L"DR"); + + if (pEntity->InCond(TF_COND_FEIGN_DEATH)) + szCond.emplace_back(L"FEIGN"); + + if (pEntity->InCond(TF_COND_STEALTHED)) + szCond.emplace_back(L"CLOAK"); + + if (pEntity->InCond(TF_COND_STEALTHED_USER_BUFF)) + szCond.emplace_back(L"STEALTH"); + + if (pEntity->InCond(TF_COND_STEALTHED_USER_BUFF_FADING)) + szCond.emplace_back(L"STEALTH+"); + + if (pEntity->InCond(TF_COND_DISGUISED)) + szCond.emplace_back(L"DISGUISE"); + + if (pEntity->InCond(TF_COND_DISGUISING)) + szCond.emplace_back(L"DISGUISING"); + + if (pEntity->InCond(TF_COND_DISGUISE_WEARINGOFF)) + szCond.emplace_back(L"UNDISGUISING"); + + if (pEntity->InCond(TF_COND_STEALTHED_BLINK)) + szCond.emplace_back(L"BLINK"); + + + + if (pEntity->InCond(TF_COND_SPEED_BOOST) || + pEntity->InCond(TF_COND_HALLOWEEN_SPEED_BOOST)) + szCond.emplace_back(L"SPEED BOOST"); + + if (pEntity->InCond(TF_COND_SODAPOPPER_HYPE)) + szCond.emplace_back(L"HYPE"); + + if (pEntity->InCond(TF_COND_SNIPERCHARGE_RAGE_BUFF)) + szCond.emplace_back(L"FOCUS"); + + if (pEntity->InCond(TF_COND_AIMING)) + szCond.emplace_back(L"SLOWED"); + + if (pEntity->InCond(TF_COND_ZOOMED)) + szCond.emplace_back(L"ZOOM"); + + if (pEntity->InCond(TF_COND_SHIELD_CHARGE)) + szCond.emplace_back(L"CHARGING"); + + if (pEntity->InCond(TF_COND_DEMO_BUFF)) + szCond.emplace_back(L"EYELANDER"); + + if (pEntity->InCond(TF_COND_PHASE)) + szCond.emplace_back(L"BONK"); + + if (pEntity->InCond(TF_COND_AFTERBURN_IMMUNE)) + szCond.emplace_back(L"NO AFTERBURN"); + + if (pEntity->InCond(TF_COND_BLASTJUMPING)) + szCond.emplace_back(L"BLASTJUMP"); + + if (pEntity->InCond(TF_COND_ROCKETPACK)) + szCond.emplace_back(L"ROCKETPACK"); + + if (pEntity->InCond(TF_COND_PARACHUTE_ACTIVE) || + pEntity->InCond(TF_COND_PARACHUTE_DEPLOYED)) + szCond.emplace_back(L"PARACHUTE"); + + if (pEntity->InCond(TF_COND_OBSCURED_SMOKE)) + szCond.emplace_back(L"DODGE"); + + + + if (pEntity->InCond(TF_COND_STUNNED) || + pEntity->InCond(TF_COND_MVM_BOT_STUN_RADIOWAVE)) + szCond.emplace_back(L"STUN"); + + if (pEntity->InCond(TF_COND_MARKEDFORDEATH) || + pEntity->InCond(TF_COND_MARKEDFORDEATH_SILENT) || + pEntity->InCond(TF_COND_PASSTIME_PENALTY_DEBUFF)) + szCond.emplace_back(L"MARKED FOR DEATH"); + + if (pEntity->InCond(TF_COND_URINE)) + szCond.emplace_back(L"JARATE"); + + if (pEntity->InCond(TF_COND_MAD_MILK)) + szCond.emplace_back(L"MILK"); + + if (pEntity->InCond(TF_COND_GAS)) + szCond.emplace_back(L"GAS"); + + if (pEntity->InCond(TF_COND_BURNING) || + pEntity->InCond(TF_COND_BURNING_PYRO)) + szCond.emplace_back(L"BURN"); + + if (pEntity->InCond(TF_COND_BLEEDING) || + pEntity->InCond(TF_COND_GRAPPLINGHOOK_BLEEDING)) + szCond.emplace_back(L"BLEED"); + + if (pEntity->InCond(TF_COND_KNOCKED_INTO_AIR)) + szCond.emplace_back(L"AIRBLAST"); + + if (pEntity->InCond(TF_COND_AIR_CURRENT)) + szCond.emplace_back(L"AIR"); + + if (pEntity->InCond(TF_COND_LOST_FOOTING)) + szCond.emplace_back(L"SLIDE"); + + if (pEntity->InCond(TF_COND_HEALING_DEBUFF)) + szCond.emplace_back(L"HEAL DEBUFF"); + + if (pEntity->InCond(TF_COND_CANNOT_SWITCH_FROM_MELEE) || + pEntity->InCond(TF_COND_MELEE_ONLY)) + szCond.emplace_back(L"ONLY MELEE"); + + + + if (pEntity->InCond(TF_COND_HALLOWEEN_GIANT)) + szCond.emplace_back(L"GIANT"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_TINY)) + szCond.emplace_back(L"TINY"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_BOMB_HEAD)) + szCond.emplace_back(L"BOMB"); + + if (pEntity->InCond(TF_COND_BALLOON_HEAD)) + szCond.emplace_back(L"BALLOON"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_GHOST_MODE)) + szCond.emplace_back(L"GHOST"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_KART)) + szCond.emplace_back(L"KART"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_KART_DASH)) + szCond.emplace_back(L"DASH"); + + if (pEntity->InCond(TF_COND_SWIMMING_CURSE) || + pEntity->InCond(TF_COND_SWIMMING_NO_EFFECTS)) + szCond.emplace_back(L"SWIM"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_KART_CAGE)) + szCond.emplace_back(L"CAGE"); + + + + // if (pEntity->InCond(TF_COND_HASRUNE)) + // szCond.emplace_back(L"RUNE"); + + if (pEntity->InCond(TF_COND_POWERUPMODE_DOMINANT)) + szCond.emplace_back(L"DOMINANT"); + + if (pEntity->InCond(TF_COND_RUNE_STRENGTH)) + szCond.emplace_back(L"STRENGTH"); + + if (pEntity->InCond(TF_COND_RUNE_HASTE)) + szCond.emplace_back(L"HASTE"); + + if (pEntity->InCond(TF_COND_RUNE_REGEN)) + szCond.emplace_back(L"REGEN"); + + if (pEntity->InCond(TF_COND_RUNE_RESIST)) + szCond.emplace_back(L"RESIST"); + + if (pEntity->InCond(TF_COND_RUNE_VAMPIRE)) + szCond.emplace_back(L"VAMPIRE"); + + if (pEntity->InCond(TF_COND_RUNE_REFLECT)) + szCond.emplace_back(L"REFLECT"); + + if (pEntity->InCond(TF_COND_RUNE_PRECISION)) + szCond.emplace_back(L"PRECISION"); + + if (pEntity->InCond(TF_COND_RUNE_AGILITY)) + szCond.emplace_back(L"AGILITY"); + + if (pEntity->InCond(TF_COND_RUNE_KNOCKOUT)) + szCond.emplace_back(L"KNOCKOUT"); + + if (pEntity->InCond(TF_COND_RUNE_IMBALANCE)) + szCond.emplace_back(L"IMBALANCE"); + + if (pEntity->InCond(TF_COND_RUNE_KING)) + szCond.emplace_back(L"KING"); + + if (pEntity->InCond(TF_COND_RUNE_PLAGUE)) + szCond.emplace_back(L"PLAGUE"); + + if (pEntity->InCond(TF_COND_RUNE_SUPERNOVA)) + szCond.emplace_back(L"SUPERNOVA"); + + if (pEntity->InCond(TF_COND_PLAGUE)) + szCond.emplace_back(L"PLAGUED"); + + if (pEntity->InCond(TF_COND_KING_BUFFED)) + szCond.emplace_back(L"KING BUFF"); + + + + if (pEntity->InCond(TF_COND_HALLOWEEN_IN_HELL)) + szCond.emplace_back(L"HELL"); + + if (pEntity->InCond(TF_COND_PURGATORY)) + szCond.emplace_back(L"PURGATORY"); + + if (pEntity->InCond(TF_COND_PASSTIME_INTERCEPTION)) + szCond.emplace_back(L"INTERCEPTION"); + + if (pEntity->InCond(TF_COND_TEAM_GLOWS)) + szCond.emplace_back(L"TEAM GLOWS"); + + + + if (pEntity->InCond(TF_COND_PREVENT_DEATH)) + szCond.emplace_back(L"PREVENT DEATH"); + + if (pEntity->InCond(TF_COND_GRAPPLINGHOOK)) + szCond.emplace_back(L"GRAPPLE"); + + if (pEntity->InCond(TF_COND_GRAPPLINGHOOK_SAFEFALL)) + szCond.emplace_back(L"SAFEFALL"); + + if (pEntity->InCond(TF_COND_GRAPPLINGHOOK_LATCHED)) + szCond.emplace_back(L"LATCHED"); + + if (pEntity->InCond(TF_COND_GRAPPLED_TO_PLAYER)) + szCond.emplace_back(L"TO PLAYER"); + + if (pEntity->InCond(TF_COND_GRAPPLED_BY_PLAYER)) + szCond.emplace_back(L"BY PLAYER"); + + if (pEntity->InCond(TF_COND_TELEPORTED)) + szCond.emplace_back(L"TELEPORT"); + + if (pEntity->InCond(TF_COND_SELECTED_TO_TELEPORT)) + szCond.emplace_back(L"TELEPORTING"); + + if (pEntity->InCond(TF_COND_MEDIGUN_DEBUFF)) + szCond.emplace_back(L"MEDIGUN DEBUFF"); + + if (pEntity->InCond(TF_COND_SAPPED)) + szCond.emplace_back(L"SAPPED"); + + if (pEntity->InCond(TF_COND_DISGUISED_AS_DISPENSER)) + szCond.emplace_back(L"DISPENSER"); + + if (pEntity->InCond(TF_COND_TAUNTING)) + szCond.emplace_back(L"TAUNT"); + + if (pEntity->InCond(TF_COND_HALLOWEEN_THRILLER)) + szCond.emplace_back(L"THRILLER"); + + if (pEntity->InCond(TF_COND_FREEZE_INPUT)) + szCond.emplace_back(L"FREEZE INPUT"); + + if (pEntity->InCond(TF_COND_REPROGRAMMED)) + szCond.emplace_back(L"REPROGRAMMED"); + + // if (pEntity->InCond(TF_COND_COMPETITIVE_WINNER)) + // szCond.emplace_back(L"WIN"); + + // if (pEntity->InCond(TF_COND_COMPETITIVE_LOSER)) + // szCond.emplace_back(L"LOSS"); + } + + return szCond; +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/LocalConditions/LocalConditions.h b/Amalgam/src/Features/Visuals/LocalConditions/LocalConditions.h new file mode 100644 index 0000000..af3b239 --- /dev/null +++ b/Amalgam/src/Features/Visuals/LocalConditions/LocalConditions.h @@ -0,0 +1,10 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class LCESP +{ +public: + std::vector GetPlayerConditions(CTFPlayer* pEntity) const; +}; + +ADD_FEATURE(LCESP, LocalConditions) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Materials/Materials.cpp b/Amalgam/src/Features/Visuals/Materials/Materials.cpp new file mode 100644 index 0000000..5cb949d --- /dev/null +++ b/Amalgam/src/Features/Visuals/Materials/Materials.cpp @@ -0,0 +1,353 @@ +#include "Materials.h" + +#include "../../Configs/Configs.h" +#include +#include + +IMaterial* CMaterials::CreateNRef(char const* szName, KeyValues* pKV) +{ + IMaterial* returnMaterial = I::MaterialSystem->CreateMaterial(szName, pKV); + returnMaterial->IncrementReferenceCount(); + mMatList[returnMaterial] = true; + return returnMaterial; +} + +void CMaterials::LoadMaterials() +{ + // cham materials + + // default materials + { // hacky + Material_t mat = {}; // None + + mat.sVMT = "\"UnlitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $color2 \"[0 0 0]\""; + mat.sVMT += "\n $additive \"1\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["None"] = mat; + } + { + Material_t mat = {}; // Flat + + mat.sVMT = "\"UnlitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $basetexture \"vgui/white_additive\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["Flat"] = mat; + } + { + Material_t mat = {}; // Shaded + + mat.sVMT = "\"VertexLitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $basetexture \"vgui/white_additive\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["Shaded"] = mat; + } + { + Material_t mat = {}; // Wireframe + + mat.sVMT = "\"UnlitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $basetexture \"vgui/white_additive\""; + mat.sVMT += "\n $wireframe \"1\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["Wireframe"] = mat; + } + { + Material_t mat = {}; // Fresnel + + mat.sVMT = "\"VertexLitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $basetexture \"vgui/white_additive\""; + mat.sVMT += "\n $bumpmap \"models/player/shared/shared_normal\""; + mat.sVMT += "\n $color2 \"[0 0 0]\""; + mat.sVMT += "\n $additive \"1\""; + mat.sVMT += "\n $phong \"1\""; + mat.sVMT += "\n $phongfresnelranges \"[0 0.5 1]\""; + mat.sVMT += "\n $envmap \"skybox/sky_dustbowl_01\""; + mat.sVMT += "\n $envmapfresnel \"1\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["Fresnel"] = mat; + } + { + Material_t mat = {}; // Shine + + mat.sVMT = "\"VertexLitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $additive \"1\""; + mat.sVMT += "\n $envmap \"cubemaps/cubemap_sheen002.hdr\""; + mat.sVMT += "\n $envmaptint \"[1 1 1]\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["Shine"] = mat; + } + { + Material_t mat = {}; // Tint + + mat.sVMT = "\"VertexLitGeneric\""; + mat.sVMT += "\n{"; + mat.sVMT += "\n $basetexture \"models/player/shared/ice_player\""; + mat.sVMT += "\n $bumpmap \"models/player/shared/shared_normal\""; + mat.sVMT += "\n $additive \"1\""; + mat.sVMT += "\n $phong \"1\""; + mat.sVMT += "\n $phongfresnelranges \"[0 0.001 0.001]\""; + mat.sVMT += "\n $envmap \"skybox/sky_dustbowl_01\""; + mat.sVMT += "\n $envmapfresnel \"1\""; + mat.sVMT += "\n $selfillum \"1\""; + mat.sVMT += "\n $selfillumtint \"[0 0 0]\""; + mat.sVMT += "\n}"; + + mat.bLocked = true; + mChamMaterials["Tint"] = mat; + } + // user materials + for (const auto& entry : std::filesystem::directory_iterator(MaterialFolder)) + { + // Ignore all non-Material files + if (!entry.is_regular_file() || entry.path().extension() != std::string(".vmt")) + continue; + + std::ifstream inStream(entry.path()); + if (!inStream.good()) + continue; + + std::string sName = entry.path().filename().string(); + sName.erase(sName.end() - 4, sName.end()); + const std::string sVMT((std::istreambuf_iterator(inStream)), std::istreambuf_iterator()); + + if (FNV1A::Hash(sName.c_str()) == FNV1A::HashConst("Original")) + continue; + + Material_t mat = {}; + mat.sVMT = sVMT; + + mChamMaterials[sName] = mat; + } + // create materials + for (auto& [sName, mat] : mChamMaterials) + { + const auto kv = new KeyValues(sName.c_str()); + kv->LoadFromBuffer(sName.c_str(), mat.sVMT.c_str()); + mat.pMaterial = CreateNRef(std::format("m_pMat%s", sName).c_str(), kv); + } + + // glow materials + + { + Material_t mat = {}; // GlowColor + + mat.pMaterial = I::MaterialSystem->FindMaterial("dev/glow_color", TEXTURE_GROUP_OTHER); + mat.pMaterial->IncrementReferenceCount(); + + mGlowMaterials["GlowColor"] = mat; + } + { + Material_t mat = {}; // BlurX + + KeyValues* m_pMatBlurXKV = new KeyValues("BlurFilterX"); + m_pMatBlurXKV->SetString("$basetexture", "glow_buffer_1"); + mat.pMaterial = CreateNRef("m_pMatBlurX", m_pMatBlurXKV); + + mGlowMaterials["BlurX"] = mat; + } + { + Material_t mat = {}; // BlurY + + KeyValues* m_pMatBlurYKV = new KeyValues("BlurFilterY"); + m_pMatBlurYKV->SetString("$basetexture", "glow_buffer_2"); + mat.pMaterial = CreateNRef("m_pMatBlurY", m_pMatBlurYKV); + + mGlowMaterials["BlurY"] = mat; + } + { + Material_t mat = {}; // HaloAddToScreen + + KeyValues* m_pMatHaloAddToScreenKV = new KeyValues("UnlitGeneric"); + m_pMatHaloAddToScreenKV->SetString("$basetexture", "glow_buffer_1"); + m_pMatHaloAddToScreenKV->SetString("$additive", "1"); + mat.pMaterial = CreateNRef("m_pMatHaloAddToScreen", m_pMatHaloAddToScreenKV); + + mGlowMaterials["HaloAddToScreen"] = mat; + } +} + +void CMaterials::UnloadMaterials() +{ + for (auto& [_, mat] : mChamMaterials) + { + if (!mat.pMaterial) + continue; + + mat.pMaterial->DecrementReferenceCount(); + mat.pMaterial->DeleteIfUnreferenced(); + mat.pMaterial = nullptr; + } + for (auto& [_, mat] : mGlowMaterials) + { + if (!mat.pMaterial) + continue; + + mat.pMaterial->DecrementReferenceCount(); + mat.pMaterial->DeleteIfUnreferenced(); + mat.pMaterial = nullptr; + } + mChamMaterials.clear(); + mGlowMaterials.clear(); + mMatList.clear(); +} + +void CMaterials::ReloadMaterials() +{ + UnloadMaterials(); + + LoadMaterials(); +} + +void CMaterials::SetColor(IMaterial* material, Color_t color, bool bSetColor) +{ + if (bSetColor) + { + if (material) + { + if (auto $phongtint = material->FindVar("$phongtint", nullptr, false)) + $phongtint->SetVecValue(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + if (auto $envmaptint = material->FindVar("$envmaptint", nullptr, false)) + $envmaptint->SetVecValue(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + } + I::RenderView->SetColorModulation(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f); + I::RenderView->SetBlend(float(color.a) / 255.f); + } + else + { + if (material) + { + if (auto $phongtint = material->FindVar("$phongtint", nullptr, false)) + $phongtint->SetVecValue(1.f, 1.f, 1.f); + if (auto $envmaptint = material->FindVar("$envmaptint", nullptr, false)) + $envmaptint->SetVecValue(1.f, 1.f, 1.f); + } + I::RenderView->SetColorModulation(1.f, 1.f, 1.f); + I::RenderView->SetBlend(1.f); + } +} + + + +IMaterial* CMaterials::GetMaterial(std::string sName) +{ + if (FNV1A::Hash(sName.c_str()) == FNV1A::HashConst("Original")) + return nullptr; + + return mChamMaterials.contains(sName) ? mChamMaterials[sName].pMaterial : nullptr; +} + +std::string CMaterials::GetVMT(std::string sName) +{ + const auto cham = mChamMaterials.find(sName); + if (cham != mChamMaterials.end()) + return cham->second.sVMT; + + return ""; +} + +void CMaterials::AddMaterial(std::string sName) +{ + if (FNV1A::Hash(sName.c_str()) == FNV1A::HashConst("Original") || std::filesystem::exists(MaterialFolder + "\\" + sName + ".vmt") || mChamMaterials.contains(sName)) + return; + + Material_t mat = {}; + mat.sVMT = "\"VertexLitGeneric\"\n{\n\t\n}"; + + const auto kv = new KeyValues(sName.c_str()); + kv->LoadFromBuffer(sName.c_str(), mat.sVMT.c_str()); + mat.pMaterial = CreateNRef(std::format("m_pMat%s", sName).c_str(), kv); + + mChamMaterials[sName] = mat; + + std::ofstream outStream(MaterialFolder + "\\" + sName + ".vmt"); + outStream << mat.sVMT; + outStream.close(); +} + +void CMaterials::EditMaterial(std::string sName, std::string sVMT) +{ + if (!std::filesystem::exists(MaterialFolder + "\\" + sName + ".vmt")) + return; + + const auto cham = mChamMaterials.find(sName); + if (cham != mChamMaterials.end()) + { + if (cham->second.bLocked) + return; + + cham->second.sVMT = sVMT; + + const auto kv = new KeyValues(sName.c_str()); + kv->LoadFromBuffer(sName.c_str(), sVMT.c_str()); + cham->second.pMaterial = CreateNRef(std::format("m_pMat%s", sName).c_str(), kv); + + std::ofstream outStream(MaterialFolder + "\\" + sName + ".vmt"); + outStream << sVMT; + outStream.close(); + } +} + +void CMaterials::RemoveMaterial(std::string sName) +{ + if (!std::filesystem::exists(MaterialFolder + "\\" + sName + ".vmt")) + return; + + const auto cham = mChamMaterials.find(sName); + if (cham != mChamMaterials.end()) + { + if (cham->second.bLocked) + return; + + if (cham->second.pMaterial) + { + cham->second.pMaterial->DecrementReferenceCount(); + cham->second.pMaterial->DeleteIfUnreferenced(); + cham->second.pMaterial = nullptr; + } + + mChamMaterials.erase(cham); + } + + std::filesystem::remove(MaterialFolder + "\\" + sName + ".vmt"); + + auto removeFromVar = [sName](ConfigVar>& var) + { + for (auto& [_, val] : var.Map) + { + for (auto it = val.begin(); it != val.end();) + { + if (*it == sName) + it = val.erase(it); + else + ++it; + } + } + }; + removeFromVar(Vars::Chams::Friendly::VisibleMaterial); + removeFromVar(Vars::Chams::Friendly::OccludedMaterial); + removeFromVar(Vars::Chams::Enemy::VisibleMaterial); + removeFromVar(Vars::Chams::Enemy::OccludedMaterial); + removeFromVar(Vars::Chams::World::VisibleMaterial); + removeFromVar(Vars::Chams::World::OccludedMaterial); + removeFromVar(Vars::Chams::Backtrack::VisibleMaterial); + removeFromVar(Vars::Chams::FakeAngle::VisibleMaterial); + removeFromVar(Vars::Chams::Viewmodel::VisibleMaterial); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Materials/Materials.h b/Amalgam/src/Features/Visuals/Materials/Materials.h new file mode 100644 index 0000000..c183e7f --- /dev/null +++ b/Amalgam/src/Features/Visuals/Materials/Materials.h @@ -0,0 +1,38 @@ +#pragma once +#include "../../../SDK/SDK.h" + +#define MaterialFolder (F::Configs.sConfigPath + "\\Materials") + +struct Material_t +{ + IMaterial* pMaterial; + + std::string sVMT = ""; // will be shown to user through material editor, for glow this won't matter + bool bLocked = false; + +}; + +class CMaterials +{ +public: + IMaterial* CreateNRef(char const* szName, KeyValues* pKV); + + void LoadMaterials(); + void UnloadMaterials(); + void ReloadMaterials(); + + IMaterial* GetMaterial(std::string sName); + std::string GetVMT(std::string sName); + + void AddMaterial(std::string sName); + void EditMaterial(std::string sName, std::string sVMT); + void RemoveMaterial(std::string sName); + + void SetColor(IMaterial* material, Color_t color, bool bSetColor = true); + + std::unordered_map mChamMaterials; + std::unordered_map mGlowMaterials; + std::unordered_map mMatList; +}; + +ADD_FEATURE(CMaterials, Materials) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Notifications/Notifications.cpp b/Amalgam/src/Features/Visuals/Notifications/Notifications.cpp new file mode 100644 index 0000000..07676c1 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Notifications/Notifications.cpp @@ -0,0 +1,43 @@ +#include "Notifications.h" + +void CNotifications::Add(const std::string& sText, Color_t cColor, float flLifeTime) +{ + vNotifications.push_back({ sText, cColor, float(SDK::PlatFloatTime()) + flLifeTime }); +} + +void CNotifications::Draw() +{ + if (vNotifications.size() > unsigned(iMaxNotifySize + 1)) + vNotifications.erase(vNotifications.begin()); + + for (auto it = vNotifications.begin(); it != vNotifications.end();) + { + if (it->m_flTime <= SDK::PlatFloatTime()) + it = vNotifications.erase(it); + else + ++it; + } + + if (vNotifications.empty()) + return; + + int y = 2; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + for (auto& tNotification : vNotifications) + { + int x = 2; + int w, h; I::MatSystemSurface->GetTextSize(fFont.m_dwFont, SDK::ConvertUtf8ToWide(tNotification.m_sText).c_str(), w, h); + w += 4; h += 4; + + const float flLife = std::min(tNotification.m_flTime - SDK::PlatFloatTime(), Vars::Logging::Lifetime.Value - (tNotification.m_flTime - SDK::PlatFloatTime())); + if (flLife < 0.1f) + x -= Math::RemapValClamped(flLife, 0.1f, 0.f, 0.f, w); + + auto& cAccent = Vars::Menu::Theme::Accent.Value, & cActive = Vars::Menu::Theme::Active.Value, & cBackground = Vars::Menu::Theme::Background.Value; + H::Draw.Line(x, y, x, y + h, { cAccent.r, cAccent.g, cAccent.b, 255 }); + H::Draw.GradientRect(x + 1, y, w, h, { cBackground.r, cBackground.g, cBackground.b, 255 }, { cBackground.r, cBackground.g, cBackground.b, 0 }, true); + H::Draw.String(fFont, x + 6, y + 2, { cActive.r, cActive.g, cActive.b, 255 }, ALIGN_TOPLEFT, tNotification.m_sText.c_str()); + + y += h + 2; + } +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Notifications/Notifications.h b/Amalgam/src/Features/Visuals/Notifications/Notifications.h new file mode 100644 index 0000000..ba1d702 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Notifications/Notifications.h @@ -0,0 +1,21 @@ +#pragma once +#include "../../../SDK/SDK.h" + +struct Notification_t +{ + std::string m_sText; + Color_t m_cColor; + float m_flTime; +}; + +class CNotifications +{ + std::vector vNotifications; + int iMaxNotifySize = 8; + +public: + void Add(const std::string& sText, Color_t cColor = { 255, 255, 255, 255 }, float flLifeTime = Vars::Logging::Lifetime.Value); + void Draw(); +}; + +ADD_FEATURE(CNotifications, Notifications) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/PlayerArrows/PlayerArrows.cpp b/Amalgam/src/Features/Visuals/PlayerArrows/PlayerArrows.cpp new file mode 100644 index 0000000..0db863f --- /dev/null +++ b/Amalgam/src/Features/Visuals/PlayerArrows/PlayerArrows.cpp @@ -0,0 +1,113 @@ +#include "PlayerArrows.h" + +bool CPlayerArrows::ShouldRun(CTFPlayer* pLocal) +{ + if (!Vars::Visuals::FOVArrows::Enabled.Value) + return false; + + if (!pLocal->IsAlive() || pLocal->IsStunned()) + return false; + + if (pLocal->IsInBumperKart() || pLocal->IsAGhost()) + return false; + + return true; +} + +void CPlayerArrows::DrawArrowTo(const Vec3& vecFromPos, const Vec3& vecToPos, Color_t color) +{ + const auto cx = static_cast(H::Draw.m_nScreenW / 2); + const auto cy = static_cast(H::Draw.m_nScreenH / 2); + + bool onScreen; Vec3 vScreenPos = {}; + { + const matrix3x4& worldToScreen = H::Draw.m_WorldToProjection.As3x4(); + float w = worldToScreen[3][0] * vecToPos[0] + worldToScreen[3][1] * vecToPos[1] + worldToScreen[3][2] * vecToPos[2] + worldToScreen[3][3]; + vScreenPos.z = 0; + + onScreen = w > 0.f; + float fl1DBw = 1 / abs(w); + vScreenPos.x = cx + (0.5 * ((worldToScreen[0][0] * vecToPos[0] + worldToScreen[0][1] * vecToPos[1] + worldToScreen[0][2] * vecToPos[2] + worldToScreen[0][3]) * fl1DBw) * cx + 0.5); + vScreenPos.y = cy - (0.5 * ((worldToScreen[1][0] * vecToPos[0] + worldToScreen[1][1] * vecToPos[1] + worldToScreen[1][2] * vecToPos[2] + worldToScreen[1][3]) * fl1DBw) * cy + 0.5); + } + + /* + if (onScreen && !(vScreenPos.x < 0 || + vScreenPos.x > H::Draw.m_nScreenW || + vScreenPos.y < 0 || + vScreenPos.y > H::Draw.m_nScreenH)) + return; + */ + + if (onScreen) + { + float minc = std::min(cx, cy); float maxc = std::max(cx, cy); + float dist = sqrt(powf(vScreenPos.x - cx, 2) + powf(vScreenPos.y - cy, 2)) * 2; + float transparency; + if (minc != maxc) + transparency = 1 - std::clamp((dist - minc) / (maxc - minc), 0.f, 1.f); + else + transparency = 1 - std::clamp(dist - minc, 0.f, 1.f); + color.a = static_cast(std::max(static_cast(color.a) - transparency * 255.f, 0.f)); + } + + if (color.a == 0) + return; + + Vec2 + p1 = { static_cast(-Vars::Visuals::FOVArrows::Offset.Value), 12.5f }, + p2 = { static_cast(-Vars::Visuals::FOVArrows::Offset.Value), -12.5f }, + p3 = { static_cast(-Vars::Visuals::FOVArrows::Offset.Value) - 25.f * sqrt(3.f) / 2.f, 0.f }; + + auto angle = Vec3(); + Math::VectorAngles(Vec3(cx - vScreenPos.x, cy - vScreenPos.y, 0), angle); + const float deg = DEG2RAD(angle.y); + const float _cos = cos(deg); + const float _sin = sin(deg); + + Vertex_t t1, t2, t3; + t1.Init({ cx + p1.x * _cos - p1.y * _sin, cy + p1.y * _cos + p1.x * _sin }); + t2.Init({ cx + p2.x * _cos - p2.y * _sin, cy + p2.y * _cos + p2.x * _sin }); + t3.Init({ cx + p3.x * _cos - p3.y * _sin, cy + p3.y * _cos + p3.x * _sin }); + std::array verts{ t1, t2, t3 }; + H::Draw.Polygon(3, verts.data(), color); +} + +void CPlayerArrows::Run(CTFPlayer* pLocal) +{ + if (!ShouldRun(pLocal)) + return; + + const Vec3 vLocalPos = pLocal->GetEyePosition(); + + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ENEMIES)) + { + auto pPlayer = pEntity->As(); + if (!pPlayer->IsAlive() || pPlayer->IsCloaked() || pPlayer->IsAGhost()) + continue; + + Vec3 vEnemyPos = pPlayer->GetCenter(); + + Color_t color; + if (!Vars::Colors::Relative.Value) + { + if (pLocal->m_iTeamNum() == 2) + color = Vars::Colors::TeamBlu.Value; + else + color = Vars::Colors::TeamRed.Value; + } + else + color = Vars::Colors::Enemy.Value; + if (pPlayer->InCond(TF_COND_DISGUISED)) + color = Vars::Colors::Cloak.Value; + + auto MapFloat = [&](float x, float in_min, float in_max, float out_min, float out_max) -> float + { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + }; + const float fMap = std::clamp(MapFloat(vLocalPos.DistTo(vEnemyPos), Vars::Visuals::FOVArrows::MaxDist.Value, Vars::Visuals::FOVArrows::MaxDist.Value * 0.9f, 0.0f, 1.0f), 0.0f, 1.0f); + color.a = static_cast(fMap * 255.f); + + DrawArrowTo(vLocalPos, vEnemyPos, color); + } +} diff --git a/Amalgam/src/Features/Visuals/PlayerArrows/PlayerArrows.h b/Amalgam/src/Features/Visuals/PlayerArrows/PlayerArrows.h new file mode 100644 index 0000000..a1cc5ea --- /dev/null +++ b/Amalgam/src/Features/Visuals/PlayerArrows/PlayerArrows.h @@ -0,0 +1,14 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CPlayerArrows +{ +private: + bool ShouldRun(CTFPlayer* pLocal); + void DrawArrowTo(const Vec3& vecFromPos, const Vec3& vecToPos, Color_t color); + +public: + void Run(CTFPlayer* pLocal); +}; + +ADD_FEATURE(CPlayerArrows, PlayerArrows) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Radar/Radar.cpp b/Amalgam/src/Features/Visuals/Radar/Radar.cpp new file mode 100644 index 0000000..32a6377 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Radar/Radar.cpp @@ -0,0 +1,372 @@ +#include "Radar.h" + +bool CRadar::GetDrawPosition(CTFPlayer* pLocal, CBaseEntity* pEntity, int& x, int& y, int& z) +{ + const float flRange = Vars::Radar::Main::Range.Value; + const float flYaw = I::EngineClient->GetViewAngles().y * (PI / 180.f); + const float flCos = cosf(flYaw), flSin = sinf(flYaw); + + const Vec3 vDelta = pEntity->GetAbsOrigin() - pLocal->GetAbsOrigin(); + auto vPos = Vec2((vDelta.y * (-flCos) + vDelta.x * flSin), (vDelta.x * (-flCos) - vDelta.y * flSin)); + z = vDelta.z; + + switch (Vars::Radar::Main::Style.Value) + { + case 0: + { + const float flDist = vDelta.Length2D(); + if (flDist > flRange) + { + if (!Vars::Radar::Main::AlwaysDraw.Value) + return false; + + vPos *= flRange / flDist; + } + break; + } + case 1: + if (fabs(vPos.x) > flRange || fabs(vPos.y) > flRange) + { + if (!Vars::Radar::Main::AlwaysDraw.Value) + return false; + + if (vPos.y > vPos.x) + { + if (vPos.y > -vPos.x) + vPos.x = flRange * vPos.x / vPos.y, vPos.y = flRange; + else + vPos.y = -flRange * vPos.y / vPos.x, vPos.x = -flRange; + } + else + { + if (vPos.y > -vPos.x) + vPos.y = flRange * vPos.y / vPos.x, vPos.x = flRange; + else + vPos.x = -flRange * vPos.x / vPos.y, vPos.y = -flRange; + } + } + } + + const WindowBox_t& info = Vars::Radar::Main::Window.Value; + x = info.x + vPos.x / flRange * info.w / 2 + float(info.w) / 2; + y = info.y + vPos.y / flRange * info.w / 2 + float(info.w) / 2; + + return true; +} + +void CRadar::DrawBackground() +{ + const WindowBox_t& info = Vars::Radar::Main::Window.Value; + const auto& themeBack = Vars::Menu::Theme::Background.Value; + const auto& themeAccent = Vars::Menu::Theme::Accent.Value; + const Color_t backgroundColor = { themeBack.r, themeBack.g, themeBack.b, static_cast(Vars::Radar::Main::BackAlpha.Value) }; + const Color_t accentColor = { themeAccent.r, themeAccent.g, themeAccent.b, static_cast(Vars::Radar::Main::LineAlpha.Value) }; + + switch (Vars::Radar::Main::Style.Value) + { + case 0: + { + const float flRadius = float(info.w) / 2; + H::Draw.FillCircle(info.x + flRadius, info.y + flRadius, flRadius, 100, backgroundColor); + H::Draw.LineCircle(info.x + flRadius, info.y + flRadius, flRadius, 100, accentColor); + break; + } + case 1: + H::Draw.FillRect(info.x, info.y, info.w, info.w, backgroundColor); + H::Draw.LineRect(info.x, info.y, info.w, info.w, accentColor); + } + + H::Draw.Line(info.x + info.w / 2, info.y, info.x + info.w / 2, info.y + info.w, accentColor); + H::Draw.Line(info.x, info.y + info.w / 2, info.x + info.w, info.y + info.w / 2, accentColor); +} + +void CRadar::DrawPoints(CTFPlayer* pLocal) +{ + // Ammo & Health + if (Vars::Radar::World::Enabled.Value) + { + const int iSize = Vars::Radar::World::IconSize.Value; + + if (Vars::Radar::World::Draw.Value & 1 << 4) + { + for (auto pGargy : H::Entities.GetGroup(EGroupType::WORLD_GARGOYLE)) + { + int x, y, z; + if (GetDrawPosition(pLocal, pGargy, x, y, z)) + { + if (Vars::Radar::World::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, Vars::Colors::Halloween.Value); + } + + H::Draw.Texture(x, y, iSize, iSize, 38); + } + } + for (auto pBook : H::Entities.GetGroup(EGroupType::WORLD_SPELLBOOK)) + { + int x, y, z; + if (GetDrawPosition(pLocal, pBook, x, y, z)) + { + if (Vars::Radar::World::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, Vars::Colors::Halloween.Value); + } + + H::Draw.Texture(x, y, iSize, iSize, 37); + } + } + } + + if (Vars::Radar::World::Draw.Value & 1 << 3) + { + for (auto bBomb : H::Entities.GetGroup(EGroupType::WORLD_BOMBS)) + { + int x, y, z; + if (GetDrawPosition(pLocal, bBomb, x, y, z)) + { + if (Vars::Radar::World::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, Vars::Colors::Bomb.Value); + } + + H::Draw.Texture(x, y, iSize, iSize, 36); + } + } + } + + if (Vars::Radar::World::Draw.Value & 1 << 2) + { + for (auto pBook : H::Entities.GetGroup(EGroupType::WORLD_MONEY)) + { + int x, y, z; + if (GetDrawPosition(pLocal, pBook, x, y, z)) + { + if (Vars::Radar::World::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, Vars::Colors::Money.Value); + } + + H::Draw.Texture(x, y, iSize, iSize, 35); + } + } + } + + if (Vars::Radar::World::Draw.Value & 1 << 1) + { + for (auto pAmmo : H::Entities.GetGroup(EGroupType::WORLD_AMMO)) + { + int x, y, z; + if (GetDrawPosition(pLocal, pAmmo, x, y, z)) + { + if (Vars::Radar::World::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, Vars::Colors::Ammo.Value); + } + + H::Draw.Texture(x, y, iSize, iSize, 34); + } + } + } + + if (Vars::Radar::World::Draw.Value & 1 << 0) + { + for (auto pHealth : H::Entities.GetGroup(EGroupType::WORLD_HEALTH)) + { + int x, y, z; + if (GetDrawPosition(pLocal, pHealth, x, y, z)) + { + if (Vars::Radar::World::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, Vars::Colors::Health.Value); + } + + H::Draw.Texture(x, y, iSize, iSize, 33); + } + } + } + } + + // Draw buildings + if (Vars::Radar::Buildings::Enabled.Value) + { + const int iSize = Vars::Radar::Buildings::IconSize.Value; + + for (auto pEntity : H::Entities.GetGroup(EGroupType::BUILDINGS_ALL)) + { + auto pBuilding = pEntity->As(); + + if (!pBuilding->m_bWasMapPlaced()) + { + auto pOwner = pBuilding->m_hBuilder().Get(); + if (pOwner) + { + const int nIndex = pOwner->entindex(); + if (nIndex != I::EngineClient->GetLocalPlayer() && pOwner != H::Entities.GetObservedTarget()) + { + if (!(Vars::Radar::Buildings::Draw.Value & 1 << 3 && H::Entities.IsFriend(nIndex))) + { + if (!(Vars::Radar::Buildings::Draw.Value & 1 << 1) && pOwner->As()->m_iTeamNum() != pLocal->m_iTeamNum()) + continue; + if (!(Vars::Radar::Buildings::Draw.Value & 1 << 2) && pOwner->As()->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + } + } + else if (!(Vars::Radar::Buildings::Draw.Value & 1 << 0)) + continue; + } + } + + int x, y, z; + if (GetDrawPosition(pLocal, pBuilding, x, y, z)) + { + const Color_t drawColor = H::Color.GetEntityDrawColor(pLocal, pBuilding, Vars::Colors::Relative.Value); + + int iBounds = iSize; + if (Vars::Radar::Buildings::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, drawColor); + iBounds = flRadius * 2; + } + + switch (pBuilding->GetClassID()) + { + case ETFClassID::CObjectSentrygun: + H::Draw.Texture(x, y, iSize, iSize, 26 + pBuilding->m_iUpgradeLevel()); + break; + case ETFClassID::CObjectDispenser: + H::Draw.Texture(x, y, iSize, iSize, 30); + break; + case ETFClassID::CObjectTeleporter: + H::Draw.Texture(x, y, iSize, iSize, pBuilding->m_iObjectMode() ? 32 : 31); + break; + } + + if (Vars::Radar::Buildings::Health.Value) + { + const int iMaxHealth = pBuilding->m_iMaxHealth(), iHealth = pBuilding->m_iHealth(); + + float flRatio = std::clamp(float(iHealth) / iMaxHealth, 0.f, 1.f); + Color_t cColor = Vars::Colors::HealthBar.Value.StartColor.Lerp(Vars::Colors::HealthBar.Value.EndColor, flRatio); + H::Draw.FillRectPercent(x - iBounds / 2, y - iBounds / 2, 2, iBounds, flRatio, cColor, { 0, 0, 0, 255 }, ALIGN_BOTTOM, true); + + if (iHealth > iMaxHealth) + { + const float flMaxOverheal = floorf(iMaxHealth / 10.f) * 5; + flRatio = std::clamp((iHealth - iMaxHealth) / flMaxOverheal, 0.f, 1.f); + cColor = Vars::Colors::Overheal.Value; + H::Draw.FillRectPercent(x - iBounds / 2, y - iBounds / 2, 2, iBounds, flRatio, cColor, { 0, 0, 0, 0 }, ALIGN_BOTTOM, true); + } + } + } + } + } + + // Draw Players + if (Vars::Radar::Players::Enabled.Value) + { + const int iSize = Vars::Radar::Players::IconSize.Value; + + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + auto pPlayer = pEntity->As(); + if (!pPlayer->IsAlive() || pPlayer->IsAGhost()) + continue; + + const int nIndex = pPlayer->entindex(); + if (nIndex != I::EngineClient->GetLocalPlayer() && pPlayer != H::Entities.GetObservedTarget()) + { + if (!(Vars::Radar::Players::Draw.Value & 1 << 3 && H::Entities.IsFriend(nIndex))) + { + if (!(Vars::Radar::Players::Draw.Value & 1 << 1) && pPlayer->m_iTeamNum() != pLocal->m_iTeamNum()) + continue; + if (!(Vars::Radar::Players::Draw.Value & 1 << 2) && pPlayer->m_iTeamNum() == pLocal->m_iTeamNum()) + continue; + } + } + else if (!(Vars::Radar::Players::Draw.Value & 1 << 0)) + continue; + if (!(Vars::Radar::Players::Draw.Value & 1 << 4) && pPlayer->m_flInvisibility() >= 1.f) + continue; + + int x, y, z; + if (GetDrawPosition(pLocal, pPlayer, x, y, z)) + { + const Color_t drawColor = H::Color.GetEntityDrawColor(pLocal, pPlayer, Vars::Colors::Relative.Value); + + int iBounds = iSize; + if (Vars::Radar::Players::Background.Value) + { + const float flRadius = sqrtf(pow(iSize, 2) * 2) / 2; + H::Draw.FillCircle(x, y, flRadius, 20, drawColor); + iBounds = flRadius * 2; + } + + switch (Vars::Radar::Players::IconType.Value) + { + case 2: + { + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi) && !pi.fakeplayer) + { + H::Draw.Avatar(x, y, iSize, iSize, pi.friendsID); + break; + } + [[fallthrough]]; + } + case 1: + if (pPlayer->IsInValidTeam()) + { + H::Draw.Texture(x, y, iSize, iSize, pPlayer->m_iClass() + (pPlayer->m_iTeamNum() == TF_TEAM_RED ? 9 : 18) - 1); + break; + } + [[fallthrough]]; + case 0: + H::Draw.Texture(x, y, iSize, iSize, pPlayer->m_iClass() - 1); + break; + } + + if (Vars::Radar::Players::Health.Value) + { + const int iMaxHealth = pPlayer->m_iMaxHealth(), iHealth = pPlayer->m_iHealth(); + + float flRatio = std::clamp(float(iHealth) / iMaxHealth, 0.f, 1.f); + Color_t cColor = Vars::Colors::HealthBar.Value.StartColor.Lerp(Vars::Colors::HealthBar.Value.EndColor, flRatio); + H::Draw.FillRectPercent(x - iBounds / 2, y - iBounds / 2, 2, iBounds, flRatio, cColor, { 0, 0, 0, 255 }, ALIGN_BOTTOM, true); + + if (iHealth > iMaxHealth) + { + const float flMaxOverheal = floorf(iMaxHealth / 10.f) * 5; + flRatio = std::clamp((iHealth - iMaxHealth) / flMaxOverheal, 0.f, 1.f); + cColor = Vars::Colors::Overheal.Value; + H::Draw.FillRectPercent(x - iBounds / 2, y - iBounds / 2, 2, iBounds, flRatio, cColor, { 0, 0, 0, 0 }, ALIGN_BOTTOM, true); + } + } + + if (Vars::Radar::Players::Height.Value && std::abs(z) > 80.f) + { + const int m = x - iSize / 2; + const int iOffset = z > 0 ? -5 : 5; + const int yPos = z > 0 ? y - iBounds / 2 - 2 : y + iBounds / 2 + 2; + + H::Draw.DrawFillTriangle({ Vec2(m, yPos), Vec2(m + iSize * 0.5f, yPos + iOffset), Vec2(m + iSize, yPos) }, drawColor); + } + } + } + } +} + +void CRadar::Run(CTFPlayer* pLocal) +{ + if (!Vars::Radar::Main::Enabled.Value) + return; + + DrawBackground(); + DrawPoints(pLocal); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Radar/Radar.h b/Amalgam/src/Features/Visuals/Radar/Radar.h new file mode 100644 index 0000000..d4b48e0 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Radar/Radar.h @@ -0,0 +1,14 @@ +#pragma once +#include "../../../SDK/SDK.h" + +class CRadar +{ + bool GetDrawPosition(CTFPlayer* pLocal, CBaseEntity* pEntity, int& x, int& y, int& z); + void DrawBackground(); + void DrawPoints(CTFPlayer* pLocal); + +public: + void Run(CTFPlayer* pLocal); +}; + +ADD_FEATURE(CRadar, Radar) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp b/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp new file mode 100644 index 0000000..2b682df --- /dev/null +++ b/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp @@ -0,0 +1,138 @@ +#include "SpectatorList.h" + +bool CSpectatorList::GetSpectators(CTFPlayer* pLocal) +{ + Spectators.clear(); + + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_TEAMMATES)) + { + auto pPlayer = pEntity->As(); + + if (!pPlayer->IsAlive() && pPlayer->m_hObserverTarget().Get() == pLocal) + { + std::wstring szMode; + switch (pPlayer->m_iObserverMode()) + { + case OBS_MODE_FIRSTPERSON: + { + szMode = L"1st"; + break; + } + case OBS_MODE_THIRDPERSON: + { + szMode = L"3rd"; + break; + } + default: + continue; + } + + int respawnIn = 0; float respawnTime = 0; + if (auto pResource = H::Entities.GetPR()) + { + respawnTime = pResource->GetNextRespawnTime(pPlayer->entindex()); + respawnIn = std::max(int(respawnTime - I::GlobalVars->curtime), 0); + } + bool respawnTimeIncreased = false; // theoretically the respawn times could be changed by the map but oh well + if (!RespawnCache.contains(pPlayer->entindex())) + RespawnCache[pPlayer->entindex()] = respawnTime; + if (RespawnCache[pPlayer->entindex()] + 0.9f < respawnTime) + { + respawnTimeIncreased = true; + RespawnCache[pPlayer->entindex()] = -1.f; + } + + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi)) + { + Spectators.push_back({ + SDK::ConvertUtf8ToWide(pi.name), szMode, respawnIn, respawnTimeIncreased, H::Entities.IsFriend(pPlayer->entindex()), + pPlayer->m_iTeamNum(), pPlayer->entindex() + }); + } + } + else + { + auto iter = RespawnCache.find(pPlayer->entindex()); + if (iter != RespawnCache.end()) + RespawnCache.erase(iter); + } + } + + return !Spectators.empty(); +} + +void CSpectatorList::Run(CTFPlayer* pLocal) +{ + if (!(Vars::Menu::Indicators.Value & (1 << 2))) + { + RespawnCache.clear(); + return; + } + + if (!pLocal->IsAlive() || !GetSpectators(pLocal)) + return; + + int x = Vars::Menu::SpectatorsDisplay.Value.x; + int iconOffset = 0; + int y = Vars::Menu::SpectatorsDisplay.Value.y + 8; + + EAlign align = ALIGN_TOP; + if (x <= (100 + 50 * Vars::Menu::DPI.Value)) + { + // iconOffset = 36; + x -= 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPLEFT; + } + else if (x >= H::Draw.m_nScreenW - (100 + 50 * Vars::Menu::DPI.Value)) + { + x += 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPRIGHT; + } + //else + // iconOffset = 16; + + //if (!Vars::Menu::SpectatorAvatars.Value) + // iconOffset = 0; + + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Accent.Value, align, L"Spectating You:"); + for (const auto& Spectator : Spectators) + { + y += fFont.m_nTall + 3; + + /* + if (Vars::Visuals::SpectatorAvatars.Value) + { + int w, h; + + I::MatSystemSurface->GetTextSize(H::Fonts.GetFont(FONT_INDICATORS).dwFont, + (Spectator.Name + Spectator.Mode + std::to_wstring(Spectator.RespawnIn) + std::wstring{L" - (respawn s)"}).c_str(), w, h); + switch (align) + { + case ALIGN_DEFAULT: w = 0; break; + case ALIGN_CENTERHORIZONTAL: w /= 2; break; + } + + PlayerInfo_t pi{}; + if (!I::EngineClient->GetPlayerInfo(Spectator.Index, &pi)) + continue; + + H::Draw.Avatar(x - w - (36 - iconOffset), y, 24, 24, pi.friendsID); + // center - half the width of the string + y += 6; + } + */ + + Color_t color = Vars::Menu::Theme::Active.Value; + if (Spectator.Mode == std::wstring{L"1st"}) + color = { 255, 200, 127, 255 }; + if (Spectator.RespawnTimeIncreased) + color = { 255, 100, 100, 255 }; + if (Spectator.IsFriend) + color = { 200, 255, 200, 255 }; + H::Draw.String(fFont, x + iconOffset, y, color, align, + L"%ls - %ls (respawn %ds)", Spectator.Name.data(), Spectator.Mode.data(), Spectator.RespawnIn); + } +} diff --git a/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.h b/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.h new file mode 100644 index 0000000..194945e --- /dev/null +++ b/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.h @@ -0,0 +1,28 @@ +#pragma once +#include "../../../SDK/SDK.h" +#include + +class CSpectatorList +{ +private: + struct Spectator_t + { + std::wstring Name; + std::wstring Mode; + int RespawnIn; + bool RespawnTimeIncreased; + bool IsFriend; + int Team; + int Index; + }; + + std::vector Spectators; + std::unordered_map RespawnCache; + +public: + int SpecListX = 30, SpecListY = 100; + bool GetSpectators(CTFPlayer* pLocal); + void Run(CTFPlayer* pLocal); +}; + +ADD_FEATURE(CSpectatorList, SpectatorList) \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Visuals.cpp b/Amalgam/src/Features/Visuals/Visuals.cpp new file mode 100644 index 0000000..01f9ff5 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Visuals.cpp @@ -0,0 +1,797 @@ +#include "Visuals.h" + +#include "../ImGui/Render.h" +#include "../Visuals/LocalConditions/LocalConditions.h" +#include "../Backtrack/Backtrack.h" +#include "../PacketManip/AntiAim/AntiAim.h" +#include "../Simulation/ProjectileSimulation/ProjectileSimulation.h" +#include "../CameraWindow/CameraWindow.h" +#include "../NoSpread/NoSpreadHitscan/NoSpreadHitscan.h" +#include "Materials/Materials.h" + +#include +#include + +MAKE_SIGNATURE(RenderLine, "engine.dll", "48 89 5C 24 ? 48 89 74 24 ? 44 89 44 24", 0x0); +MAKE_SIGNATURE(RenderBox, "engine.dll", "48 83 EC ? 8B 84 24 ? ? ? ? 4D 8B D8", 0x0); +MAKE_SIGNATURE(RenderWireframeBox, "engine.dll", "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 55 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 49 8B F9", 0x0); +MAKE_SIGNATURE(DrawServerHitboxes, "server.dll", "44 88 44 24 ? 53 48 81 EC", 0x0); +MAKE_SIGNATURE(GetServerAnimating, "server.dll", "48 83 EC ? 8B D1 85 C9 7E ? 48 8B 05", 0x0); +MAKE_SIGNATURE(LoadSkys, "engine.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 56 41 57 48 81 EC ? ? ? ? 48 8D 05", 0x0); + +void CVisuals::DrawAimbotFOV(CTFPlayer* pLocal) +{ + if (!Vars::Aimbot::General::FOVCircle.Value || !Vars::Colors::FOVCircle.Value.a || !pLocal->IsAlive() || pLocal->IsAGhost() || pLocal->IsTaunting() || pLocal->IsStunned() || pLocal->IsInBumperKart()) + return; + + const float flR = tanf(DEG2RAD(Vars::Aimbot::General::AimFOV.Value) / 2.0f) / tanf(DEG2RAD(pLocal->m_iFOV()) / 2.0f) * H::Draw.m_nScreenW; + const Color_t clr = Vars::Colors::FOVCircle.Value; + H::Draw.LineCircle(H::Draw.m_nScreenW / 2, H::Draw.m_nScreenH / 2, flR, 68, clr); +} + +void CVisuals::DrawTickbaseText(CTFPlayer* pLocal) +{ + if (!(Vars::Menu::Indicators.Value & (1 << 0))) + return; + + if (!pLocal->IsAlive()) + return; + + const int iTicks = std::clamp(G::ShiftedTicks + G::ChokeAmount, 0, G::MaxShift); + + const DragBox_t dtPos = Vars::Menu::TicksDisplay.Value; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + const int offset = 7 + 12 * Vars::Menu::DPI.Value; + H::Draw.String(fFont, dtPos.x, dtPos.y + 2, Vars::Menu::Theme::Active.Value, ALIGN_TOP, "Ticks %d / %d", iTicks, G::MaxShift); + if (G::WaitForShift) + H::Draw.String(fFont, dtPos.x, dtPos.y + fFont.m_nTall + offset, Vars::Menu::Theme::Active.Value, ALIGN_TOP, "Not Ready"); + + const float ratioCurrent = (float)iTicks / (float)G::MaxShift; + float sizeX = 100 * Vars::Menu::DPI.Value, sizeY = 12 * Vars::Menu::DPI.Value, posX = dtPos.x - sizeX / 2, posY = dtPos.y + 5 + fFont.m_nTall; + H::Draw.LineRect(posX, dtPos.y + 5 + fFont.m_nTall, sizeX, sizeY, Vars::Menu::Theme::Accent.Value); + if (iTicks) + { + sizeX -= 4, sizeY -= 4, posX = dtPos.x - sizeX / 2; + H::Draw.StartClipping(posX, posY, sizeX * ratioCurrent, sizeY + 2 /*?*/); + H::Draw.FillRect(posX, posY + 2, sizeX, sizeY, Vars::Menu::Theme::Accent.Value); + H::Draw.EndClipping(); + } +} +void CVisuals::DrawTickbaseBars() +{ + /* get rid of me + + if (!(Vars::Menu::Indicators.Value & (1 << 0)) || I::EngineVGui->IsGameUIVisible()) + return; + + auto pLocal = I::ClientEntityList->GetClientEntity(I::EngineClient->GetLocalPlayer()); + if (!pLocal || !pLocal->As()->IsAlive()) + return; + + const int iTicks = std::clamp(G::ShiftedTicks + G::ChokeAmount, 0, G::MaxShift); + + const DragBox_t dtPos = Vars::Menu::TicksDisplay.Value; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + const float ratioCurrent = (float)iTicks / (float)G::MaxShift; + + float sizeX = 100 * Vars::Menu::DPI.Value, sizeY = 12 * Vars::Menu::DPI.Value, posY = dtPos.y + 5 + fFont.m_nTall; + ImGui::GetBackgroundDrawList()->AddRectFilled( + ImVec2(dtPos.x - sizeX / 2, posY), ImVec2(dtPos.x + sizeX / 2, posY + sizeY), + F::Render.Background, 10 + ); + if (iTicks && ratioCurrent) + { + sizeX = 96 * Vars::Menu::DPI.Value, sizeY = 8 * Vars::Menu::DPI.Value; posY = posY + 2 * Vars::Menu::DPI.Value; + ImGui::GetBackgroundDrawList()->PushClipRect(ImVec2(dtPos.x - sizeX / 2, posY), ImVec2(dtPos.x - sizeX / 2 + sizeX * ratioCurrent + 1, posY + sizeY), true); + ImGui::GetBackgroundDrawList()->AddRectFilled( + ImVec2(dtPos.x - sizeX / 2, posY), ImVec2(dtPos.x + sizeX / 2, posY + sizeY), + ImColor(Vars::Menu::Theme::Accent.Value.r, Vars::Menu::Theme::Accent.Value.g, Vars::Menu::Theme::Accent.Value.b, Vars::Menu::Theme::Accent.Value.a), 10 + ); + ImGui::GetBackgroundDrawList()->PopClipRect(); + } + */ +} + +void CVisuals::DrawOnScreenPing(CTFPlayer* pLocal) +{ + if (!(Vars::Menu::Indicators.Value & (1 << 3)) || !pLocal || !pLocal->IsAlive()) + return; + + auto pResource = H::Entities.GetPR(); + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + if (!pResource || !pNetChan) + return; + + const float flLatencyIn = pNetChan->GetLatency(FLOW_INCOMING) * 1000.f; + const float flLatencyOut = pNetChan->GetLatency(FLOW_OUTGOING) * 1000.f; + const float flFake = std::min((F::Backtrack.GetFake() + (F::Backtrack.flFakeInterp > G::Lerp ? F::Backtrack.flFakeInterp : 0.f)) * 1000.f, F::Backtrack.flMaxUnlag * 1000.f); + const float flLatency = F::Backtrack.GetReal() * 1000.f; + const int iLatencyScoreboard = pResource->GetPing(pLocal->entindex()); + + int x = Vars::Menu::PingDisplay.Value.x; + int y = Vars::Menu::PingDisplay.Value.y + 8; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + EAlign align = ALIGN_TOP; + if (x <= (100 + 50 * Vars::Menu::DPI.Value)) + { + x -= 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPLEFT; + } + else if (x >= H::Draw.m_nScreenW - (100 + 50 * Vars::Menu::DPI.Value)) + { + x += 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPRIGHT; + } + + if (flFake || Vars::Backtrack::Interp.Value && Vars::Backtrack::Enabled.Value) + { + if (flLatency > 0.f) + { + if (!Vars::Debug::Info.Value) + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "Real %.0f (+ %.0f) ms", flLatency, flFake); + else + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "In %.0f, Out %.0f (+ %.0f) ms", flLatencyIn, flLatencyOut, flFake); + } + else + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "Syncing"); + } + else + { + if (!Vars::Debug::Info.Value) + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "Real %.0f ms", flLatency); + else + H::Draw.String(fFont, x, y, Vars::Menu::Theme::Active.Value, align, "In %.0f, Out %.0f ms", flLatencyIn, flLatencyOut); + } + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, Vars::Menu::Theme::Active.Value, align, "Scoreboard %d ms", iLatencyScoreboard); + if (Vars::Debug::Info.Value) + { + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, align, "iTickCount %i (%i, %i, %i)", F::Backtrack.iTickCount, TIME_TO_TICKS(F::Backtrack.GetReal()), TIME_TO_TICKS(flLatencyIn / 1000), TIME_TO_TICKS(flLatencyOut / 1000)); + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, align, "G::AnticipatedChoke %i", G::AnticipatedChoke); + } +} + +void CVisuals::DrawOnScreenConditions(CTFPlayer* pLocal) +{ + if (!(Vars::Menu::Indicators.Value & (1 << 4)) || !pLocal->IsAlive()) + return; + + int x = Vars::Menu::ConditionsDisplay.Value.x; + int y = Vars::Menu::ConditionsDisplay.Value.y + 8; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + EAlign align = ALIGN_TOP; + if (x <= (100 + 50 * Vars::Menu::DPI.Value)) + { + x -= 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPLEFT; + } + else if (x >= H::Draw.m_nScreenW - (100 + 50 * Vars::Menu::DPI.Value)) + { + x += 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPRIGHT; + } + + std::vector conditionsVec = F::LocalConditions.GetPlayerConditions(pLocal); + + int offset = 0; + for (const std::wstring& cond : conditionsVec) + { + H::Draw.String(fFont, x, y + offset, Vars::Menu::Theme::Active.Value, align, cond.data()); + offset += fFont.m_nTall + 1; + } +} + +void CVisuals::DrawSeedPrediction(CTFPlayer* pLocal) +{ + if (!(Vars::Menu::Indicators.Value & (1 << 5)) || !pLocal || !pLocal->IsAlive() || !Vars::Aimbot::General::NoSpread.Value) + return; + + if (!Vars::Debug::Info.Value) + { + auto pWeapon = H::Entities.GetWeapon(); + if (!pWeapon || !F::NoSpreadHitscan.ShouldRun(pLocal, pWeapon)) + return; + } + + int x = Vars::Menu::SeedPredictionDisplay.Value.x; + int y = Vars::Menu::SeedPredictionDisplay.Value.y + 8; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + EAlign align = ALIGN_TOP; + if (x <= (100 + 50 * Vars::Menu::DPI.Value)) + { + x -= 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPLEFT; + } + else if (x >= H::Draw.m_nScreenW - (100 + 50 * Vars::Menu::DPI.Value)) + { + x += 42 * Vars::Menu::DPI.Value; + align = ALIGN_TOPRIGHT; + } + + const auto& cColor = F::NoSpreadHitscan.bSynced ? Vars::Menu::Theme::Active.Value : Vars::Menu::Theme::Inactive.Value; + + H::Draw.String(fFont, x, y, cColor, align, std::format("Uptime {}", F::NoSpreadHitscan.GetFormat(F::NoSpreadHitscan.flServerTime)).c_str()); + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("Mantissa step {}", F::NoSpreadHitscan.flMantissaStep).c_str()); + if (Vars::Debug::Info.Value) + { + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("Seed {}", F::NoSpreadHitscan.iSeed).c_str()); + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, cColor, align, std::format("{}", F::NoSpreadHitscan.flFloatTimeDelta).c_str()); + } +} + +void CVisuals::ProjectileTrace(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const bool bQuick) +{ + F::CameraWindow.ShouldDraw = false; + if ((bQuick ? !Vars::Visuals::Simulation::ProjectileTrajectory.Value : !Vars::Visuals::Simulation::TrajectoryOnShot.Value) || !pLocal || !pWeapon + || pWeapon->m_iWeaponID() == TF_WEAPON_FLAMETHROWER && !Vars::Debug::Info.Value) + return; + + ProjectileInfo projInfo = {}; + if (!F::ProjSim.GetInfo(pLocal, pWeapon, bQuick ? I::EngineClient->GetViewAngles() : G::CurrentUserCmd->viewangles, projInfo, true, bQuick, (bQuick && Vars::Aimbot::Projectile::AutoRelease.Value) ? Vars::Aimbot::Projectile::AutoRelease.Value / 100 : -1.f) + || !F::ProjSim.Initialize(projInfo)) + return; + + CGameTrace trace = {}; + CTraceFilterProjectile filter = {}; + filter.pSkip = pLocal; + + for (int n = -1; n < TIME_TO_TICKS(projInfo.m_flLifetime); n++) + { + Vec3 Old = F::ProjSim.GetOrigin(); + F::ProjSim.RunTick(projInfo); + Vec3 New = F::ProjSim.GetOrigin(); + + SDK::TraceHull(Old, New, projInfo.m_vHull * -1, projInfo.m_vHull, MASK_SOLID, &filter, &trace); + if (trace.DidHit()) + { + const float flSize = std::max(projInfo.m_vHull.x, 1.f); + const Vec3 vSize = { 1.f, flSize, flSize }; + Vec3 vAngles; Math::VectorAngles(trace.plane.normal, vAngles); + + if (bQuick) + { + RenderBox(trace.endpos, vSize * -1, vSize, vAngles, Vars::Colors::ProjectileColor.Value, { 0, 0, 0, 0 }); + if (Vars::Colors::ClippedColor.Value.a) + RenderBox(trace.endpos, vSize * -1, vSize, vAngles, Vars::Colors::ClippedColor.Value, { 0, 0, 0, 0 }, true); + } + else + { + G::BoxesStorage.clear(); + G::BoxesStorage.push_back({ trace.endpos, vSize * -1, vSize, vAngles, I::GlobalVars->curtime + TICKS_TO_TIME(n) + F::Backtrack.GetReal(), Vars::Colors::ProjectileColor.Value}); + } + break; + } + } + + projInfo.PredictionLines.push_back({ trace.endpos, Math::GetRotatedPosition(trace.endpos, Math::VelocityToAngles(F::ProjSim.GetVelocity() * Vec3(1, 1, 0)).Length2D() + 90, Vars::Visuals::Simulation::SeparatorLength.Value) }); + + if (bQuick) + { + DrawSimLine(projInfo.PredictionLines, Vars::Colors::ProjectileColor.Value); + if (Vars::Colors::ClippedColor.Value.a) + DrawSimLine(projInfo.PredictionLines, Vars::Colors::ClippedColor.Value, false, true); + + if (!I::EngineVGui->IsGameUIVisible() && Vars::Visuals::Simulation::ProjectileCamera.Value && pLocal->m_vecOrigin().DistTo(trace.endpos) > 500.f) + { + auto vAngles = Math::CalcAngle(trace.startpos, trace.endpos); + Vec3 vForward = {}; Math::AngleVectors(vAngles, &vForward); + SDK::Trace(trace.endpos, trace.endpos - vForward * 500.f, MASK_SOLID, &filter, &trace); + + F::CameraWindow.ShouldDraw = true; + F::CameraWindow.CameraOrigin = trace.endpos; + F::CameraWindow.CameraAngles = vAngles; + } + } + else + { + G::LinesStorage.clear(); + G::LinesStorage.push_back({ projInfo.PredictionLines, -float(projInfo.PredictionLines.size()) - TIME_TO_TICKS(F::Backtrack.GetReal()), Vars::Colors::ProjectileColor.Value }); + } +} + +void CVisuals::DrawAntiAim(CTFPlayer* pLocal) +{ + if (!pLocal->IsAlive() || pLocal->IsAGhost() || !I::Input->CAM_IsThirdPerson()) + return; + + if (F::AntiAim.AntiAimOn() && Vars::Debug::AntiAimLines.Value) + { + const auto& vOrigin = pLocal->GetAbsOrigin(); + + Vec3 vScreen1, vScreen2; + if (SDK::W2S(vOrigin, vScreen1)) + { + constexpr auto distance = 50.f; + if (SDK::W2S(Math::GetRotatedPosition(vOrigin, F::AntiAim.vRealAngles.y, distance), vScreen2)) + H::Draw.Line(vScreen1.x, vScreen1.y, vScreen2.x, vScreen2.y, { 0, 255, 0, 255 }); + + if (SDK::W2S(Math::GetRotatedPosition(vOrigin, F::AntiAim.vFakeAngles.y, distance), vScreen2)) + H::Draw.Line(vScreen1.x, vScreen1.y, vScreen2.x, vScreen2.y, { 255, 0, 0, 255 }); + } + + for (auto& vPair : F::AntiAim.vEdgeTrace) + { + if (SDK::W2S(vPair.first, vScreen1) && SDK::W2S(vPair.second, vScreen2)) + H::Draw.Line(vScreen1.x, vScreen1.y, vScreen2.x, vScreen2.y, { 255, 255, 255, 255 }); + } + } +} + +void CVisuals::DrawDebugInfo(CTFPlayer* pLocal) +{ + // Debug info + if (Vars::Debug::Info.Value) + { + int x = 10, y = 10; + const auto& fFont = H::Fonts.GetFont(FONT_INDICATORS); + + Vec3 vOrigin = pLocal->m_vecOrigin(); + H::Draw.String(fFont, x, y, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "Origin: (%.3f, %.3f, %.3f)", vOrigin.x, vOrigin.y, vOrigin.z); + + Vec3 vVelocity = pLocal->m_vecVelocity(); + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "Velocity: %.3f (%.3f, %.3f, %.3f)", vVelocity.Length(), vVelocity.x, vVelocity.y, vVelocity.z); + + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, std::format("Attacking: {}", G::IsAttacking).c_str()); + + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "RoundState: %i", SDK::GetRoundState()); + + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, std::format("Choke: {}, {}", G::Choking, I::ClientState->chokedcommands).c_str()); + + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, std::format("Ticks: {}, {}", G::ShiftedTicks, G::ShiftedGoal).c_str()); + + if (auto pCmd = G::LastUserCmd) + { + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "pCmd move: (%.0f, %.0f)", pCmd->forwardmove, pCmd->sidemove); + H::Draw.String(fFont, x, y += fFont.m_nTall + 1, { 255, 255, 255, 255 }, ALIGN_TOPLEFT, "pCmd buttons: %i", pCmd->buttons); + } + } +} + + + +std::vector CVisuals::GetHitboxes(matrix3x4 bones[128], CBaseAnimating* pEntity, const int iHitbox) +{ + std::vector vBoxes = {}; + + auto pModel = pEntity->GetModel(); + if (!pModel) return vBoxes; + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) return vBoxes; + auto pSet = pHDR->pHitboxSet(pEntity->m_nHitboxSet()); + if (!pSet) return vBoxes; + + for (int i = iHitbox != -1 ? iHitbox : 0; i < pSet->numhitboxes; ++i) + { + if (iHitbox != -1 && iHitbox != i) + break; + + auto bbox = pSet->pHitbox(i); + if (!bbox) continue; + + matrix3x4 rotMatrix; + Math::AngleMatrix(bbox->angle, rotMatrix); + + matrix3x4 matrix; + Math::ConcatTransforms(bones[bbox->bone], rotMatrix, matrix); + + Vec3 bboxAngle; + Math::MatrixAngles(matrix, bboxAngle); + + Vec3 matrixOrigin; + Math::GetMatrixOrigin(matrix, matrixOrigin); + + vBoxes.push_back({ matrixOrigin, bbox->bbmin, bbox->bbmax, bboxAngle, I::GlobalVars->curtime + 5.f, Vars::Colors::HitboxEdge.Value, Vars::Colors::HitboxFace.Value, true }); + } + + return vBoxes; +} + +void CVisuals::DrawBulletLines() +{ + for (auto& Line : G::BulletsStorage) + { + if (Line.m_flTime < I::GlobalVars->curtime) continue; + + RenderLine(Line.m_line.first, Line.m_line.second, Line.m_color, Line.m_bZBuffer); + } +} + +void CVisuals::DrawSimLine(std::deque>& Line, Color_t Color, bool bSeparators, bool bZBuffer, float flTime) +{ + for (size_t i = 1; i < Line.size(); i++) + { + if (flTime < 0.f && Line.size() - i > -flTime) + continue; + + if (!bSeparators) + RenderLine(Line.at(i - 1).first, Line.at(i).first, Color, bZBuffer); + else + { + const auto& vStart = Line[i - 1].first; + const auto& vRotate = Line[i - 1].second; + const auto& vEnd = Line[i].first; + if (((Line.size() - i) % Vars::Visuals::Simulation::SeparatorSpacing.Value) == 0) + RenderLine(vStart, vRotate, Color); + RenderLine(vStart, vEnd, Color); + } + } +} + +void CVisuals::DrawSimLines() +{ + for (auto& Line : G::LinesStorage) + { + if (Line.m_flTime >= 0.f && Line.m_flTime < I::GlobalVars->curtime) + continue; + + DrawSimLine(Line.m_line, Line.m_color, Vars::Visuals::Simulation::Separators.Value, Line.m_bZBuffer, Line.m_flTime); + } +} + +void CVisuals::DrawBoxes() +{ + for (auto& Box : G::BoxesStorage) + { + if (Box.m_flTime < I::GlobalVars->curtime) continue; + + RenderBox(Box.m_vecPos, Box.m_vecMins, Box.m_vecMaxs, Box.m_vecOrientation, Box.m_colorEdge, Box.m_colorFace, Box.m_bZBuffer); + } +} + +void CVisuals::RevealBulletLines() +{ + for (auto& Line : G::BulletsStorage) + Line.m_flTime = I::GlobalVars->curtime + 60.f; +} + +void CVisuals::RevealSimLines() +{ + for (auto& PredictionLine : G::LinesStorage) + PredictionLine.m_flTime = I::GlobalVars->curtime + 60.f; +} + +void CVisuals::RevealBoxes() +{ + for (auto& Box : G::BoxesStorage) + Box.m_flTime = I::GlobalVars->curtime + 60.f; +} + +void CVisuals::DrawServerHitboxes(CTFPlayer* pLocal) +{ + static int iOldTick = I::GlobalVars->tickcount; + if (iOldTick == I::GlobalVars->tickcount) + return; + iOldTick = I::GlobalVars->tickcount; + + if (I::Input->CAM_IsThirdPerson() && Vars::Debug::ServerHitbox.Value && pLocal->IsAlive()) + { + using GetServerAnimating_t = void* (*)(int); + static auto GetServerAnimating = S::GetServerAnimating.As(); + + using DrawServerHitboxes_t = void(__fastcall*)(void*, float, bool); // C_BaseAnimating, Duration, MonoColour + static auto DrawServerHitboxes = S::DrawServerHitboxes.As(); + + void* server_animating = GetServerAnimating(pLocal->entindex()); + if (server_animating) + DrawServerHitboxes(server_animating, TICK_INTERVAL, true); + } +} + +void CVisuals::RenderLine(const Vec3& vStart, const Vec3& vEnd, Color_t cLine, bool bZBuffer) +{ + if (cLine.a) + { + static auto fnRenderLine = S::RenderLine.As(); + fnRenderLine(vStart, vEnd, cLine, bZBuffer); + } +} + +void CVisuals::RenderBox(const Vec3& vPos, const Vec3& vMins, const Vec3& vMaxs, const Vec3& vOrientation, Color_t cEdge, Color_t cFace, bool bZBuffer) +{ + if (cFace.a) + { + static auto fnRenderBox = S::RenderBox.As(); + fnRenderBox(vPos, vOrientation, vMins, vMaxs, cFace, bZBuffer, false); + } + + if (cEdge.a) + { + static auto fnRenderWireframeBox = S::RenderWireframeBox.As(); + fnRenderWireframeBox(vPos, vOrientation, vMins, vMaxs, cEdge, bZBuffer); + } +} + + + +void CVisuals::FOV(CTFPlayer* pLocal, CViewSetup* pView) +{ + pLocal->m_iFOV() = pView->fov; + + const int fov = pLocal->IsScoped() ? Vars::Visuals::UI::ZoomFieldOfView.Value : Vars::Visuals::UI::FieldOfView.Value; + if (!fov) + return; + + pView->fov = fov; + pLocal->m_iFOV() = fov; +} + +void CVisuals::ThirdPerson(CTFPlayer* pLocal, CViewSetup* pView) +{ + if (!pLocal->IsAlive()) + return I::Input->CAM_ToFirstPerson(); + + const bool bNoZoom = (!Vars::Visuals::Removals::Scope.Value || Vars::Visuals::UI::ZoomFieldOfView.Value < 70) && pLocal->IsScoped(); + const bool bForce = pLocal->IsTaunting() || pLocal->IsAGhost() || pLocal->IsInBumperKart() || pLocal->InCond(TF_COND_HALLOWEEN_THRILLER); + + //if (bForce) + // return; + + if (Vars::Visuals::ThirdPerson::Enabled.Value && !bNoZoom || bForce) + I::Input->CAM_ToThirdPerson(); + else + I::Input->CAM_ToFirstPerson(); + pLocal->ThirdPersonSwitch(); + + if (I::Input->CAM_IsThirdPerson()) + { // Thirdperson offset + Vec3 vForward, vRight, vUp; + Math::AngleVectors(pView->angles, &vForward, &vRight, &vUp); + + Vec3 offset; + offset += vRight * Vars::Visuals::ThirdPerson::Right.Value; + offset += vUp * Vars::Visuals::ThirdPerson::Up.Value; + offset -= vForward * Vars::Visuals::ThirdPerson::Distance.Value; + + const Vec3 viewDiff = pView->origin - pLocal->GetEyePosition(); + CGameTrace trace = {}; CTraceFilterWorldAndPropsOnly filter = {}; + SDK::TraceHull(pView->origin - viewDiff, pView->origin + offset - viewDiff, { -14.f, -14.f, -14.f }, { 14.f, 14.f, 14.f }, MASK_SOLID, &filter, &trace); + + pView->origin += offset * trace.fraction - viewDiff; + } +} + +bool CVisuals::RemoveScope(int nPanel) +{ + if (!Vars::Visuals::Removals::Scope.Value) + return false; + + if (!m_nHudZoom && FNV1A::Hash(I::VGuiPanel->GetName(nPanel)) == FNV1A::HashConst("HudScope")) + m_nHudZoom = nPanel; + + return nPanel == m_nHudZoom; +} + +void CVisuals::DrawSightlines() +{ + if (Vars::Visuals::UI::SniperSightlines.Value) + { + if (!m_SightLines.empty()) + { + for (const auto& sightline : m_SightLines) + { + if (sightline.m_bDraw) + RenderLine(sightline.m_vStart, sightline.m_vEnd, sightline.m_Color); + } + } + } +} + +void CVisuals::StoreSightlines() +{ + auto pLocal = H::Entities.GetLocal(); + if (Vars::Visuals::UI::SniperSightlines.Value && pLocal) + { + m_SightLines = {}; // should get rid of residual lines + + std::unordered_map mDots = {}; + for (auto pEntity : H::Entities.GetGroup(EGroupType::MISC_DOTS)) + { + if (auto pOwner = pEntity->m_hOwnerEntity().Get()) + mDots[pOwner] = pEntity->m_vecOrigin(); + } + + for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ENEMIES)) + { + auto pPlayer = pEntity->As(); + int iEntityIndex = pPlayer->entindex(); + auto pWeapon = pPlayer->m_hActiveWeapon().Get()->As(); + if (!pPlayer->IsAlive() || pPlayer->IsAGhost() || pPlayer->IsDormant() || !pPlayer->InCond(TF_COND_AIMING) || + !pWeapon || pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW || pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN) + { + continue; + } + + Vec3 vShootPos = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset(); + Vec3 vForward; Math::AngleVectors(pPlayer->GetEyeAngles(), &vForward); + Vec3 vShootEnd = mDots.contains(pPlayer) ? mDots[pPlayer] : vShootPos + (vForward * 8192.f); + + CTraceFilterHitscan filter{}; + CGameTrace trace{}; + filter.pSkip = pPlayer; + SDK::Trace(vShootPos, vShootEnd, MASK_SHOT, &filter, &trace); + + m_SightLines[pPlayer->entindex()] = { vShootPos, trace.endpos, H::Color.GetEntityDrawColor(pLocal, pPlayer, Vars::Colors::Relative.Value), true }; + } + } +} + +void CVisuals::PickupTimers() +{ + if (!Vars::Visuals::UI::PickupTimers.Value) + return; + + for (auto pickupData = PickupDatas.begin(); pickupData != PickupDatas.end();) + { + const float timeDiff = I::EngineClient->Time() - pickupData->Time; + if (timeDiff > 10.f) + { + pickupData = PickupDatas.erase(pickupData); + continue; + } + + auto timerText = std::format("{:.1f}s", 10.f - timeDiff); + auto color = pickupData->Type ? Vars::Colors::Health.Value : Vars::Colors::Ammo.Value; + + Vec3 vScreen; + if (SDK::W2S(pickupData->Location, vScreen)) + H::Draw.String(H::Fonts.GetFont(FONT_ESP), vScreen.x, vScreen.y, color, ALIGN_CENTER, timerText.c_str()); + + ++pickupData; + } +} + +// Credits go to reestart entirely +void CVisuals::ManualNetwork(const StartSoundParams_t& params) +{ + if (params.soundsource <= 0) + return; + + Vector vOrigin = params.origin; + const int iEntIndex = params.soundsource; + auto pEntity = I::ClientEntityList->GetClientEntity(iEntIndex); + + if (pEntity && iEntIndex != I::EngineClient->GetLocalPlayer() && pEntity->IsDormant() && pEntity->GetClassID() == ETFClassID::CTFPlayer) + G::DormancyMap[iEntIndex] = { vOrigin, I::EngineClient->Time() }; +} + + + +void CVisuals::OverrideWorldTextures() +{ + KeyValues* kv = nullptr; + + auto uHash = FNV1A::Hash(Vars::Visuals::World::WorldTexture.Value.c_str()); + if (uHash == FNV1A::HashConst("Default")) + return; + + kv = new KeyValues("LightmappedGeneric"); + if (uHash == FNV1A::HashConst("Dev")) + kv->SetString("$basetexture", "dev/dev_measuregeneric01b"); + else if (uHash == FNV1A::HashConst("Camo")) + kv->SetString("$basetexture", "patterns/paint_strokes"); + else if (uHash == FNV1A::HashConst("Black")) + kv->SetString("$basetexture", "patterns/combat/black"); + else if (uHash == FNV1A::HashConst("White")) + kv->SetString("$basetexture", "patterns/combat/white"); + else if (uHash == FNV1A::HashConst("Flat")) + { + kv->SetString("$basetexture", "vgui/white_additive"); + kv->SetString("$color2", "[0.12 0.12 0.15]"); + } + else + kv->SetString("$basetexture", Vars::Visuals::World::WorldTexture.Value.c_str()); + + if (!kv) + return; + + for (auto h = I::MaterialSystem->FirstMaterial(); h != I::MaterialSystem->InvalidMaterial(); h = I::MaterialSystem->NextMaterial(h)) + { + auto pMaterial = I::MaterialSystem->GetMaterial(h); + if (!pMaterial || pMaterial->IsErrorMaterial() || !pMaterial->IsPrecached() || pMaterial->IsTranslucent() || pMaterial->IsSpriteCard()) + continue; + + auto sGroup = std::string_view(pMaterial->GetTextureGroupName()); + auto sName = std::string_view(pMaterial->GetName()); + + if (!sGroup._Starts_with("World") + || sName.find("water") != std::string_view::npos || sName.find("glass") != std::string_view::npos + || sName.find("door") != std::string_view::npos || sName.find("tools") != std::string_view::npos + || sName.find("player") != std::string_view::npos || sName.find("chicken") != std::string_view::npos + || sName.find("wall28") != std::string_view::npos || sName.find("wall26") != std::string_view::npos + || sName.find("decal") != std::string_view::npos || sName.find("overlay") != std::string_view::npos + || sName.find("hay") != std::string_view::npos) + { + continue; + } + + pMaterial->SetShaderAndParams(kv); + } +} + +void ApplyModulation(const Color_t& clr, bool bSky = false) +{ + for (auto h = I::MaterialSystem->FirstMaterial(); h != I::MaterialSystem->InvalidMaterial(); h = I::MaterialSystem->NextMaterial(h)) + { + auto pMaterial = I::MaterialSystem->GetMaterial(h); + if (!pMaterial || pMaterial->IsErrorMaterial() || !pMaterial->IsPrecached()) + continue; + + auto sGroup = std::string_view(pMaterial->GetTextureGroupName()); + if (!bSky ? !sGroup._Starts_with("World") : !sGroup._Starts_with("SkyBox")) + continue; + + pMaterial->ColorModulate(float(clr.r) / 255.f, float(clr.g) / 255.f, float(clr.b) / 255.f); + } +} + +void CVisuals::Modulate() +{ + const bool bScreenshot = Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot(); + const bool bWorldModulation = Vars::Visuals::World::Modulations.Value & 1 << 0 && !bScreenshot; + const bool bSkyModulation = Vars::Visuals::World::Modulations.Value & 1 << 1 && !bScreenshot; + + static bool bLastConnectionState = I::EngineClient->IsConnected() && I::EngineClient->IsInGame(); + const bool bCurrConnectionState = I::EngineClient->IsConnected() && I::EngineClient->IsInGame(); + const bool bUnchanged = bLastConnectionState == bCurrConnectionState; + + bool bSetChanged, bColorChanged, bSkyChanged; + { + static auto oldW = bWorldModulation; + const auto curW = bWorldModulation; + static auto oldS = bSkyModulation; + const auto curS = bSkyModulation; + + bSetChanged = curS != oldS || curW != oldW; + + oldW = curW; + oldS = curS; + } + { + static auto oldW = Vars::Colors::WorldModulation.Value; + static auto oldS = Vars::Colors::SkyModulation.Value; + const auto curW = Vars::Colors::WorldModulation.Value; + const auto curS = Vars::Colors::SkyModulation.Value; + + bColorChanged = curW != oldW || curS != oldS; + + oldW = curW; + oldS = curS; + } + { + static auto oldS = Vars::Visuals::World::SkyboxChanger.Value; + const auto curS = Vars::Visuals::World::SkyboxChanger.Value; + + bSkyChanged = curS != oldS; + + oldS = curS; + } + + if (bSetChanged || bColorChanged || bSkyChanged || !bUnchanged) + { + bWorldModulation ? ApplyModulation(Vars::Colors::WorldModulation.Value) : ApplyModulation({ 255, 255, 255, 255 }); + bSkyModulation ? ApplyModulation(Vars::Colors::SkyModulation.Value, true) : ApplyModulation({ 255, 255, 255, 255 }, true); + bLastConnectionState = bCurrConnectionState; + } +} + +void CVisuals::RestoreWorldModulation() // keep this because its mentioned in @DLLMain.cpp if you find a better way to do this, remove it ig. +{ + ApplyModulation({ 255, 255, 255, 255 }); + ApplyModulation({ 255, 255, 255, 255 }, true); +} + +void CVisuals::SkyboxChanger() +{ + using LoadNamedSkysFn = bool(_cdecl*)(const char*); + static auto fnLoadSkys = S::LoadSkys.As(); + const bool bScreenshot = Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot(); + + static auto sv_skyname = U::ConVars.FindVar("sv_skyname"); + if (FNV1A::Hash(Vars::Visuals::World::SkyboxChanger.Value.c_str()) != FNV1A::HashConst("Off") && !bScreenshot) + fnLoadSkys(Vars::Visuals::World::SkyboxChanger.Value.c_str()); + else if (sv_skyname) + fnLoadSkys(sv_skyname->GetString()); +} \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/Visuals.h b/Amalgam/src/Features/Visuals/Visuals.h new file mode 100644 index 0000000..ddb08f3 --- /dev/null +++ b/Amalgam/src/Features/Visuals/Visuals.h @@ -0,0 +1,83 @@ +#pragma once +#include "../../SDK/SDK.h" + +#include + +struct Sightline_t +{ + Vec3 m_vStart = { 0,0,0 }; + Vec3 m_vEnd = { 0,0,0 }; + Color_t m_Color = { 0,0,0,0 }; + bool m_bDraw = false; +}; + +class CVisuals +{ +private: + int m_nHudZoom = 0; + +public: + void DrawAimbotFOV(CTFPlayer* pLocal); + void DrawTickbaseText(CTFPlayer* pLocal); + void DrawTickbaseBars(); + void DrawOnScreenPing(CTFPlayer* pLocal); + void DrawOnScreenConditions(CTFPlayer* pLocal); + void DrawSeedPrediction(CTFPlayer* pLocal); + void ProjectileTrace(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const bool bQuick = true); + void DrawAntiAim(CTFPlayer* pLocal); + void DrawDebugInfo(CTFPlayer* pLocal); + + std::vector GetHitboxes(matrix3x4 bones[128], CBaseAnimating* pEntity, const int iHitbox = -1); + void DrawBulletLines(); + void DrawSimLine(std::deque>& Line, Color_t Color, bool bSeparators = false, bool bZBuffer = false, float flTime = 0.f); + void DrawSimLines(); + void DrawBoxes(); + void RevealSimLines(); + void RevealBulletLines(); + void RevealBoxes(); + void DrawServerHitboxes(CTFPlayer* pLocal); + void RenderLine(const Vec3& vStart, const Vec3& vEnd, Color_t cLine, bool bZBuffer = false); + void RenderBox(const Vec3& vPos, const Vec3& vMins, const Vec3& vMaxs, const Vec3& vOrientation, Color_t cEdge, Color_t cFace, bool bZBuffer = false); + + void FOV(CTFPlayer* pLocal, CViewSetup* pView); + void ThirdPerson(CTFPlayer* pLocal, CViewSetup* pView); + bool RemoveScope(int nPanel); + void DrawSightlines(); + void StoreSightlines(); + void PickupTimers(); + void ManualNetwork(const StartSoundParams_t& params); // Credits: reestart + + std::array m_SightLines; + + struct PickupData + { + int Type = 0; + float Time = 0.f; + Vec3 Location; + }; + std::vector PickupDatas; + + void OverrideWorldTextures(); + void Modulate(); + void SkyboxChanger(); + void RestoreWorldModulation(); + + struct MaterialHandleData + { + enum class EMatGroupType + { + GROUP_OTHER, + GROUP_WORLD, + GROUP_SKY + }; + + MaterialHandle_t Handle; + IMaterial* Material; + std::string_view Group; + std::string_view Name; + EMatGroupType GroupType; + bool ShouldOverrideTextures; + }; +}; + +ADD_FEATURE(CVisuals, Visuals) \ No newline at end of file diff --git a/Amalgam/src/Hooks/BaseClientDLL_DispatchUserMessage.cpp b/Amalgam/src/Hooks/BaseClientDLL_DispatchUserMessage.cpp new file mode 100644 index 0000000..a53a4aa --- /dev/null +++ b/Amalgam/src/Hooks/BaseClientDLL_DispatchUserMessage.cpp @@ -0,0 +1,87 @@ +#include "../SDK/SDK.h" + +#include "../Features/Misc/Misc.h" +#include "../Features/Logs/Logs.h" +#include "../Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h" +#include +#include + +MAKE_HOOK(BaseClientDLL_DispatchUserMessage, U::Memory.GetVFunc(I::BaseClientDLL, 36), bool, __fastcall, + void* ecx, UserMessageType type, bf_read& msgData) +{ + const auto bufData = reinterpret_cast(msgData.m_pData); + msgData.SetAssertOnOverflow(false); + msgData.Seek(0); + + switch (type) + { + case VoteStart: + F::Logs.UserMessage(msgData); + + break; + /* + case VoiceSubtitle: + { + int iEntityID = msgData.ReadByte(); + int iVoiceMenu = msgData.ReadByte(); + int iCommandID = msgData.ReadByte(); + + if (iVoiceMenu == 1 && iCommandID == 6) + F::...mMedicCallers.push_back(iEntityID); + + break; + } + */ + case TextMsg: + if (F::NoSpreadHitscan.ParsePlayerPerf(msgData)) + return true; + + if (Vars::Misc::Automation::AntiAutobalance.Value && msgData.GetNumBitsLeft() > 35) + { + static int anti_balance_attempts = 0; + static std::string previous_name; + + auto pNetChan = I::EngineClient->GetNetChannelInfo(); + const std::string data(bufData); + + if (data.find("TeamChangeP") != std::string::npos && H::Entities.GetLocal()) + { + const std::string serverName = pNetChan->GetAddress(); + if (serverName != previous_name) + { + previous_name = serverName; + anti_balance_attempts = 0; + } + if (anti_balance_attempts < 2) + I::EngineClient->ClientCmd_Unrestricted("retry"); + anti_balance_attempts++; + } + } + break; + case VGUIMenu: + if (Vars::Visuals::Removals::MOTD.Value) + { + if (strcmp(reinterpret_cast(msgData.m_pData), "info") == 0) + { + I::EngineClient->ClientCmd_Unrestricted("closedwelcomemenu"); + return true; + } + } + + break; + case ForcePlayerViewAngles: + return Vars::Visuals::Removals::AngleForcing.Value ? true : CALL_ORIGINAL(ecx, type, msgData); + case SpawnFlyingBird: + case PlayerGodRayEffect: + case PlayerTauntSoundLoopStart: + case PlayerTauntSoundLoopEnd: + return Vars::Visuals::Removals::Taunts.Value ? true : CALL_ORIGINAL(ecx, type, msgData); + case Shake: + case Fade: + case Rumble: + return Vars::Visuals::Removals::ScreenEffects.Value ? true : CALL_ORIGINAL(ecx, type, msgData); + } + + msgData.Seek(0); + return CALL_ORIGINAL(ecx, type, msgData); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/BaseClientDLL_FrameStageNotify.cpp b/Amalgam/src/Hooks/BaseClientDLL_FrameStageNotify.cpp new file mode 100644 index 0000000..bae7632 --- /dev/null +++ b/Amalgam/src/Hooks/BaseClientDLL_FrameStageNotify.cpp @@ -0,0 +1,80 @@ +#include "../SDK/SDK.h" + +#include "../Features/Backtrack/Backtrack.h" +#include "../Features/CheaterDetection/CheaterDetection.h" +#include "../Features/CritHack/CritHack.h" +#include "../Features/Misc/Misc.h" +#include "../Features/Players/PlayerUtils.h" +#include "../Features/Resolver/Resolver.h" +#include "../Features/Simulation/MovementSimulation/MovementSimulation.h" +#include "../Features/Visuals/Visuals.h" + +MAKE_HOOK(BaseClientDLL_FrameStageNotify, U::Memory.GetVFunc(I::BaseClientDLL, 35), void, __fastcall, + void* ecx, ClientFrameStage_t curStage) +{ + switch (curStage) + { + case FRAME_RENDER_START: + G::PunchAngles = Vec3(); + if (auto pLocal = H::Entities.GetLocal()) + { + G::PunchAngles = pLocal->m_vecPunchAngle(); // use in aimbot + if (Vars::Visuals::Removals::ViewPunch.Value) + pLocal->m_vecPunchAngle() = Vec3(); // visual no-recoil + F::Resolver.FrameStageNotify(pLocal); + // CRASH: Exception thrown at 0x00007FFCD004E223 (client.dll) in tf_win64.exe: 0xC0000005: Access violation reading location 0x0000025800000000. + // CRASH: Exception thrown at 0x00007FFC5A09EED0 (client.dll) in tf_win64.exe: 0xC0000005: Access violation reading location 0x000001F636472562. + // crashes likely not fsn related + } + } + + CALL_ORIGINAL(ecx, curStage); + + switch (curStage) + { + case FRAME_NET_UPDATE_START: + H::Entities.Clear(); + break; + case FRAME_NET_UPDATE_END: + H::Entities.Fill(); + for (auto& pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_ALL)) + { + G::VelocityMap[pEntity->entindex()] = { pEntity->m_vecOrigin(), pEntity->m_vecMaxs().z - pEntity->m_vecMins().z, pEntity->m_flSimulationTime() }; + + if (pEntity->entindex() == I::EngineClient->GetLocalPlayer()) + continue; // local player managed in CPrediction_RunCommand + + static auto sv_maxusrcmdprocessticks = U::ConVars.FindVar("sv_maxusrcmdprocessticks"); + const int iTicks = sv_maxusrcmdprocessticks ? sv_maxusrcmdprocessticks->GetInt() : 24; + if (auto iDifference = std::min(TIME_TO_TICKS(pEntity->m_flSimulationTime() - pEntity->m_flOldSimulationTime()), iTicks)) + { + float flOldFrameTime = I::GlobalVars->frametime; + I::GlobalVars->frametime = I::Prediction->m_bEnginePaused ? 0.f : TICK_INTERVAL; + for (int i = 0; i < iDifference; i++) + { + G::UpdatingAnims = true; + pEntity->As()->UpdateClientSideAnimation(); + G::UpdatingAnims = false; + } + I::GlobalVars->frametime = flOldFrameTime; + } + } + + F::PlayerUtils.UpdatePlayers(); + F::Misc.DetectChoke(); + + F::Backtrack.FrameStageNotify(); + F::MoveSim.FillVelocities(); + F::CritHack.Store(); + F::Visuals.StoreSightlines(); + + F::CheaterDetection.Fill(); // maybe switch this to run instead + + break; + case FRAME_RENDER_START: + if (G::Unload) + break; + F::Visuals.SkyboxChanger(); + F::Visuals.Modulate(); + } +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/BaseClientDLL_Shutdown.cpp b/Amalgam/src/Hooks/BaseClientDLL_Shutdown.cpp new file mode 100644 index 0000000..43e755a --- /dev/null +++ b/Amalgam/src/Hooks/BaseClientDLL_Shutdown.cpp @@ -0,0 +1,13 @@ +#include "../SDK/SDK.h" + +#include "../Features/Misc/Misc.h" + +MAKE_HOOK(BaseClientDLL_Shutdown, U::Memory.GetVFunc(I::BaseClientDLL, 7), void, __fastcall, + void* ecx) +{ + H::Entities.Clear(); + G::DormancyMap.clear(); + G::ChokeMap.clear(); + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CAchievementMgr_CheckAchievementsEnabled.cpp b/Amalgam/src/Hooks/CAchievementMgr_CheckAchievementsEnabled.cpp new file mode 100644 index 0000000..1432573 --- /dev/null +++ b/Amalgam/src/Hooks/CAchievementMgr_CheckAchievementsEnabled.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CAchievementMgr_CheckAchievementsEnabled, "client.dll", "40 53 48 83 EC ? 48 8B 05 ? ? ? ? 48 8B D9 48 8B 48 ? 48 85 C9 0F 84", 0x0); + +MAKE_HOOK(CAchievementMgr_CheckAchievementsEnabled, S::CAchievementMgr_CheckAchievementsEnabled(), bool, __fastcall, + void* ecx) +{ + return true; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseAnimating_FrameAdvance.cpp b/Amalgam/src/Hooks/CBaseAnimating_FrameAdvance.cpp new file mode 100644 index 0000000..52c8504 --- /dev/null +++ b/Amalgam/src/Hooks/CBaseAnimating_FrameAdvance.cpp @@ -0,0 +1,23 @@ +#include "../SDK/SDK.h" + +std::unordered_map> pAnimatingInfo; + +MAKE_HOOK(C_BaseAnimating_FrameAdvance, S::CBaseAnimating_FrameAdvance(), float, __fastcall, + void* ecx, float flInterval) +{ + if (!Vars::Visuals::Removals::Interpolation.Value || ecx == H::Entities.GetLocal()) + return CALL_ORIGINAL(ecx, flInterval); + + const auto pEntity = static_cast(ecx); + if (pEntity && pEntity->IsPlayer()) + { + if (pEntity->m_flSimulationTime() == pEntity->m_flOldSimulationTime() || I::GlobalVars->tickcount == pAnimatingInfo[ecx].first) + { + pAnimatingInfo[ecx].second += flInterval; + return 0.f; + } + } + + flInterval = pAnimatingInfo[ecx].second; pAnimatingInfo[ecx].second = 0.f; pAnimatingInfo[ecx].first = I::GlobalVars->tickcount; + return CALL_ORIGINAL(ecx, flInterval); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseAnimating_Interpolate.cpp b/Amalgam/src/Hooks/CBaseAnimating_Interpolate.cpp new file mode 100644 index 0000000..d509fee --- /dev/null +++ b/Amalgam/src/Hooks/CBaseAnimating_Interpolate.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBaseAnimating_Interpolate, "client.dll", "48 8B C4 48 89 70 ? F3 0F 11 48", 0x0); + +MAKE_HOOK(C_BaseAnimating_Interpolate, S::CBaseAnimating_Interpolate(), bool, __fastcall, + void* ecx, float currentTime) +{ + if (ecx == H::Entities.GetLocal() ? G::Recharge : Vars::Visuals::Removals::Interpolation.Value) + return true; + + return CALL_ORIGINAL(ecx, currentTime); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseAnimating_MaintainSequenceTransitions.cpp b/Amalgam/src/Hooks/CBaseAnimating_MaintainSequenceTransitions.cpp new file mode 100644 index 0000000..06b728b --- /dev/null +++ b/Amalgam/src/Hooks/CBaseAnimating_MaintainSequenceTransitions.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBaseAnimating_MaintainSequenceTransitions, "client.dll", "4C 89 4C 24 ? 41 56", 0x0); + +MAKE_HOOK(C_BaseAnimating_MaintainSequenceTransitions, S::CBaseAnimating_MaintainSequenceTransitions(), void, __fastcall, + void* ecx, void* boneSetup, float flCycle, Vec3 pos[], Vector4D q[]) +{ + return; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseAnimating_SetupBones.cpp b/Amalgam/src/Hooks/CBaseAnimating_SetupBones.cpp new file mode 100644 index 0000000..83d486b --- /dev/null +++ b/Amalgam/src/Hooks/CBaseAnimating_SetupBones.cpp @@ -0,0 +1,51 @@ +#include "../SDK/SDK.h" + +#include "../Features/Backtrack/Backtrack.h" + +MAKE_SIGNATURE(CBaseAnimating_SetupBones, "client.dll", "48 8B C4 44 89 40 ? 48 89 50 ? 55 53", 0x0); + +MAKE_HOOK(CBaseAnimating_SetupBones, S::CBaseAnimating_SetupBones(), bool, __fastcall, + void* ecx, matrix3x4* pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime) +{ + if (Vars::Misc::Game::SetupBonesOptimization.Value && !F::Backtrack.bSettingUpBones) + { + auto pBaseEntity = reinterpret_cast(std::uintptr_t(ecx) - 8); + if (pBaseEntity) + { + auto GetRootMoveParent = [&]() + { + auto pEntity = pBaseEntity; + auto pParent = pBaseEntity->GetMoveParent(); + + int i = 0; + while (pParent) + { + if (i > 32) //XD + break; + i++; + + pEntity = pParent; + pParent = pEntity->GetMoveParent(); + } + + return pEntity; + }; + + auto pOwner = GetRootMoveParent(); + auto pEntity = pOwner ? pOwner : pBaseEntity; + if (pEntity->GetClassID() == ETFClassID::CTFPlayer && pEntity != H::Entities.GetLocal()) + { + if (pBoneToWorldOut) + { + auto bones = pEntity->As()->GetCachedBoneData(); + if (bones) + std::memcpy(pBoneToWorldOut, bones->Base(), sizeof(matrix3x4) * std::min(nMaxBones, bones->Count())); + } + + return true; + } + } + } + + return CALL_ORIGINAL(ecx, pBoneToWorldOut, nMaxBones, boneMask, currentTime); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseAnimating_UpdateClientSideAnimations.cpp b/Amalgam/src/Hooks/CBaseAnimating_UpdateClientSideAnimations.cpp new file mode 100644 index 0000000..6ede28e --- /dev/null +++ b/Amalgam/src/Hooks/CBaseAnimating_UpdateClientSideAnimations.cpp @@ -0,0 +1,15 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBaseAnimating_UpdateClientSideAnimation, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B D9 E8 ? ? ? ? 48 8B F8 48 85 C0 74 ? 48 8B 00 48 8B CF FF 90 ? ? ? ? 84 C0 75 ? 33 FF 48 3B DF", 0x0); + +MAKE_HOOK(CBaseAnimating_UpdateClientSideAnimation, S::CBaseAnimating_UpdateClientSideAnimation(), void, __fastcall, + void* ecx) +{ + auto pLocal = H::Entities.GetLocal(); + if (!G::UpdatingAnims && (ecx && ecx == pLocal ? !pLocal->IsInBumperKart() : true)) + return; + + G::AnimateKart = true; + CALL_ORIGINAL(ecx); + G::AnimateKart = false; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseClient_Connect.cpp b/Amalgam/src/Hooks/CBaseClient_Connect.cpp new file mode 100644 index 0000000..01a581b --- /dev/null +++ b/Amalgam/src/Hooks/CBaseClient_Connect.cpp @@ -0,0 +1,13 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Materials/Materials.h" + +MAKE_SIGNATURE(CBaseClient_Connect, "engine.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B D9 49 8B E9 48 8D 0D", 0x0); + +MAKE_HOOK(CBaseClient_Connect, S::CBaseClient_Connect(), void, __fastcall, + void* ecx, const char* szName, int nUserID, INetChannel* pNetChannel, bool bFakePlayer, int clientChallenge) +{ + F::Materials.ReloadMaterials(); + + CALL_ORIGINAL(ecx, szName, nUserID, pNetChannel, bFakePlayer, clientChallenge); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseClient_Disconnect.cpp b/Amalgam/src/Hooks/CBaseClient_Disconnect.cpp new file mode 100644 index 0000000..d080719 --- /dev/null +++ b/Amalgam/src/Hooks/CBaseClient_Disconnect.cpp @@ -0,0 +1,13 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Materials/Materials.h" + +MAKE_SIGNATURE(CBaseClient_Disconnect, "engine.dll", "48 8B C4 48 89 50 ? 4C 89 40 ? 4C 89 48 ? 57 48 81 EC ? ? ? ? 83 B9 ? ? ? ? ? 48 8B F9 0F 84 ? ? ? ? 48 89 58", 0x0); + +MAKE_HOOK(CBaseClient_Disconnect, S::CBaseClient_Disconnect(), void, __fastcall, + void* ecx, const char* fmt, ...) +{ + F::Materials.UnloadMaterials(); + + CALL_ORIGINAL(ecx, fmt); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseEntity_FireBullets.cpp b/Amalgam/src/Hooks/CBaseEntity_FireBullets.cpp new file mode 100644 index 0000000..d7852b6 --- /dev/null +++ b/Amalgam/src/Hooks/CBaseEntity_FireBullets.cpp @@ -0,0 +1,94 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Visuals.h" + +MAKE_SIGNATURE(CBaseEntity_FireBullets, "client.dll", "48 89 74 24 ? 55 57 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? F3 41 0F 10 58", 0x0); + +MAKE_HOOK(CBaseEntity_FireBullets, S::CBaseEntity_FireBullets(), void, __fastcall, + void* ecx, CBaseCombatWeapon* pWeapon, const FireBulletsInfo_t& info, bool bDoEffects, int nDamageType, int nCustomDamageType) +{ + auto pLocal = H::Entities.GetLocal(); + auto pPlayer = reinterpret_cast(ecx); + if (!pLocal || pPlayer != pLocal) + return CALL_ORIGINAL(ecx, pWeapon, info, bDoEffects, nDamageType, nCustomDamageType); + + const Vec3 vStart = info.m_vecSrc; + const Vec3 vEnd = vStart + info.m_vecDirShooting * info.m_flDistance; + CGameTrace trace = {}; + CTraceFilterHitscan filter = {}; + filter.pSkip = pLocal; + SDK::Trace(vStart, vEnd, MASK_SHOT | CONTENTS_GRATE, &filter, &trace); + + const int iAttachment = pWeapon->LookupAttachment("muzzle"); + pWeapon->GetAttachment(iAttachment, trace.startpos); + + const bool bCrit = nDamageType & DMG_CRITICAL || pLocal->IsCritBoosted(); + const int iTeam = pLocal->m_iTeamNum(); + + auto& sString = bCrit ? Vars::Visuals::Tracers::ParticleTracerCrits.Value : Vars::Visuals::Tracers::ParticleTracer.Value; + auto uHash = FNV1A::Hash(sString.c_str()); + if (!pLocal->IsInValidTeam() || uHash == FNV1A::HashConst("Off") || uHash == FNV1A::HashConst("Default")) + CALL_ORIGINAL(ecx, pWeapon, info, bDoEffects, nDamageType, nCustomDamageType); + else if (uHash == FNV1A::HashConst("Machina")) + H::Particles.ParticleTracer(iTeam == TF_TEAM_RED ? "dxhr_sniper_rail_red" : "dxhr_sniper_rail_blue", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("C.A.P.P.E.R")) + H::Particles.ParticleTracer(iTeam == TF_TEAM_RED ? "bullet_tracer_raygun_red" : "bullet_tracer_raygun_blue", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Short Circuit")) + H::Particles.ParticleTracer(iTeam == TF_TEAM_RED ? "dxhr_lightningball_hit_zap_red" : "dxhr_lightningball_hit_zap_blue", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Merasmus ZAP")) + H::Particles.ParticleTracer("merasmus_zap", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Merasmus ZAP 2")) + H::Particles.ParticleTracer("merasmus_zap_beam02", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Big Nasty")) + H::Particles.ParticleTracer(iTeam == TF_TEAM_RED ? "bullet_bignasty_tracer01_blue" : "bullet_bignasty_tracer01_red", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Distortion Trail")) + H::Particles.ParticleTracer("tfc_sniper_distortion_trail", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Black Ink")) + H::Particles.ParticleTracer("merasmus_zap_beam01", trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); + else if (uHash == FNV1A::HashConst("Line")) + { + bool bClear = false; + for (auto& Line : G::BulletsStorage) + { + if (I::GlobalVars->curtime - (Line.m_flTime - 5.f) > 0) + { + bClear = true; + break; + } + } + if (bClear) + G::BulletsStorage.clear(); + + G::BulletsStorage.push_back({ {trace.startpos, trace.endpos}, I::GlobalVars->curtime + 5.f, Vars::Colors::BulletTracer.Value, true }); + } + else if (uHash == FNV1A::HashConst("Beam")) + { + BeamInfo_t beamInfo; + beamInfo.m_nType = 0; + beamInfo.m_pszModelName = FNV1A::Hash(Vars::Visuals::Beams::Model.Value.c_str()) != FNV1A::HashConst("") ? Vars::Visuals::Beams::Model.Value.c_str() : "sprites/physbeam.vmt"; + beamInfo.m_nModelIndex = -1; // will be set by CreateBeamPoints if its -1 + beamInfo.m_flHaloScale = 0.0f; + beamInfo.m_flLife = Vars::Visuals::Beams::Life.Value; + beamInfo.m_flWidth = Vars::Visuals::Beams::Width.Value; + beamInfo.m_flEndWidth = Vars::Visuals::Beams::EndWidth.Value; + beamInfo.m_flFadeLength = Vars::Visuals::Beams::FadeLength.Value; + beamInfo.m_flAmplitude = Vars::Visuals::Beams::Amplitude.Value; + beamInfo.m_flBrightness = Vars::Visuals::Beams::Brightness.Value; + beamInfo.m_flSpeed = Vars::Visuals::Beams::Speed.Value; + beamInfo.m_nStartFrame = 0; + beamInfo.m_flFrameRate = 0; + beamInfo.m_flRed = Vars::Visuals::Beams::BeamColor.Value.r; + beamInfo.m_flGreen = Vars::Visuals::Beams::BeamColor.Value.g; + beamInfo.m_flBlue = Vars::Visuals::Beams::BeamColor.Value.b; + beamInfo.m_nSegments = Vars::Visuals::Beams::Segments.Value; + beamInfo.m_bRenderable = true; + beamInfo.m_nFlags = Vars::Visuals::Beams::Flags.Value; + beamInfo.m_vecStart = trace.startpos; + beamInfo.m_vecEnd = trace.endpos; + + if (auto pBeam = I::ViewRenderBeams->CreateBeamPoints(beamInfo)) + I::ViewRenderBeams->DrawBeam(pBeam); + } + else + H::Particles.ParticleTracer(sString.c_str(), trace.startpos, trace.endpos, pLocal->entindex(), iAttachment, true); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseEntity_Interpolate.cpp b/Amalgam/src/Hooks/CBaseEntity_Interpolate.cpp new file mode 100644 index 0000000..7df9ac3 --- /dev/null +++ b/Amalgam/src/Hooks/CBaseEntity_Interpolate.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBaseEntity_Interpolate, "client.dll", "4C 8B DC 49 89 5B ? F3 0F 11 4C 24", 0x0); + +MAKE_HOOK(CBaseEntity_Interpolate, S::CBaseEntity_Interpolate(), bool, __fastcall, + void* ecx, float currentTime) +{ + return !Vars::Visuals::Removals::Interpolation.Value ? CALL_ORIGINAL(ecx, currentTime) : true; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseEntity_InterpolateServerEntities.cpp b/Amalgam/src/Hooks/CBaseEntity_InterpolateServerEntities.cpp new file mode 100644 index 0000000..5565cbd --- /dev/null +++ b/Amalgam/src/Hooks/CBaseEntity_InterpolateServerEntities.cpp @@ -0,0 +1,15 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBaseEntity_InterpolateServerEntities, "client.dll", "4C 8B DC 41 54 41 55 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 45 33 ED 49 89 5B ? 48 8D 1D", 0x0); + +MAKE_HOOK(CBaseEntity_InterpolateServerEntities, S::CBaseEntity_InterpolateServerEntities(), void, __fastcall, + void* ecx) +{ + if (auto pLocal = H::Entities.GetLocal()) + { + if (G::Recharge && !I::Input->CAM_IsThirdPerson() && pLocal->IsAlive()) + return; + } + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseEntity_ResetLatched.cpp b/Amalgam/src/Hooks/CBaseEntity_ResetLatched.cpp new file mode 100644 index 0000000..be6b8df --- /dev/null +++ b/Amalgam/src/Hooks/CBaseEntity_ResetLatched.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBaseEntity_ResetLatched, "client.dll", "40 56 48 83 EC ? 48 8B 01 48 8B F1 FF 90 ? ? ? ? 84 C0 75", 0x0); + +MAKE_HOOK(CBaseEntity_ResetLatched, S::CBaseEntity_ResetLatched(), void, __fastcall, + void* ecx) +{ + if (Vars::Misc::Game::PredictionErrorJitterFix.Value) + return; + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseEntity_SetAbsVelocity.cpp b/Amalgam/src/Hooks/CBaseEntity_SetAbsVelocity.cpp new file mode 100644 index 0000000..cadf00c --- /dev/null +++ b/Amalgam/src/Hooks/CBaseEntity_SetAbsVelocity.cpp @@ -0,0 +1,36 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBasePlayer_PostDataUpdate_Call, "client.dll", "E8 ? ? ? ? 0F 28 74 24 ? 8B D6", 0x5); + +MAKE_HOOK(CBaseEntity_SetAbsVelocity, S::CBaseEntity_SetAbsVelocity(), void, __fastcall, + void* ecx, const Vec3& vecAbsVelocity) +{ + static const auto dwDesired = S::CBasePlayer_PostDataUpdate_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (dwRetAddr == dwDesired) + { + const auto pPlayer = static_cast(ecx); + if (pPlayer && G::VelocityMap.contains(pPlayer->entindex())) + { + const auto newRecord = VelFixRecord(pPlayer->m_vecOrigin(), pPlayer->m_vecMaxs().z - pPlayer->m_vecMins().z, pPlayer->m_flSimulationTime()); + const auto& oldRecord = G::VelocityMap[pPlayer->entindex()]; + + const float flDelta = newRecord.m_flSimulationTime - oldRecord.m_flSimulationTime; + const Vec3 vDelta = newRecord.m_vecOrigin - oldRecord.m_vecOrigin; + + static auto sv_lagcompensation_teleport_dist = U::ConVars.FindVar("sv_lagcompensation_teleport_dist"); + const float flDist = powf(sv_lagcompensation_teleport_dist ? sv_lagcompensation_teleport_dist->GetFloat() : 64.f, 2.f) * TIME_TO_TICKS(flDelta); + if (flDelta > 0.f && vDelta.Length2DSqr() < flDist) + { + Vec3 vOldOrigin = oldRecord.m_vecOrigin; + if (!pPlayer->IsOnGround()) + vOldOrigin.z += oldRecord.m_flHeight - newRecord.m_flHeight; + CALL_ORIGINAL(ecx, (newRecord.m_vecOrigin - vOldOrigin) / flDelta); + } + return; + } + } + + CALL_ORIGINAL(ecx, vecAbsVelocity); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBaseHudChat_ChatPrintf.cpp b/Amalgam/src/Hooks/CBaseHudChat_ChatPrintf.cpp new file mode 100644 index 0000000..b121d62 --- /dev/null +++ b/Amalgam/src/Hooks/CBaseHudChat_ChatPrintf.cpp @@ -0,0 +1,55 @@ +#include "../SDK/SDK.h" + +#include "../Features/Players/PlayerUtils.h" + +MAKE_HOOK(CBaseHudChat_ChatPrintf, U::Memory.GetVFunc(I::ClientModeShared->m_pChatElement, 19), void, __fastcall, + void* ecx, int iPlayerIndex, int iFilter, const char* fmt, ...) +{ + va_list marker; + char buffer[4096]; + va_start(marker, fmt); + vsnprintf_s(buffer, sizeof(buffer), fmt, marker); + va_end(marker); + + if (strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == '\n') + buffer[strlen(buffer) - 1] = 0; + char* msg = buffer; + while (*msg && (*msg == '\n' || *msg == '\r' || *msg == '\x1A')) + msg++; + if (!*msg) + return; + + std::string finalMsg = msg, name = {}; + + PlayerInfo_t pi{}; + if (!I::EngineClient->GetPlayerInfo(iPlayerIndex, &pi)) + return CALL_ORIGINAL(ecx, iPlayerIndex, iFilter, "%s", finalMsg.c_str()); + + name = pi.name; + if (finalMsg.find(name) == std::string::npos) + return CALL_ORIGINAL(ecx, iPlayerIndex, iFilter, "%s", finalMsg.c_str()); + + if (iPlayerIndex && Vars::Misc::Chat::Tags.Value) + { + std::string tag = "", color = ""; + if (iPlayerIndex == I::EngineClient->GetLocalPlayer()) + tag = "You", color = Vars::Colors::Local.Value.ToHexA(); + else if (H::Entities.IsFriend(iPlayerIndex)) + tag = "Friend", color = F::PlayerUtils.mTags["Friend"].Color.ToHexA(); + else + { + std::string sTag; PriorityLabel_t plTag; + if (F::PlayerUtils.GetSignificantTag(pi.friendsID, &sTag, &plTag, 0)) + tag = sTag, color = plTag.Color.ToHexA(); + } + + if (tag.length()) + { + finalMsg = std::format("{}[{}] \x3{}", color, tag, finalMsg); + if (auto offset = finalMsg.find(name)) + finalMsg = finalMsg.replace(offset + name.length(), 0, "\x1"); + } + } + + CALL_ORIGINAL(ecx, iPlayerIndex, iFilter, "%s", finalMsg.c_str()); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CBasePlayer_CalcViewModelView.cpp b/Amalgam/src/Hooks/CBasePlayer_CalcViewModelView.cpp new file mode 100644 index 0000000..5410230 --- /dev/null +++ b/Amalgam/src/Hooks/CBasePlayer_CalcViewModelView.cpp @@ -0,0 +1,60 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CBasePlayer_CalcViewModelView, "client.dll", "48 89 74 24 ? 55 41 56 41 57 48 8D AC 24", 0x0); + +MAKE_HOOK(C_BasePlayer_CalcViewModelView, S::CBasePlayer_CalcViewModelView(), void, __fastcall, + void* ecx, CBaseEntity* pOwner, const Vec3& vEyePosition, Vec3& vEyeAngles) +{ + Vec3 vOffset = { float(Vars::Visuals::Viewmodel::OffsetX.Value), float(Vars::Visuals::Viewmodel::OffsetY.Value), float(Vars::Visuals::Viewmodel::OffsetZ.Value) }; + bool bOffset = !vOffset.IsZero(); + + if (!Vars::Visuals::Viewmodel::ViewmodelAim.Value && !bOffset && !Vars::Visuals::Viewmodel::Roll.Value + || Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + return CALL_ORIGINAL(ecx, pOwner, vEyePosition, vEyeAngles); + + bool bFlip = false; + { + static auto cl_flipviewmodels = U::ConVars.FindVar("cl_flipviewmodels"); + if (cl_flipviewmodels ? cl_flipviewmodels->GetBool() : false) + bFlip = !bFlip; + auto pWeapon = H::Entities.GetWeapon(); + if (pWeapon && pWeapon->m_iWeaponID() == TF_WEAPON_COMPOUND_BOW) + bFlip = !bFlip; + } + + if (Vars::Visuals::Viewmodel::ViewmodelAim.Value) + { + auto pLocal = H::Entities.GetLocal(); + if (pLocal && pLocal->IsAlive()) + { + static Vec3 vAng = {}; + static int iTick = 0; + + if (!G::AimPosition.IsZero()) + { + vAng = Math::CalcAngle(vEyePosition, G::AimPosition); + iTick = I::GlobalVars->tickcount; + } + + if (abs(iTick - I::GlobalVars->tickcount) < 32) + { + Vec3 vDiff = I::EngineClient->GetViewAngles() - vAng; + if (bFlip) + vDiff.y *= -1; + vEyeAngles = I::EngineClient->GetViewAngles() - vDiff; + } + } + } + + Vec3 vNewEyePosition = vEyePosition; + if (bOffset) + { + Vec3 vForward = {}, vRight = {}, vUp = {}; + Math::AngleVectors(vEyeAngles, &vForward, &vRight, &vUp); + vNewEyePosition += (vRight * vOffset.x * (bFlip ? -1 : 1)) + (vForward * vOffset.y) + (vUp * vOffset.z); + } + if (Vars::Visuals::Viewmodel::Roll.Value) + vEyeAngles.z += Vars::Visuals::Viewmodel::Roll.Value * (bFlip ? -1 : 1); + + CALL_ORIGINAL(ecx, pOwner, vNewEyePosition, vEyeAngles); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CEconItemSchema_GetItemDefinition.cpp b/Amalgam/src/Hooks/CEconItemSchema_GetItemDefinition.cpp new file mode 100644 index 0000000..c1150e9 --- /dev/null +++ b/Amalgam/src/Hooks/CEconItemSchema_GetItemDefinition.cpp @@ -0,0 +1,23 @@ +#include "../SDK/SDK.h" + +struct CEconItemDefinition_t +{ + byte pad0[524]; + uint32 m_unEquipRegionMask; + uint32 m_unEquipRegionConflictMask; +}; + +MAKE_SIGNATURE(CEconItemSchema_GetItemDefinition, "client.dll", "89 54 24 ? 53 48 83 EC ? 48 8B D9 48 8D 54 24 ? 48 81 C1 ? ? ? ? E8 ? ? ? ? 85 C0", 0x0); + +MAKE_HOOK(CEconItemSchema_GetItemDefinition, S::CEconItemSchema_GetItemDefinition(), CEconItemDefinition_t*, __fastcall, + void* ecx, int iItemIndex) +{ + const auto pItemDefinition = CALL_ORIGINAL(ecx, iItemIndex); + if (Vars::Misc::Exploits::EquipRegionUnlock.Value && pItemDefinition) + { + pItemDefinition->m_unEquipRegionMask = 0; + pItemDefinition->m_unEquipRegionConflictMask = 0; + } + + return pItemDefinition; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CGameEventManager_FireEventIntern.cpp b/Amalgam/src/Hooks/CGameEventManager_FireEventIntern.cpp new file mode 100644 index 0000000..ffda7a0 --- /dev/null +++ b/Amalgam/src/Hooks/CGameEventManager_FireEventIntern.cpp @@ -0,0 +1,68 @@ +#include "../SDK/SDK.h" + +#include "../Features/Backtrack/Backtrack.h" +#include "../Features/CheaterDetection/CheaterDetection.h" +#include "../Features/CritHack/CritHack.h" +#include "../Features/Logs/Logs.h" +#include "../Features/Misc/Misc.h" +#include "../Features/PacketManip/AntiAim/AntiAim.h" +#include "../Features/Resolver/Resolver.h" +#include "../Features/Visuals/Visuals.h" + +MAKE_SIGNATURE(CGameEventManager_FireEventIntern, "engine.dll", "44 88 44 24 ? 48 89 4C 24 ? 55 57", 0x0); + +MAKE_HOOK(CGameEventManager_FireEventIntern, S::CGameEventManager_FireEventIntern(), bool, __fastcall, + void* ecx, IGameEvent* pEvent, bool bServerOnly, bool bClientOnly) +{ + SDK::Output("Event", std::format("{}: {}, {}", pEvent ? pEvent->GetName() : "unknown", bServerOnly, bClientOnly).c_str(), {255, 255, 255, 255}, Vars::Debug::Logging.Value, false, true); + + if (!pEvent || I::EngineClient->IsPlayingTimeDemo() || !bClientOnly) + return CALL_ORIGINAL(ecx, pEvent, bServerOnly, bClientOnly); + + auto pLocal = H::Entities.GetLocal(); + auto uHash = FNV1A::Hash(pEvent->GetName()); + + F::Logs.Event(pEvent, uHash, pLocal); + F::CritHack.Event(pEvent, uHash, pLocal); + F::Misc.Event(pEvent, uHash); + switch (uHash) + { + case FNV1A::HashConst("player_hurt"): + F::Resolver.OnPlayerHurt(pEvent); + F::CheaterDetection.ReportDamage(pEvent); + break; + case FNV1A::HashConst("player_spawn"): + F::Backtrack.SetLerp(pEvent); + break; + case FNV1A::HashConst("item_pickup"): // this is never sent!!! + { + if (!Vars::Visuals::UI::PickupTimers.Value) + break; + + if (auto pEntity = I::ClientEntityList->GetClientEntity(I::EngineClient->GetPlayerForUserID(pEvent->GetInt("userid")))) + { + auto itemName = pEvent->GetString("item"); + if (std::strstr(itemName, "medkit")) + F::Visuals.PickupDatas.push_back({ 1, I::EngineClient->Time(), pEntity->GetAbsOrigin() }); + else if (std::strstr(itemName, "ammopack")) + F::Visuals.PickupDatas.push_back({ 0, I::EngineClient->Time(), pEntity->GetAbsOrigin() }); + } + + break; + } + case FNV1A::HashConst("revive_player_notify"): + { + if (!Vars::Misc::MannVsMachine::InstantRevive.Value) + break; + + if (pEvent->GetInt("entindex") != I::EngineClient->GetLocalPlayer()) + break; + + auto kv = new KeyValues("MVM_Revive_Response"); + kv->SetInt("accepted", 1); + I::EngineClient->ServerCmdKeyValues(kv); + } + } + + return CALL_ORIGINAL(ecx, pEvent, bServerOnly, bClientOnly); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CHudCrosshair_GetDrawPosition.cpp b/Amalgam/src/Hooks/CHudCrosshair_GetDrawPosition.cpp new file mode 100644 index 0000000..0a0bc95 --- /dev/null +++ b/Amalgam/src/Hooks/CHudCrosshair_GetDrawPosition.cpp @@ -0,0 +1,68 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CHudCrosshair_GetDrawPosition, "client.dll", "48 8B C4 55 53 56 41 54 41 55", 0x0); + +MAKE_HOOK(CHudCrosshair_GetDrawPosition, S::CHudCrosshair_GetDrawPosition(), void, __cdecl, + float* pX, float* pY, bool* pbBehindCamera, Vec3 angleCrosshairOffset) +{ + if (!Vars::Visuals::Viewmodel::CrosshairAim.Value && !Vars::Visuals::ThirdPerson::Crosshair.Value + || Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + return CALL_ORIGINAL(pX, pY, pbBehindCamera, angleCrosshairOffset); + + auto pLocal = H::Entities.GetLocal(); + if (!pLocal) + return CALL_ORIGINAL(pX, pY, pbBehindCamera, angleCrosshairOffset); + + bool bSet = false; + + if (Vars::Visuals::Viewmodel::CrosshairAim.Value && pLocal->IsAlive()) + { + static Vec3 vPos = {}; + static int iTick = 0; + + if (!G::AimPosition.IsZero()) + { + vPos = G::AimPosition; + iTick = I::GlobalVars->tickcount; + } + + if (abs(iTick - I::GlobalVars->tickcount) < 32) + { + Vec3 vScreen; + if (SDK::W2S(vPos, vScreen)) + { + if (pX) *pX = vScreen.x; + if (pY) *pY = vScreen.y; + if (pbBehindCamera) *pbBehindCamera = false; + bSet = true; + } + } + } + + if (Vars::Visuals::ThirdPerson::Crosshair.Value && !bSet && I::Input->CAM_IsThirdPerson()) + { + const Vec3 viewangles = I::EngineClient->GetViewAngles(); + Vec3 vForward{}; + Math::AngleVectors(viewangles, &vForward); + + const Vec3 vStartPos = pLocal->GetEyePosition(); + const Vec3 vEndPos = (vStartPos + vForward * 8192); + + CGameTrace trace = {}; + CTraceFilterHitscan filter = {}; + filter.pSkip = pLocal; + SDK::Trace(vStartPos, vEndPos, MASK_SHOT, &filter, &trace); + + Vec3 vScreen; + if (SDK::W2S(trace.endpos, vScreen)) + { + if (pX) *pX = vScreen.x; + if (pY) *pY = vScreen.y; + if (pbBehindCamera) *pbBehindCamera = false; + bSet = true; + } + } + + if (!bSet) + CALL_ORIGINAL(pX, pY, pbBehindCamera, angleCrosshairOffset); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CInterpolatedVarArrayBase_Interpolate.cpp b/Amalgam/src/Hooks/CInterpolatedVarArrayBase_Interpolate.cpp new file mode 100644 index 0000000..652f0ce --- /dev/null +++ b/Amalgam/src/Hooks/CInterpolatedVarArrayBase_Interpolate.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CInterpolatedVarArrayBase_Interpolate, "client.dll", "48 8B C4 55 56 57 48 8D 68 ? 48 81 EC ? ? ? ? 0F 29 78", 0x0); + +MAKE_HOOK(CInterpolatedVarArrayBase_Interpolate, S::CInterpolatedVarArrayBase_Interpolate(), int, __fastcall, + void* ecx, float currentTime, float interpolation_amount) +{ + return Vars::Visuals::Removals::Interpolation.Value ? 1 : CALL_ORIGINAL(ecx, currentTime, interpolation_amount); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CInventoryManager_ShowItemsPickedUp.cpp b/Amalgam/src/Hooks/CInventoryManager_ShowItemsPickedUp.cpp new file mode 100644 index 0000000..da0d367 --- /dev/null +++ b/Amalgam/src/Hooks/CInventoryManager_ShowItemsPickedUp.cpp @@ -0,0 +1,14 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CInventoryManager_ShowItemsPickedUp, "client.dll", "44 88 4C 24 ? 44 88 44 24 ? 53 41 56", 0x0); + +MAKE_HOOK(CInventoryManager_ShowItemsPickedUp, S::CInventoryManager_ShowItemsPickedUp(), bool, __fastcall, + void* ecx, bool bForce, bool bReturnToGame, bool bNoPanel) +{ + if (Vars::Misc::Automation::AcceptItemDrops.Value) + { + CALL_ORIGINAL(ecx, true, true, true); + return false; + } + return CALL_ORIGINAL(ecx, bForce, bReturnToGame, bNoPanel); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CL_CheckForPureServerWhitelist.cpp b/Amalgam/src/Hooks/CL_CheckForPureServerWhitelist.cpp new file mode 100644 index 0000000..b95a016 --- /dev/null +++ b/Amalgam/src/Hooks/CL_CheckForPureServerWhitelist.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CL_CheckForPureServerWhitelist, "engine.dll", "40 56 48 83 EC ? 83 3D ? ? ? ? ? 48 8B F1 0F 8E", 0x0); + +MAKE_HOOK(CL_CheckForPureServerWhitelist, S::CL_CheckForPureServerWhitelist(), void, __cdecl, + void **pFilesToReload) +{ + if (Vars::Misc::Exploits::BypassPure.Value) + return; + + CALL_ORIGINAL(pFilesToReload); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CL_Move.cpp b/Amalgam/src/Hooks/CL_Move.cpp new file mode 100644 index 0000000..a367f9b --- /dev/null +++ b/Amalgam/src/Hooks/CL_Move.cpp @@ -0,0 +1,37 @@ +#include "../SDK/SDK.h" + +#include "../Features/TickHandler/TickHandler.h" +#include "../Features/Conditions/Conditions.h" +#include "../Features/CheaterDetection/CheaterDetection.h" +#include "../Features/Players/PlayerCore.h" +#include "../Features/AutoQueue/AutoQueue.h" +#include "../Features/Backtrack/Backtrack.h" +#include "../Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h" + +MAKE_SIGNATURE(CL_Move, "engine.dll", "40 55 53 48 8D AC 24 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 83 3D", 0x0); + +MAKE_HOOK(CL_Move, S::CL_Move(), void, __fastcall, + float accumulated_extra_samples, bool bFinalTick) +{ + if (G::Unload) + return CALL_ORIGINAL(accumulated_extra_samples, bFinalTick); + + F::Backtrack.iTickCount = I::GlobalVars->tickcount; + + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + + F::Conditions.Run(pLocal, pWeapon); + F::CheaterDetection.Run(); + F::Ticks.Run(accumulated_extra_samples, bFinalTick, pLocal); + F::PlayerCore.Run(); + F::AutoQueue.Run(); + F::NoSpreadHitscan.AskForPlayerPerf(); + I::EngineClient->FireEvents(); + + for (auto& Line : G::LinesStorage) + { + if (Line.m_flTime < 0.f) + Line.m_flTime = std::min(Line.m_flTime + 1.f, 0.f); + } +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CL_ReadPackets.cpp b/Amalgam/src/Hooks/CL_ReadPackets.cpp new file mode 100644 index 0000000..761043f --- /dev/null +++ b/Amalgam/src/Hooks/CL_ReadPackets.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +#include "../Features/NetworkFix/NetworkFix.h" + +MAKE_SIGNATURE(CL_ReadPackets, "engine.dll", "4C 8B DC 49 89 5B ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC ? 48 8B 05", 0x0); + +MAKE_HOOK(CL_ReadPackets, S::CL_ReadPackets(), void, __cdecl, + bool bFinalTick) +{ + if (F::NetworkFix.ShouldReadPackets()) + CALL_ORIGINAL(bFinalTick); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CMatchInviteNotification_OnTick.cpp b/Amalgam/src/Hooks/CMatchInviteNotification_OnTick.cpp new file mode 100644 index 0000000..8eb0d05 --- /dev/null +++ b/Amalgam/src/Hooks/CMatchInviteNotification_OnTick.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CMatchInviteNotification_OnTick, "client.dll", "40 53 48 83 EC ? 48 8B D9 E8 ? ? ? ? F7 83", 0x0); + +MAKE_HOOK(CMatchInviteNotification_OnTick, S::CMatchInviteNotification_OnTick(), void, __fastcall, + void* ecx) +{ + if (Vars::Misc::Queueing::FreezeQueue.Value) + *reinterpret_cast(std::uintptr_t(ecx) + 616) = 0.0; + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CMaterial_Uncache.cpp b/Amalgam/src/Hooks/CMaterial_Uncache.cpp new file mode 100644 index 0000000..9d6e738 --- /dev/null +++ b/Amalgam/src/Hooks/CMaterial_Uncache.cpp @@ -0,0 +1,14 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Materials/Materials.h" + +MAKE_SIGNATURE(CMaterial_Uncache, "materialsystem.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 81 EC ? ? ? ? 48 8B F9", 0x0); + +MAKE_HOOK(CMaterial_Uncache, S::CMaterial_Uncache(), void, __fastcall, + IMaterial* ecx, bool bPreserveVars) +{ + if (ecx && F::Materials.mMatList.contains(ecx)) + return; + + CALL_ORIGINAL(ecx, bPreserveVars); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CNetChan_SendNetMsg.cpp b/Amalgam/src/Hooks/CNetChan_SendNetMsg.cpp new file mode 100644 index 0000000..796829f --- /dev/null +++ b/Amalgam/src/Hooks/CNetChan_SendNetMsg.cpp @@ -0,0 +1,95 @@ +#include "../SDK/SDK.h" + +#include "../Features/TickHandler/TickHandler.h" + +MAKE_SIGNATURE(CNetChan_SendNetMsg, "engine.dll", "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 48 8B F1 45 0F B6 F1", 0x0); + +MAKE_HOOK(CNetChan_SendNetMsg, S::CNetChan_SendNetMsg(), bool, __fastcall, + CNetChannel* pNetChannel, INetMessage& msg, bool bForceReliable, bool bVoice) +{ + switch (msg.GetType()) + { + case clc_VoiceData: + // stop lag with voice chat + bVoice = true; + break; + case clc_FileCRCCheck: + // whitelist + if (Vars::Misc::Exploits::BypassPure.Value) + return false; + break; + case clc_RespondCvarValue: + // causes b1g crash + if (Vars::Visuals::Removals::ConvarQueries.Value) + { + if (const auto pMsg = reinterpret_cast(&msg)) + { + if (const auto cvarName = reinterpret_cast(pMsg[6])) + { + if (const auto pConVar = U::ConVars.FindVar(cvarName)) + { + if (auto defaultValue = pConVar->m_pParent->m_pszDefaultValue) + { + pMsg[7] = std::uintptr_t(defaultValue); + SDK::Output("Removals::ConvarQueries", msg.ToString()); + break; + } + } + return true; // if we failed to manipulate the data, don't send it. + } + } + } + break; + case clc_Move: + { + const auto pMsg = reinterpret_cast(&msg); + + { + const int nLastOutGoingCommand = I::ClientState->lastoutgoingcommand; + const int nChokedCommands = I::ClientState->chokedcommands; + const int nNextCommandNr = nLastOutGoingCommand + nChokedCommands + 1; + + byte data[4000] = {}; + pMsg->m_DataOut.StartWriting(data, sizeof(data)); + pMsg->m_nNewCommands = std::clamp(1 + nChokedCommands, 0, MAX_NEW_COMMANDS); + const int nExtraCommands = nChokedCommands + 1 - pMsg->m_nNewCommands; + const int nCmdBackup = std::max(2, nExtraCommands); + pMsg->m_nBackupCommands = std::clamp(nCmdBackup, 0, MAX_BACKUP_COMMANDS); + + const int nNumCmds = pMsg->m_nNewCommands + pMsg->m_nBackupCommands; + int nFrom = -1; + bool bOk = true; + for (int nTo = nNextCommandNr - nNumCmds + 1; nTo <= nNextCommandNr; nTo++) + { + const bool bIsNewCmd = nTo >= nNextCommandNr - pMsg->m_nNewCommands + 1; + bOk = bOk && I::BaseClientDLL->WriteUsercmdDeltaToBuffer(&pMsg->m_DataOut, nFrom, nTo, bIsNewCmd); + nFrom = nTo; + } + + if (bOk) + { + if (nExtraCommands > 0) + pNetChannel->m_nChokedPackets -= nExtraCommands; + + CALL_ORIGINAL(pNetChannel, reinterpret_cast(*pMsg), bForceReliable, bVoice); + } + } + + { + static auto sv_maxusrcmdprocessticks = U::ConVars.FindVar("sv_maxusrcmdprocessticks"); + const int iAllowedNewCommands = fmax(sv_maxusrcmdprocessticks->GetInt() - G::ShiftedTicks, 0); + const int iCmdCount = pMsg->m_nNewCommands + pMsg->m_nBackupCommands - 3; + if (iCmdCount > iAllowedNewCommands) + { + SDK::Output("clc_Move", std::format("{:d} sent <{:d} | {:d}>, max was {:d}.", iCmdCount, pMsg->m_nNewCommands, pMsg->m_nBackupCommands, iAllowedNewCommands).c_str(), { 0, 222, 255, 255 }, Vars::Debug::Logging.Value); + G::ShiftedTicks = G::ShiftedGoal -= iCmdCount - iAllowedNewCommands; + F::Ticks.iDeficit = iCmdCount - iAllowedNewCommands; + } + } + + return true; + } + } + + return CALL_ORIGINAL(pNetChannel, msg, bForceReliable, bVoice); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/COPRenderSprites_RenderSpriteCard.cpp b/Amalgam/src/Hooks/COPRenderSprites_RenderSpriteCard.cpp new file mode 100644 index 0000000..e2b4c54 --- /dev/null +++ b/Amalgam/src/Hooks/COPRenderSprites_RenderSpriteCard.cpp @@ -0,0 +1,46 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(COPRenderSprites_RenderSpriteCard, "client.dll", "48 8B C4 48 89 58 ? 57 41 54", 0x0); + +// https://www.unknowncheats.me/forum/team-fortress-2-a/520739-custom-particle-colors.html +typedef union +{ + float m128_f32[4]; + uint32_t m128_u32[4]; +} fltx4; + +struct SpriteRenderInfo_t +{ + size_t m_nXYZStride{}; + fltx4* m_pXYZ{}; + size_t m_nRotStride{}; + fltx4* m_pRot{}; + size_t m_nYawStride{}; + fltx4* m_pYaw{}; + size_t m_nRGBStride{}; + fltx4* m_pRGB{}; + size_t m_nCreationTimeStride{}; + fltx4* m_pCreationTimeStamp{}; + size_t m_nSequenceStride{}; + fltx4* m_pSequenceNumber{}; + size_t m_nSequence1Stride{}; + fltx4* m_pSequence1Number{}; + float m_flAgeScale{}; + float m_flAgeScale2{}; + void* m_pSheet{}; + int m_nVertexOffset{}; + void* m_pParticles{}; +}; + +MAKE_HOOK(COPRenderSprites_RenderSpriteCard, S::COPRenderSprites_RenderSpriteCard(), void, __fastcall, + void* ecx, void* meshBuilder, void* pCtx, SpriteRenderInfo_t& info, int hParticle, void* pSortList, void* pCamera) +{ + if (Vars::Visuals::World::Modulations.Value & 1 << 3 && !(Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot())) + { + info.m_pRGB[((hParticle / 4) * info.m_nRGBStride) + 0].m128_f32[hParticle & 0x3] = float(Vars::Colors::ParticleModulation.Value.r) / 255.f; // red + info.m_pRGB[((hParticle / 4) * info.m_nRGBStride) + 1].m128_f32[hParticle & 0x3] = float(Vars::Colors::ParticleModulation.Value.g) / 255.f; // green + info.m_pRGB[((hParticle / 4) * info.m_nRGBStride) + 2].m128_f32[hParticle & 0x3] = float(Vars::Colors::ParticleModulation.Value.b) / 255.f; // blue + } + + CALL_ORIGINAL(ecx, meshBuilder, pCtx, info, hParticle, pSortList, pCamera); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CPlayerResource_GetTeamColor.cpp b/Amalgam/src/Hooks/CPlayerResource_GetTeamColor.cpp new file mode 100644 index 0000000..60f19bc --- /dev/null +++ b/Amalgam/src/Hooks/CPlayerResource_GetTeamColor.cpp @@ -0,0 +1,61 @@ +#include "../SDK/SDK.h" +#include "../Features/Players/PlayerUtils.h" + +MAKE_SIGNATURE(CTFPlayerResource_GetPlayerConnectionState, "client.dll", "85 D2 74 ? 83 FA ? 7F", 0x0); +MAKE_SIGNATURE(CPlayerResource_GetTeamColor, "client.dll", "83 FA ? 77 ? 48 63 C2 48 05", 0x0); +MAKE_SIGNATURE(CTFPlayer_Resource_Call, "client.dll", "8B E8 85 C0 75 ? 48 8B 0D", 0x0); + +int iCurPlayer; +unsigned char _color[4]; + +__inline Color_t GetScoreboardColor(int iIndex, bool enableOtherColors) +{ + Color_t out = { 0, 0, 0, 0 }; + + PlayerInfo_t pi{}; bool bTagColor = false; Color_t plTagColor; + if (I::EngineClient->GetPlayerInfo(iIndex, &pi)) + { + std::string _; PriorityLabel_t plTag; + if (bTagColor = F::PlayerUtils.GetSignificantTag(pi.friendsID, &_, &plTag)) + plTagColor = plTag.Color; + } + + if (iIndex == I::EngineClient->GetLocalPlayer()) + out = Vars::Colors::Local.Value; + else if (H::Entities.IsFriend(iIndex)) + out = F::PlayerUtils.mTags["Friend"].Color; + else if (bTagColor) + out = plTagColor; + + return out; +} + +MAKE_HOOK(CTFPlayerResource_GetPlayerConnectionState, S::CTFPlayerResource_GetPlayerConnectionState(), MM_PlayerConnectionState_t, __fastcall, + void* ecx, int iIndex) +{ + static auto dwDesired = S::CTFPlayer_Resource_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + const auto result = CALL_ORIGINAL(ecx, iIndex); + + if (result != MM_WAITING_FOR_PLAYER && dwRetAddr == dwDesired) + iCurPlayer = iIndex; + else + iCurPlayer = 0; + + return result; +} + +MAKE_HOOK(CPlayerResource_GetTeamColor, S::CPlayerResource_GetTeamColor(), unsigned char*, __fastcall, + void* ecx, int iIndex) +{ + if (!Vars::Visuals::UI::ScoreboardColors.Value || !iCurPlayer) + return CALL_ORIGINAL(ecx, iIndex); + + const Color_t cReturn = GetScoreboardColor(iCurPlayer, Vars::Colors::Relative.Value); + if (!cReturn.a) + return CALL_ORIGINAL(ecx, iIndex); + + _color[0] = cReturn.r; _color[1] = cReturn.g; _color[2] = cReturn.b; _color[3] = 255; + return _color; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CPrediction_RunCommand.cpp b/Amalgam/src/Hooks/CPrediction_RunCommand.cpp new file mode 100644 index 0000000..69715c4 --- /dev/null +++ b/Amalgam/src/Hooks/CPrediction_RunCommand.cpp @@ -0,0 +1,25 @@ +#include "../SDK/SDK.h" + +std::vector vAngles; + +MAKE_HOOK(CPrediction_RunCommand, U::Memory.GetVFunc(I::Prediction, 17), void, __fastcall, + void* ecx, CTFPlayer* pPlayer, CUserCmd* pCmd, IMoveHelper* moveHelper) +{ + CALL_ORIGINAL(ecx, pPlayer, pCmd, moveHelper); + + // credits: KGB + if (pPlayer != H::Entities.GetLocal() || G::Recharge || pCmd->hasbeenpredicted) + return; + + auto pAnimState = pPlayer->GetAnimState(); + vAngles.push_back(G::ViewAngles); + if (!pAnimState || G::Choking) + return; + + for (auto& vAngle : vAngles) + { + pAnimState->Update(vAngle.y, vAngle.x); + pPlayer->FrameAdvance(TICK_INTERVAL); + } + vAngles.clear(); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CRendering3dView_EnableWorldFog.cpp b/Amalgam/src/Hooks/CRendering3dView_EnableWorldFog.cpp new file mode 100644 index 0000000..a08e369 --- /dev/null +++ b/Amalgam/src/Hooks/CRendering3dView_EnableWorldFog.cpp @@ -0,0 +1,20 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CRendering3dView_EnableWorldFog, "client.dll", "40 53 48 83 EC ? 48 8B 0D ? ? ? ? 48 89 7C 24", 0x0); + +MAKE_HOOK(CRendering3dView_EnableWorldFog, S::CRendering3dView_EnableWorldFog(), void, __cdecl, + ) +{ + if (!(Vars::Visuals::World::Modulations.Value & 1 << 4) || I::EngineClient->IsTakingScreenshot() && Vars::Visuals::UI::CleanScreenshots.Value) + return CALL_ORIGINAL(); + + if (!Vars::Colors::FogModulation.Value.a) + return; + + CALL_ORIGINAL(); + if (const auto pRenderContext = I::MaterialSystem->GetRenderContext()) + { + float blend[3] = { float(Vars::Colors::FogModulation.Value.r) / 255.f, float(Vars::Colors::FogModulation.Value.g) / 255.f, float(Vars::Colors::FogModulation.Value.b) / 255.f }; + pRenderContext->FogColor3fv(blend); + } +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CSequenceTransitioner_CheckForSequenceChange.cpp b/Amalgam/src/Hooks/CSequenceTransitioner_CheckForSequenceChange.cpp new file mode 100644 index 0000000..86bf56e --- /dev/null +++ b/Amalgam/src/Hooks/CSequenceTransitioner_CheckForSequenceChange.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CSequenceTransitioner_CheckForSequenceChange, "client.dll", "48 85 D2 0F 84 ? ? ? ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24", 0x0); + +MAKE_HOOK(CSequenceTransitioner_CheckForSequenceChange, S::CSequenceTransitioner_CheckForSequenceChange(), void, __fastcall, + void* ecx, CStudioHdr* hdr, int nCurSequence, bool bForceNewSequence, bool bInterpolate) +{ + return CALL_ORIGINAL(ecx, hdr, nCurSequence, bForceNewSequence, Vars::Visuals::Removals::Interpolation.Value ? false : bInterpolate); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CSkyboxView_Enable3dSkyboxFog.cpp b/Amalgam/src/Hooks/CSkyboxView_Enable3dSkyboxFog.cpp new file mode 100644 index 0000000..82104fa --- /dev/null +++ b/Amalgam/src/Hooks/CSkyboxView_Enable3dSkyboxFog.cpp @@ -0,0 +1,20 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CSkyboxView_Enable3dSkyboxFog, "client.dll", "40 57 48 83 EC ? E8 ? ? ? ? 48 8B F8 48 85 C0 0F 84 ? ? ? ? 48 8B 0D", 0x0); + +MAKE_HOOK(CSkyboxView_Enable3dSkyboxFog, S::CSkyboxView_Enable3dSkyboxFog(), void, __fastcall, + void* ecx) +{ + if (!(Vars::Visuals::World::Modulations.Value & 1 << 4) || I::EngineClient->IsTakingScreenshot() && Vars::Visuals::UI::CleanScreenshots.Value) + return CALL_ORIGINAL(ecx); + + if (!Vars::Colors::FogModulation.Value.a) + return; + + CALL_ORIGINAL(ecx); + if (const auto pRenderContext = I::MaterialSystem->GetRenderContext()) + { + float blend[3] = { float(Vars::Colors::FogModulation.Value.r) / 255.f, float(Vars::Colors::FogModulation.Value.g) / 255.f, float(Vars::Colors::FogModulation.Value.b) / 255.f }; + pRenderContext->FogColor3fv(blend); + } +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CSoundEmitterSystem_EmitSound.cpp b/Amalgam/src/Hooks/CSoundEmitterSystem_EmitSound.cpp new file mode 100644 index 0000000..042e323 --- /dev/null +++ b/Amalgam/src/Hooks/CSoundEmitterSystem_EmitSound.cpp @@ -0,0 +1,121 @@ +#include "../SDK/SDK.h" + +#include + +MAKE_SIGNATURE(CSoundEmitterSystem_EmitSound, "client.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 41 56 48 81 EC ? ? ? ? 49 8B D9", 0x0); + +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; +}; + +struct CSoundParameters +{ + CSoundParameters() + { + channel = 0; // 0 + volume = 1.0f; // 1.0f + pitch = 100; // 100 + + pitchlow = 100; + pitchhigh = 100; + + 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; +}; + +struct EmitSound_t +{ + EmitSound_t() : + m_nChannel(0), + m_pSoundName(0), + m_flVolume(1.0f), + m_SoundLevel(0), + m_nFlags(0), + m_nPitch(100), + m_nSpecialDSP(0), + m_pOrigin(0), + m_flSoundTime(0.0f), + m_pflSoundDuration(0), + m_bEmitCloseCaption(true), + m_bWarnOnMissingCloseCaption(false), + m_bWarnOnDirectWaveReference(false), + m_nSpeakerEntity(-1), + m_UtlVecSoundOrigin(), + m_hSoundScriptHandle(-1) + { + } + + EmitSound_t(const CSoundParameters& src); + + int m_nChannel; + char const* m_pSoundName; + float m_flVolume; + int m_SoundLevel; + int m_nFlags; + int m_nPitch; + int m_nSpecialDSP; + const Vector* m_pOrigin; + float m_flSoundTime; ///< NOT DURATION, but rather, some absolute time in the future until which this sound should be delayed + float* m_pflSoundDuration; + bool m_bEmitCloseCaption; + bool m_bWarnOnMissingCloseCaption; + bool m_bWarnOnDirectWaveReference; + int m_nSpeakerEntity; + mutable CUtlVector< Vector > m_UtlVecSoundOrigin; ///< Actual sound origin(s) (can be multiple if sound routed through speaker entity(ies) ) + mutable short m_hSoundScriptHandle; +}; + +const static std::vector NOISEMAKER_SOUNDS{ "items/halloween", "items/football_manager", "items/japan_fundraiser", "items/samurai", "items/summer", "misc/happy_birthday_tf", "misc/jingle_bells" }; + +MAKE_HOOK(CSoundEmitterSystem_EmitSound, S::CSoundEmitterSystem_EmitSound(), void, __fastcall, + void* ecx, IRecipientFilter& filter, int entindex, const EmitSound_t& ep) +{ + if (ep.m_pSoundName) + { + std::string soundName(ep.m_pSoundName); + boost::algorithm::to_lower(soundName); + + // Footsteps + if (Vars::Misc::Sound::Block.Value & (1 << 0)) + { + if (soundName.find("footsteps") != std::string::npos) + return; + } + + // Noisemaker + if (Vars::Misc::Sound::Block.Value & (1 << 1)) + { + for (auto& sound : NOISEMAKER_SOUNDS) + { + if (soundName.find(sound) != std::string::npos) + return; + } + } + } + + return CALL_ORIGINAL(ecx, filter, entindex, ep); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CStaticPropMgr_ComputePropOpacity.cpp b/Amalgam/src/Hooks/CStaticPropMgr_ComputePropOpacity.cpp new file mode 100644 index 0000000..03ad096 --- /dev/null +++ b/Amalgam/src/Hooks/CStaticPropMgr_ComputePropOpacity.cpp @@ -0,0 +1,51 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CStaticPropMgr_ComputePropOpacity, "engine.dll", "48 89 5C 24 ? 48 89 7C 24 ? 41 54 41 56 41 57 48 83 EC ? 48 8B 05", 0x0); + +class CStaticProp +{ +public: + byte pad[20]; + Vector m_Origin; + QAngle m_Angles; + model_t* m_pModel; + SpatialPartitionHandle_t m_Partition; + ModelInstanceHandle_t m_ModelInstance; + unsigned char m_Alpha; + unsigned char m_nSolidType; + unsigned char m_Skin; + unsigned char m_Flags; + unsigned short m_FirstLeaf; + unsigned short m_LeafCount; + CBaseHandle m_EntHandle; // FIXME: Do I need client + server handles? + ClientRenderHandle_t m_RenderHandle; + unsigned short m_FadeIndex; // Index into the m_StaticPropFade dictionary + float m_flForcedFadeScale; + + // bbox is the same for both GetBounds and GetRenderBounds since static props never move. + // GetRenderBounds is interpolated data, and GetBounds is last networked. + Vector m_RenderBBoxMin; + Vector m_RenderBBoxMax; + matrix3x4 m_ModelToWorld; + float m_flRadius; + + Vector m_WorldRenderBBoxMin; + Vector m_WorldRenderBBoxMax; + + // FIXME: This sucks. Need to store the lighting origin off + // because the time at which the static props are unserialized + // doesn't necessarily match the time at which we can initialize the light cache + Vector m_LightingOrigin; +}; + +MAKE_HOOK(CStaticPropMgr_ComputePropOpacity, S::CStaticPropMgr_ComputePropOpacity(), void, __fastcall, + void* ecx, CStaticProp* pProp) +{ + if (Vars::Visuals::World::NoPropFade.Value && pProp) + { + pProp->m_Alpha = 255; + return; + } + + CALL_ORIGINAL(ecx, pProp); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp b/Amalgam/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp new file mode 100644 index 0000000..216aec2 --- /dev/null +++ b/Amalgam/src/Hooks/CStaticPropMgr_DrawStaticProps.cpp @@ -0,0 +1,11 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CStaticPropMgr_DrawStaticProps, "engine.dll", "4C 8B DC 49 89 5B ? 49 89 6B ? 49 89 73 ? 57 41 54 41 55 41 56 41 57 48 83 EC ? 4C 8B 3D", 0x0); + +MAKE_HOOK(CStaticPropMgr_DrawStaticProps, S::CStaticPropMgr_DrawStaticProps(), void, __fastcall, + void* ecx, IClientRenderable** pProps, int count, bool bShadowDepth, bool drawVCollideWireframe) +{ + G::DrawingProps = true; + CALL_ORIGINAL(ecx, pProps, count, bShadowDepth, drawVCollideWireframe); + G::DrawingProps = false; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CStudioRender_DrawModelStaticProp.cpp b/Amalgam/src/Hooks/CStudioRender_DrawModelStaticProp.cpp new file mode 100644 index 0000000..98fb819 --- /dev/null +++ b/Amalgam/src/Hooks/CStudioRender_DrawModelStaticProp.cpp @@ -0,0 +1,22 @@ +#include "../SDK/SDK.h" + +MAKE_HOOK(CStudioRender_DrawModelStaticProp, U::Memory.GetVFunc(I::StudioRender, 30), void, __fastcall, + void* ecx, const DrawModelState_t& pState, const matrix3x4& modelToWorld, int flags) +{ + if (Vars::Visuals::World::NearPropFade.Value) + { + if (auto pLocal = H::Entities.GetLocal()) + { + Vec3 vOrigin = { modelToWorld[0][3], modelToWorld[1][3], modelToWorld[2][3] }; + + const float flDistance = pLocal->m_vecOrigin().DistTo(vOrigin); + + float flAlpha = 1.f; + if (flDistance < 300.0f) + flAlpha = Math::RemapValClamped(flDistance, 150.0f, 300.0f, 0.15f, 1.f); + I::StudioRender->SetAlphaModulation(flAlpha); + } + } + + CALL_ORIGINAL(ecx, pState, modelToWorld, flags); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFGCClientSystem_UpdateAssignedLobby.cpp b/Amalgam/src/Hooks/CTFGCClientSystem_UpdateAssignedLobby.cpp new file mode 100644 index 0000000..8a62b73 --- /dev/null +++ b/Amalgam/src/Hooks/CTFGCClientSystem_UpdateAssignedLobby.cpp @@ -0,0 +1,14 @@ +// what is this for? + +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFGCClientSystem_UpdateAssignedLobby, "client.dll", "55 8B EC 83 EC 28 53 8B D9 56 57 89 5D F0 8B 8B ? ? ? ? 85 C9 0F 84 ? ? ? ? 68 ? ? ? ? E8 ? ? ? ? 85 C0 74 77", 0x0); + +MAKE_HOOK(CTFGCClientSystem_UpdateAssignedLobby, S::CTFGCClientSystem_UpdateAssignedLobby(), char /*?*/, __fastcall, + void* ecx) +{ + char cReturn = CALL_ORIGINAL(ecx); + if (ecx) + *((bool*)ecx + 1440) = false; + return cReturn; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFGameRules_ModifySentChat.cpp b/Amalgam/src/Hooks/CTFGameRules_ModifySentChat.cpp new file mode 100644 index 0000000..bc53b5e --- /dev/null +++ b/Amalgam/src/Hooks/CTFGameRules_ModifySentChat.cpp @@ -0,0 +1,41 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFGameRules_ModifySentChat, "client.dll", "55 8B EC 80 B9 ? ? ? ? ? 56 8B 75 08 74 26", 0x0); + +struct s_CTFGameRules +{ + char pad[1031]; + bool m_bPlayingMedieval; +}; + +MAKE_HOOK(CTFGameRules_ModifySentChat, S::CTFGameRules_ModifySentChat(), void, __fastcall, + void* ecx, char* pBuf, int iBufSize) +{ + if (Vars::Misc::MedievalChat.Value > 0) + { + if (const auto pGameRules = static_cast(ecx)) + { + ConVar* tf_medieval_autorp = I::CVar->FindVar("tf_medieval_autorp"); + ConVar* english = I::CVar->FindVar("english"); + if (tf_medieval_autorp && english) + { + const bool bOriginalAutoRP = tf_medieval_autorp->GetBool(); + const bool bOriginalEnglish = english->GetBool(); + const bool bOriginalPlayingMedieval = pGameRules->m_bPlayingMedieval; + const bool forceMedieval = Vars::Misc::MedievalChat.Value == 2; + + pGameRules->m_bPlayingMedieval = forceMedieval; + tf_medieval_autorp->SetValue(forceMedieval); + english->SetValue(forceMedieval); + + CALL_ORIGINAL(ecx, pBuf, iBufSize); + pGameRules->m_bPlayingMedieval = bOriginalPlayingMedieval; + tf_medieval_autorp->SetValue(bOriginalAutoRP); + english->SetValue(bOriginalEnglish); + return; + } + } + } + + CALL_ORIGINAL(ecx, pBuf, iBufSize); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFMatchSummary_OnTick.cpp b/Amalgam/src/Hooks/CTFMatchSummary_OnTick.cpp new file mode 100644 index 0000000..ece9209 --- /dev/null +++ b/Amalgam/src/Hooks/CTFMatchSummary_OnTick.cpp @@ -0,0 +1,16 @@ +// what is this for? + +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFMatchSummary_OnTick, "client.dll", "55 8B EC 83 EC ? 53 57 8B F9 E8 ? ? ? ? E8", 0x0); + +// Credits: mfed +MAKE_HOOK(CTFMatchSummary_OnTick, S::CTFMatchSummary_OnTick(), int, __fastcall, + void* ecx) +{ + if (!reinterpret_cast(ecx) + 750) { return CALL_ORIGINAL(ecx); } // m_iCurrentState == MS_STATE_INITIAL + DWORD* flags = reinterpret_cast(I::TFGCClientSystem + 1488); + if (flags && *flags & 2) + *flags &= ~2; + return CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPartyClient_BCanRequestToJoinPlayer.cpp b/Amalgam/src/Hooks/CTFPartyClient_BCanRequestToJoinPlayer.cpp new file mode 100644 index 0000000..9bdd1f2 --- /dev/null +++ b/Amalgam/src/Hooks/CTFPartyClient_BCanRequestToJoinPlayer.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPartyClient_BCanRequestToJoinPlayer, "client.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 56 41 57 48 83 EC ? 48 8B E9 48 89 54 24 ? 48 8B 49", 0x0); + +MAKE_HOOK(CTFPartyClient_BCanRequestToJoinPlayer, S::CTFPartyClient_BCanRequestToJoinPlayer(), bool, __fastcall, + CTFPartyClient* ecx, int64 targetPlayer) +{ + return true; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayerInventory_GetMaxItemCount.cpp b/Amalgam/src/Hooks/CTFPlayerInventory_GetMaxItemCount.cpp new file mode 100644 index 0000000..b198e9f --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayerInventory_GetMaxItemCount.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayerInventory_GetMaxItemCount, "client.dll", "40 53 48 83 EC ? 48 8B 89 ? ? ? ? BB", 0x0); + +MAKE_HOOK(CTFPlayerInventory_GetMaxItemCount, S::CTFPlayerInventory_GetMaxItemCount(), int, __fastcall, + void* ecx) +{ + return !Vars::Misc::Automation::BackpackExpander.Value ? CALL_ORIGINAL(ecx) : 3000; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayerPanel_GetTeam.cpp b/Amalgam/src/Hooks/CTFPlayerPanel_GetTeam.cpp new file mode 100644 index 0000000..f81a8f6 --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayerPanel_GetTeam.cpp @@ -0,0 +1,20 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayerPanel_GetTeam, "client.dll", "8B 91 ? ? ? ? 83 FA ? 74 ? 48 8B 05", 0x0); +MAKE_SIGNATURE(CTFPlayerPanel_GetTeam_Desired, "client.dll", "8B 9F ? ? ? ? 40 32 F6", 0x0); + +MAKE_HOOK(CTFPlayerPanel_GetTeam, S::CTFPlayerPanel_GetTeam(), int, __fastcall, + void* ecx) +{ + static auto dwDesired = S::CTFPlayerPanel_GetTeam_Desired(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (Vars::Visuals::UI::RevealScoreboard.Value && dwRetAddr == dwDesired) + { + auto pResource = H::Entities.GetPR(); + if (pResource) + return pResource->GetTeam(I::EngineClient->GetLocalPlayer()); + } + + return CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayerShared_InCond.cpp b/Amalgam/src/Hooks/CTFPlayerShared_InCond.cpp new file mode 100644 index 0000000..522517f --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayerShared_InCond.cpp @@ -0,0 +1,51 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayerShared_InCond, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 8B DA 48 8B F9 83 FA ? 7D", 0x0); +MAKE_SIGNATURE(PlayerShouldDraw, "client.dll", "E8 ? ? ? ? 84 C0 74 ? 32 C0 48 8B 74 24", 0x5); +MAKE_SIGNATURE(WearableShouldDraw, "client.dll", "E8 ? ? ? ? 84 C0 0F 85 ? ? ? ? 41 BF", 0x5); +MAKE_SIGNATURE(HudScopeShouldDraw, "client.dll", "84 C0 74 ? 48 8B CB E8 ? ? ? ? 48 85 C0 74 ? 48 8B CB E8 ? ? ? ? 48 8B C8 48 8B 10 FF 92 ? ? ? ? 83 F8 ? 0F 94 C0", 0x0); + +MAKE_HOOK(CTFPlayerShared_InCond, S::CTFPlayerShared_InCond(), bool, __fastcall, + void* ecx, ETFCond nCond) +{ + static const auto dwPlayerShouldDraw = S::PlayerShouldDraw(); + static const auto dwWearableShouldDraw = S::WearableShouldDraw(); + static const auto dwHudScopeShouldDraw = S::HudScopeShouldDraw(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + auto GetOuter = [&ecx]() -> CBaseEntity* + { + static const auto dwShared = U::NetVars.GetNetVar("CTFPlayer", "m_Shared"); + static const auto dwBombHeadStage = U::NetVars.GetNetVar("CTFPlayer", "m_nHalloweenBombHeadStage"); + static const auto dwOff = (dwBombHeadStage - dwShared) + 0x4; + return *reinterpret_cast(std::uintptr_t(ecx) + dwOff); + }; + + switch (nCond) + { + case TF_COND_ZOOMED: + if (dwRetAddr == dwPlayerShouldDraw || dwRetAddr == dwWearableShouldDraw || Vars::Visuals::Removals::Scope.Value && dwRetAddr == dwHudScopeShouldDraw) + return false; + break; + case TF_COND_TAUNTING: + if (Vars::Visuals::Removals::Taunts.Value) + { + auto pLocal = H::Entities.GetLocal(); + auto pEntity = GetOuter(); + + // Compare team's, removing team's taunt is useless + if (pLocal && pEntity && pEntity->m_iTeamNum() != pLocal->m_iTeamNum()) + return false; + } + break; + case TF_COND_HALLOWEEN_KART: + if (Vars::Misc::Automation::KartControl.Value && H::Entities.GetLocal() == GetOuter() && !G::AnimateKart) + return false; + break; + case TF_COND_DISGUISED: + if (Vars::Visuals::Removals::Disguises.Value && H::Entities.GetLocal() != GetOuter()) + return false; + } + + return CALL_ORIGINAL(ecx, nCond); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayerShared_IsPlayerDominated.cpp b/Amalgam/src/Hooks/CTFPlayerShared_IsPlayerDominated.cpp new file mode 100644 index 0000000..fda5185 --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayerShared_IsPlayerDominated.cpp @@ -0,0 +1,20 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayerShared_IsPlayerDominated, "client.dll", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 63 F2 48 8B D9 E8", 0x0); +MAKE_SIGNATURE(CTFPlayerShared_IsPlayerDominated_Desired, "client.dll", "84 C0 74 ? 40 84 ED 74 ? 45 8B 86", 0x0); +MAKE_SIGNATURE(CTFPlayerShared_IsPlayerDominated_Jump, "client.dll", "8B F0 E8 ? ? ? ? 3B C7", 0x0); + +MAKE_HOOK(CTFPlayerShared_IsPlayerDominated, S::CTFPlayerShared_IsPlayerDominated(), bool, __fastcall, + void* ecx, int index) +{ + static auto dwDesired = S::CTFPlayerShared_IsPlayerDominated_Desired(); + static auto dwJump = S::CTFPlayerShared_IsPlayerDominated_Jump(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + const bool bResult = CALL_ORIGINAL(ecx, index); + + if (dwRetAddr == dwDesired && Vars::Visuals::UI::RevealScoreboard.Value && !bResult) + *static_cast(_AddressOfReturnAddress()) = dwJump; + + return bResult; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayer_AvoidPlayers.cpp b/Amalgam/src/Hooks/CTFPlayer_AvoidPlayers.cpp new file mode 100644 index 0000000..43526a2 --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayer_AvoidPlayers.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayer_AvoidPlayers, "client.dll", "48 89 54 24 ? 55 41 56", 0x0); + +MAKE_HOOK(CTFPlayer_AvoidPlayers, S::CTFPlayer_AvoidPlayers(), void, __fastcall, + void* ecx, CUserCmd* pCmd) +{ + if (Vars::Misc::Movement::NoPush.Value) + return; + + CALL_ORIGINAL(ecx, pCmd); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayer_BRenderAsZombie.cpp b/Amalgam/src/Hooks/CTFPlayer_BRenderAsZombie.cpp new file mode 100644 index 0000000..1da6b50 --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayer_BRenderAsZombie.cpp @@ -0,0 +1,16 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayer_BRenderAsZombie, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B D9 B9 ? ? ? ? E8 ? ? ? ? 84 C0", 0x0); +MAKE_SIGNATURE(CTFRagdoll_CreateTFRagdoll_Call, "client.dll", "E8 ? ? ? ? 84 C0 74 ? C6 87", 0x5); + +MAKE_HOOK(CTFPlayer_BRenderAsZombie, S::CTFPlayer_BRenderAsZombie(), bool, __fastcall, + void* ecx, bool bWeaponsCheck) +{ + static auto dwDesired = S::CTFRagdoll_CreateTFRagdoll_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (Vars::Visuals::Ragdolls::NoGib.Value && dwRetAddr == dwDesired) + return true; + + return CALL_ORIGINAL(ecx, bWeaponsCheck); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFPlayer_IsPlayerClass.cpp b/Amalgam/src/Hooks/CTFPlayer_IsPlayerClass.cpp new file mode 100644 index 0000000..8482bf3 --- /dev/null +++ b/Amalgam/src/Hooks/CTFPlayer_IsPlayerClass.cpp @@ -0,0 +1,16 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFPlayer_IsPlayerClass, "client.dll", "48 81 C1 ? ? ? ? 75 ? 32 C0", 0x0); +MAKE_SIGNATURE(CTFPlayer_IsPlayerClass_Desired, "client.dll", "84 C0 0F 84 ? ? ? ? 48 8B 06 48 8B CE FF 90 ? ? ? ? 49 8B 16", 0x0); + +MAKE_HOOK(CTFPlayer_IsPlayerClass, S::CTFPlayer_IsPlayerClass(), bool, __fastcall, + void* ecx, int iClass) +{ + static const auto dwDesired = S::CTFPlayer_IsPlayerClass_Desired(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (Vars::Misc::Sound::HitsoundAlways.Value && dwRetAddr == dwDesired) + return false; + + return CALL_ORIGINAL(ecx, iClass); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFRagdoll_CreateTFRagdoll.cpp b/Amalgam/src/Hooks/CTFRagdoll_CreateTFRagdoll.cpp new file mode 100644 index 0000000..bf73efc --- /dev/null +++ b/Amalgam/src/Hooks/CTFRagdoll_CreateTFRagdoll.cpp @@ -0,0 +1,52 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFRagdoll_CreateTFRagdoll, "client.dll", "48 89 4C 24 ? 55 53 56 57 48 8D AC 24 ? ? ? ? B8 ? ? ? ? E8 ? ? ? ? 48 2B E0 8B 91", 0x0); + +#define Offset(type, ent, offset) *reinterpret_cast(ent + offset) + +void ClearEffects(CBaseEntity* pEntity) +{ + Offset(bool*, pEntity, 4273) = false; // Gib + Offset(bool*, pEntity, 4274) = false; // Burning + Offset(bool*, pEntity, 4275) = false; // Electrocuted + Offset(bool*, pEntity, 4277) = false; // Dissolve + Offset(bool*, pEntity, 4281) = false; // Ash + Offset(bool*, pEntity, 4288) = false; // Gold + Offset(bool*, pEntity, 4289) = false; // Ice +} + +MAKE_HOOK(CTFRagdoll_CreateTFRagdoll, S::CTFRagdoll_CreateTFRagdoll(), void, __fastcall, + void* ecx) +{ + if (Vars::Visuals::Ragdolls::NoRagdolls.Value) + return; + + if (!Vars::Visuals::Ragdolls::Enabled.Value) + return CALL_ORIGINAL(ecx); + + if (auto pEntity = static_cast(ecx)) + { + if (Vars::Visuals::Ragdolls::EnemyOnly.Value) + { + auto pLocal = H::Entities.GetLocal(); + if (pLocal && Offset(int*, pEntity, 4208) == pLocal->m_iTeamNum()) // Team offset + return CALL_ORIGINAL(ecx); + } + + ClearEffects(pEntity); + + Offset(bool*, pEntity, 4274) = Vars::Visuals::Ragdolls::Effects.Value & (1 << 0); + Offset(bool*, pEntity, 4275) = Vars::Visuals::Ragdolls::Effects.Value & (1 << 1); + Offset(bool*, pEntity, 4281) = Vars::Visuals::Ragdolls::Effects.Value & (1 << 2); + Offset(bool*, pEntity, 4277) = Vars::Visuals::Ragdolls::Effects.Value & (1 << 3); + Offset(bool*, pEntity, 4288) = Vars::Visuals::Ragdolls::Type.Value == 1; + Offset(bool*, pEntity, 4289) = Vars::Visuals::Ragdolls::Type.Value == 2; + + pEntity->m_vecForce() *= Vars::Visuals::Ragdolls::Force.Value; + pEntity->m_vecForce().x *= Vars::Visuals::Ragdolls::ForceHorizontal.Value; + pEntity->m_vecForce().y *= Vars::Visuals::Ragdolls::ForceHorizontal.Value; + pEntity->m_vecForce().z *= Vars::Visuals::Ragdolls::ForceVertical.Value; + } + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp b/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp new file mode 100644 index 0000000..fd360d7 --- /dev/null +++ b/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp @@ -0,0 +1,21 @@ +#include "../SDK/SDK.h" +#include "../Features/CritHack/CritHack.h" + +MAKE_SIGNATURE(CTFWeaponBase_CalcIsAttackCritical, "client.dll", "48 89 74 24 ? 57 48 83 EC ? 48 8B F9 E8 ? ? ? ? 48 8B C8 C7 44 24 ? ? ? ? ? 4C 8D 0D ? ? ? ? 33 D2 4C 8D 05 ? ? ? ? E8 ? ? ? ? 48 8B F0 48 85 C0 0F 84 ? ? ? ? 48 8B 10", 0x0); + +MAKE_HOOK(CTFWeaponBase_CalcIsAttackCritical, S::CTFWeaponBase_CalcIsAttackCritical(), void, __fastcall, + void* ecx) +{ + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + if (!pLocal || !pWeapon || pWeapon != ecx) + CALL_ORIGINAL(ecx); + + if (!F::CritHack.CalcIsAttackCriticalHandler(pLocal, pWeapon)) + return; + + const auto nPreviousWeaponMode = pWeapon->m_iWeaponMode(); + pWeapon->m_iWeaponMode() = 0; + CALL_ORIGINAL(ecx); + pWeapon->m_iWeaponMode() = nPreviousWeaponMode; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CTFWeaponBase_GetShootSound.cpp b/Amalgam/src/Hooks/CTFWeaponBase_GetShootSound.cpp new file mode 100644 index 0000000..e0909a3 --- /dev/null +++ b/Amalgam/src/Hooks/CTFWeaponBase_GetShootSound.cpp @@ -0,0 +1,36 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFWeaponBase_GetShootSound, "client.dll", "40 55 56 41 56 48 83 EC ? 80 B9", 0x0); + +MAKE_HOOK(CTFWeaponBase_GetShootSound, S::CTFWeaponBase_GetShootSound(), const char*, __fastcall, + void* ecx, int iIndex) +{ + if (Vars::Misc::Sound::GiantWeaponSounds.Value) + { + auto pWeapon = reinterpret_cast(ecx); + auto pOwner = pWeapon ? I::ClientEntityList->GetClientEntityFromHandle(pWeapon->m_hOwnerEntity()) : nullptr; + auto pLocal = H::Entities.GetLocal(); + if (pWeapon && pOwner == pLocal) + { + int nOldTeam = pWeapon->m_iTeamNum(); + pWeapon->m_iTeamNum() = 4; + auto ret = CALL_ORIGINAL(ecx, iIndex); + pWeapon->m_iTeamNum() = nOldTeam; + + // credits: KGB + + if (FNV1A::Hash(ret) == FNV1A::HashConst("Weapon_FlameThrower.Fire")) + return "MVM.GiantPyro_FlameStart"; + + if (FNV1A::Hash(ret) == FNV1A::HashConst("Weapon_FlameThrower.FireLoop")) + return "MVM.GiantPyro_FlameLoop"; + + if (FNV1A::Hash(ret) == FNV1A::HashConst("Weapon_GrenadeLauncher.Single")) + return "MVM.GiantDemoman_Grenadeshoot"; + + return ret; + } + } + + return CALL_ORIGINAL(ecx, iIndex); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/CViewRender_DrawUnderwaterOverlay.cpp b/Amalgam/src/Hooks/CViewRender_DrawUnderwaterOverlay.cpp new file mode 100644 index 0000000..b1afccb --- /dev/null +++ b/Amalgam/src/Hooks/CViewRender_DrawUnderwaterOverlay.cpp @@ -0,0 +1,10 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CViewRender_DrawUnderwaterOverlay, "client.dll", "4C 8B DC 41 56 48 81 EC ? ? ? ? 4C 8B B1", 0x0); + +MAKE_HOOK(CViewRender_DrawUnderwaterOverlay, S::CViewRender_DrawUnderwaterOverlay(), void, __fastcall, + void* eax) +{ + if (!Vars::Visuals::Removals::ScreenOverlays.Value || Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + CALL_ORIGINAL(eax); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientModeShared_CreateMove.cpp b/Amalgam/src/Hooks/ClientModeShared_CreateMove.cpp new file mode 100644 index 0000000..16832fe --- /dev/null +++ b/Amalgam/src/Hooks/ClientModeShared_CreateMove.cpp @@ -0,0 +1,126 @@ +#include "../SDK/SDK.h" +#include "../Features/Aimbot/Aimbot.h" +#include "../Features/Aimbot/AimbotProjectile/AimbotProjectile.h" +#include "../Features/Backtrack/Backtrack.h" +#include "../Features/CritHack/CritHack.h" +#include "../Features/EnginePrediction/EnginePrediction.h" +#include "../Features/Misc/Misc.h" +#include "../Features/NoSpread/NoSpread.h" +#include "../Features/PacketManip/PacketManip.h" +#include "../Features/Resolver/Resolver.h" +#include "../Features/TickHandler/TickHandler.h" +#include "../Features/Visuals/Visuals.h" +#include "../Features/Visuals/FakeAngle/FakeAngle.h" + +MAKE_HOOK(ClientModeShared_CreateMove, U::Memory.GetVFunc(I::ClientModeShared, 21), bool, __fastcall, + CClientModeShared* ecx, float flInputSampleTime, CUserCmd* pCmd) +{ + G::PSilentAngles = G::SilentAngles = G::IsAttacking = false; + G::Buttons = pCmd ? pCmd->buttons : G::Buttons; + const bool bReturn = CALL_ORIGINAL(ecx, flInputSampleTime, pCmd); + if (!pCmd || !pCmd->command_number) + return bReturn; + + auto ebp = *reinterpret_cast(uintptr_t(_AddressOfReturnAddress()) - sizeof(void*)); + bool* pSendPacket = reinterpret_cast(ebp + 0xA7); + + I::Prediction->Update(I::ClientState->m_nDeltaTick, I::ClientState->m_nDeltaTick > 0, I::ClientState->last_command_ack, I::ClientState->lastoutgoingcommand + I::ClientState->chokedcommands); + + G::CurrentUserCmd = pCmd; + if (!G::LastUserCmd) + G::LastUserCmd = pCmd; + + // correct tick_count for fakeinterp / nointerp + pCmd->tick_count += TICKS_TO_TIME(F::Backtrack.flFakeInterp) - (Vars::Visuals::Removals::Interpolation.Value ? 0 : TICKS_TO_TIME(G::Lerp)); + if (G::Buttons & IN_DUCK) // lol + pCmd->buttons |= IN_DUCK; + + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + if (pLocal && pWeapon) + { // Update Global Info + int nOldDefIndex = G::WeaponDefIndex; + G::WeaponDefIndex = pWeapon->m_iItemDefinitionIndex(); + if (G::WeaponDefIndex != nOldDefIndex || !pWeapon->m_iClip1() || !pLocal->IsAlive() || pLocal->IsTaunting() || pLocal->IsBonked() || pLocal->IsAGhost() || pLocal->IsInBumperKart()) + G::WaitForShift = 1; + + bool bCanAttack = pLocal->CanAttack() && (pWeapon->m_iWeaponID() == TF_WEAPON_FLAME_BALL ? pLocal->m_flTankPressure() >= 100.f : true); + G::CanPrimaryAttack = bCanAttack && pWeapon->CanPrimaryAttack(pLocal); + G::CanSecondaryAttack = bCanAttack && pWeapon->CanSecondaryAttack(pLocal); + switch (SDK::GetRoundState()) + { + case GR_STATE_BETWEEN_RNDS: + case GR_STATE_GAME_OVER: + if (pLocal->m_fFlags() & FL_FROZEN) + G::CanPrimaryAttack = G::CanSecondaryAttack = false; + } + if (pWeapon->m_iSlot() != SLOT_MELEE) + { + if (pWeapon->IsInReload()) + G::CanPrimaryAttack = pWeapon->HasPrimaryAmmoForShot(); + + if (pWeapon->m_iWeaponID() == TF_WEAPON_MINIGUN && pWeapon->As()->m_iWeaponState() != AC_STATE_FIRING && pWeapon->As()->m_iWeaponState() != AC_STATE_SPINNING) + G::CanPrimaryAttack = false; + + if (pWeapon->m_iWeaponID() == TF_WEAPON_FLAREGUN_REVENGE && pCmd->buttons & IN_ATTACK2) + G::CanPrimaryAttack = false; + + if (pWeapon->m_bEnergyWeapon() && !pWeapon->m_flEnergy()) + G::CanPrimaryAttack = false; + + if (G::WeaponDefIndex != Soldier_m_TheBeggarsBazooka && pWeapon->m_iClip1() == 0) + G::CanPrimaryAttack = false; + } + + G::IsAttacking = SDK::IsAttacking(pLocal, pWeapon, pCmd); + G::WeaponType = SDK::GetWeaponType(pWeapon); + G::CanHeadshot = pWeapon->CanHeadShot(pLocal); + } + + const bool bSkip = F::AimbotProjectile.bLastTickCancel; + if (bSkip) + { + pCmd->weaponselect = F::AimbotProjectile.bLastTickCancel; + F::AimbotProjectile.bLastTickCancel = 0; + } + + // Run Features + F::Misc.RunPre(pLocal, pCmd); + F::Backtrack.Run(pCmd); + + F::EnginePrediction.Start(pLocal, pCmd); + { + const bool bAimRan = bSkip ? false : F::Aimbot.Run(pLocal, pWeapon, pCmd); + if (!bAimRan && G::CanPrimaryAttack && G::IsAttacking && !F::AimbotProjectile.bLastTickCancel) + F::Visuals.ProjectileTrace(pLocal, pWeapon, false); + } + F::EnginePrediction.End(pLocal, pCmd); + + F::PacketManip.Run(pLocal, pCmd, pSendPacket); + F::Ticks.MovePost(pLocal, pCmd); + F::CritHack.Run(pLocal, pWeapon, pCmd); + F::NoSpread.Run(pLocal, pWeapon, pCmd); + F::Misc.RunPost(pLocal, pCmd, *pSendPacket); + F::Resolver.CreateMove(); + + { + static bool bWasSet = false; + const bool bOverchoking = I::ClientState->chokedcommands >= 21; // failsafe + if (G::PSilentAngles && G::ShiftedTicks != G::MaxShift && !bOverchoking) + *pSendPacket = false, bWasSet = true; + else if (bWasSet || bOverchoking) + *pSendPacket = true, bWasSet = false; + } + F::Misc.DoubletapPacket(pCmd, pSendPacket); + F::AntiAim.Run(pLocal, pCmd, pSendPacket); + G::Choking = !*pSendPacket; + if (*pSendPacket) + F::FakeAngle.Run(pLocal); + + G::ViewAngles = pCmd->viewangles; + G::LastUserCmd = pCmd; + + //const bool bShouldSkip = G::PSilentAngles || G::SilentAngles || G::AntiAim || G::AvoidingBackstab; + //return bShouldSkip ? false : CALL_ORIGINAL(ecx, edx, input_sample_frametime, pCmd); + return false; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientModeShared_DoPostScreenSpaceEffects.cpp b/Amalgam/src/Hooks/ClientModeShared_DoPostScreenSpaceEffects.cpp new file mode 100644 index 0000000..710852c --- /dev/null +++ b/Amalgam/src/Hooks/ClientModeShared_DoPostScreenSpaceEffects.cpp @@ -0,0 +1,39 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Chams/Chams.h" +#include "../Features/Visuals/Glow/Glow.h" +#include "../Features/CameraWindow/CameraWindow.h" +#include "../Features/Visuals/Visuals.h" + +MAKE_HOOK(ClientModeShared_DoPostScreenSpaceEffects, U::Memory.GetVFunc(I::ClientModeShared, 39), bool, __fastcall, + void* ecx, const CViewSetup* pSetup) +{ + F::Chams.mEntities.clear(); + if (I::EngineVGui->IsGameUIVisible() || Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + return CALL_ORIGINAL(ecx, pSetup); + + static std::once_flag onceFlag; + std::call_once(onceFlag, [] + { + F::Glow.Init(); + F::CameraWindow.Init(); + }); + + F::Visuals.DrawBoxes(); + F::Visuals.DrawBulletLines(); + F::Visuals.DrawSimLines(); + F::Visuals.DrawSightlines(); + + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + if (pLocal) + { + F::Chams.RenderMain(pLocal); + F::Glow.RenderMain(pLocal); + + if (pWeapon) + F::Visuals.ProjectileTrace(pLocal, pWeapon); + } + + return CALL_ORIGINAL(ecx, pSetup); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientModeShared_OverrideView.cpp b/Amalgam/src/Hooks/ClientModeShared_OverrideView.cpp new file mode 100644 index 0000000..712ccca --- /dev/null +++ b/Amalgam/src/Hooks/ClientModeShared_OverrideView.cpp @@ -0,0 +1,18 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Visuals.h" + +MAKE_HOOK(ClientModeShared_OverrideView, U::Memory.GetVFunc(I::ClientModeShared, 16), void, __fastcall, + void* ecx, CViewSetup* pView) +{ + CALL_ORIGINAL(ecx, pView); + if (Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + return; + + auto pLocal = H::Entities.GetLocal(); + if (pLocal && pView) + { + F::Visuals.FOV(pLocal, pView); + F::Visuals.ThirdPerson(pLocal, pView); + } +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientModeShared_ShouldDrawViewModel.cpp b/Amalgam/src/Hooks/ClientModeShared_ShouldDrawViewModel.cpp new file mode 100644 index 0000000..39dbdbf --- /dev/null +++ b/Amalgam/src/Hooks/ClientModeShared_ShouldDrawViewModel.cpp @@ -0,0 +1,15 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Visuals.h" + +MAKE_HOOK(ClientModeShared_ShouldDrawViewModel, U::Memory.GetVFunc(I::ClientModeShared, 24), bool, __fastcall, + void* ecx) +{ + if (auto pLocal = H::Entities.GetLocal()) + { + if (pLocal->IsScoped() && Vars::Visuals::Removals::Scope.Value && Vars::Visuals::UI::ZoomFieldOfView.Value > 70 && !I::Input->CAM_IsThirdPerson()) + return true; + } + + return CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientModeTFNormal_UpdateSteamRichPresence.cpp b/Amalgam/src/Hooks/ClientModeTFNormal_UpdateSteamRichPresence.cpp new file mode 100644 index 0000000..1a77434 --- /dev/null +++ b/Amalgam/src/Hooks/ClientModeTFNormal_UpdateSteamRichPresence.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +#include "../Features/Misc/Misc.h" + +MAKE_SIGNATURE(ClientModeTFNormal_UpdateSteamRichPresence, "client.dll", "4C 8B DC 41 54 41 55 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 45 33 ED 49 89 5B ? 48 8B D9", 0x0); + +MAKE_HOOK(ClientModeTFNormal_UpdateSteamRichPresence, S::ClientModeTFNormal_UpdateSteamRichPresence(), void, __fastcall, + void* ecx) +{ + if (!F::Misc.SteamRPC()) + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientState_GetClientInterpAmount.cpp b/Amalgam/src/Hooks/ClientState_GetClientInterpAmount.cpp new file mode 100644 index 0000000..51f0650 --- /dev/null +++ b/Amalgam/src/Hooks/ClientState_GetClientInterpAmount.cpp @@ -0,0 +1,10 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(ClientState_GetClientInterpAmount, "engine.dll", "48 83 EC ? 48 8B 0D ? ? ? ? 48 85 C9 75", 0x0); + +MAKE_HOOK(ClientState_GetClientInterpAmount, S::ClientState_GetClientInterpAmount(), float, __fastcall, + CClientState* ecx) +{ + G::Lerp = CALL_ORIGINAL(ecx); + return Vars::Visuals::Removals::Interpolation.Value ? 0.f : G::Lerp; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ClientState_ProcessFixAngle.cpp b/Amalgam/src/Hooks/ClientState_ProcessFixAngle.cpp new file mode 100644 index 0000000..729d9d3 --- /dev/null +++ b/Amalgam/src/Hooks/ClientState_ProcessFixAngle.cpp @@ -0,0 +1,9 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(ClientState_ProcessFixAngle, "engine.dll", "40 53 48 83 EC ? F3 0F 10 42", 0x0); + +MAKE_HOOK(ClientState_ProcessFixAngle, S::ClientState_ProcessFixAngle(), bool, __fastcall, + CClientState* ecx, SVC_FixAngle* msg) +{ + return Vars::Visuals::Removals::AngleForcing.Value ? false : CALL_ORIGINAL(ecx, msg); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/DSP_Process.cpp b/Amalgam/src/Hooks/DSP_Process.cpp new file mode 100644 index 0000000..7b7fe5d --- /dev/null +++ b/Amalgam/src/Hooks/DSP_Process.cpp @@ -0,0 +1,10 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(DSP_Process, "engine.dll", "48 89 5C 24 ? 55 41 54 41 57 48 83 EC ? 48 63 D9", 0x0); + +MAKE_HOOK(DSP_Process, S::DSP_Process(), void, __cdecl, + unsigned int idsp, int* pbfront, int* pbrear, int* pbcenter, int sampleCount) +{ + if (!Vars::Visuals::Removals::DSP.Value) + CALL_ORIGINAL(idsp, pbfront, pbrear, pbcenter, sampleCount); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/Direct3DDevice9_EndScene.cpp b/Amalgam/src/Hooks/Direct3DDevice9_EndScene.cpp new file mode 100644 index 0000000..0403333 --- /dev/null +++ b/Amalgam/src/Hooks/Direct3DDevice9_EndScene.cpp @@ -0,0 +1,107 @@ +#include "Direct3DDevice9_EndScene.h" + +#include "../SDK/SDK.h" +#include "../Features/ImGui/Render.h" +#include "../Features/ImGui/Menu/Menu.h" + +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +MAKE_HOOK(Direct3DDevice9_EndScene, U::Memory.GetVFunc(I::DirectXDevice, 42), HRESULT, __stdcall, + LPDIRECT3DDEVICE9 pDevice) +{ + static void* fRegularAddr = 0, *fOverlayAddr = 0; + if (!fRegularAddr || !fOverlayAddr) + { + MEMORY_BASIC_INFORMATION info; + VirtualQuery(_ReturnAddress(), &info, sizeof(MEMORY_BASIC_INFORMATION)); + + char mod[MAX_PATH]; + GetModuleFileNameA((HMODULE)info.AllocationBase, mod, MAX_PATH); + + if (strstr(mod, "\\shaderapi")) + fRegularAddr = _ReturnAddress(); + else + fOverlayAddr = _ReturnAddress(); + } + + // proof of concept, frankly would like to keep surface in use + //if (!Vars::Visuals::AntiOBS.Value ? (fRegularAddr && fRegularAddr != _ReturnAddress()) : (fOverlayAddr && fOverlayAddr != _ReturnAddress())) + if (G::Unload || fRegularAddr && fRegularAddr != _ReturnAddress()) + return CALL_ORIGINAL(pDevice); + + F::Render.Render(pDevice); + + return CALL_ORIGINAL(pDevice); +} + +MAKE_HOOK(Direct3DDevice9_Reset, U::Memory.GetVFunc(I::DirectXDevice, 16), HRESULT, __stdcall, + LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters) +{ + ImGui_ImplDX9_InvalidateDeviceObjects(); + const HRESULT Original = CALL_ORIGINAL(pDevice, pPresentationParameters); + ImGui_ImplDX9_CreateDeviceObjects(); + return Original; +} + +LONG __stdcall WndProc::Func(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (F::Menu.IsOpen) + { + ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam); + if (ImGui::GetIO().WantTextInput || F::Menu.InKeybind) + { + I::InputSystem->ResetInputState(); + return 1; + } + + if (uMsg >= WM_MOUSEFIRST && WM_MOUSELAST >= uMsg) + return 1; + } + + return CallWindowProc(Original, hWnd, uMsg, wParam, lParam); +} + +MAKE_HOOK(VGuiSurface_LockCursor, U::Memory.GetVFunc(I::MatSystemSurface, 62), void, __fastcall, + void* ecx) +{ + if (F::Menu.IsOpen) + return I::MatSystemSurface->UnlockCursor(); + + CALL_ORIGINAL(ecx); +} + +MAKE_HOOK(VGuiSurface_SetCursor, U::Memory.GetVFunc(I::MatSystemSurface, 51), void, __fastcall, + void* ecx, HCursor cursor) +{ + if (F::Menu.IsOpen) + { + switch (F::Render.Cursor) + { + case 0: cursor = 2; break; + case 1: cursor = 3; break; + case 2: cursor = 12; break; + case 3: cursor = 11; break; + case 4: cursor = 10; break; + case 5: cursor = 9; break; + case 6: cursor = 8; break; + case 7: cursor = 14; break; + case 8: cursor = 13; break; + } + return CALL_ORIGINAL(ecx, cursor); + } + + CALL_ORIGINAL(ecx, cursor); +} + +void WndProc::Initialize() +{ + while (!hwWindow) + hwWindow = SDK::GetTeamFortressWindow(); + + Original = reinterpret_cast(SetWindowLongPtr(hwWindow, GWLP_WNDPROC, reinterpret_cast(Func))); +} + +void WndProc::Unload() +{ + SetWindowLongPtr(hwWindow, GWLP_WNDPROC, reinterpret_cast(Original)); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/Direct3DDevice9_EndScene.h b/Amalgam/src/Hooks/Direct3DDevice9_EndScene.h new file mode 100644 index 0000000..656f92b --- /dev/null +++ b/Amalgam/src/Hooks/Direct3DDevice9_EndScene.h @@ -0,0 +1,12 @@ +#pragma once +#include + +namespace WndProc +{ + inline HWND hwWindow; + inline WNDPROC Original; + LONG __stdcall Func(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + void Initialize(); + void Unload(); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/DoEnginePostProcessing.cpp b/Amalgam/src/Hooks/DoEnginePostProcessing.cpp new file mode 100644 index 0000000..eebf3b0 --- /dev/null +++ b/Amalgam/src/Hooks/DoEnginePostProcessing.cpp @@ -0,0 +1,10 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(DoEnginePostProcessing, "client.dll", "48 8B C4 44 89 48 ? 44 89 40 ? 89 50 ? 89 48", 0x0); + +MAKE_HOOK(DoEnginePostProcessing, S::DoEnginePostProcessing(), void, __cdecl, + int x, int y, int w, int h, bool bFlashlightIsOn, bool bPostVGui) +{ + if (!Vars::Visuals::Removals::PostProcessing.Value || Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + CALL_ORIGINAL(x, y, w, h, bFlashlightIsOn, bPostVGui); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/EngineClient_ClientCmd_Unrestricted.cpp b/Amalgam/src/Hooks/EngineClient_ClientCmd_Unrestricted.cpp new file mode 100644 index 0000000..5cf7f15 --- /dev/null +++ b/Amalgam/src/Hooks/EngineClient_ClientCmd_Unrestricted.cpp @@ -0,0 +1,40 @@ +#include "../SDK/SDK.h" + +#include "../Features/Commands/Commands.h" +#include + +class split_q +{ +public: + split_q() : in_q(false) {} + + bool operator()(char ch) const + { + if (ch == '\"') + { + in_q = !in_q; + } + return !in_q && ch == ' '; + } + +private: + mutable bool in_q; +}; + +MAKE_HOOK(EngineClient_ClientCmd_Unrestricted, U::Memory.GetVFunc(I::EngineClient, 106), void, __fastcall, + void* ecx, const char* szCmdString) +{ + std::string cmdString = szCmdString; + std::deque cmdArgs; + boost::split(cmdArgs, cmdString, split_q()); + if (!cmdArgs.empty()) + { + const std::string cmdName = cmdArgs.front(); + cmdArgs.pop_front(); + + if (F::Commands.Run(cmdName, cmdArgs)) + return; + } + + CALL_ORIGINAL(ecx, cmdString.c_str()); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/EngineVGui_Paint.cpp b/Amalgam/src/Hooks/EngineVGui_Paint.cpp new file mode 100644 index 0000000..90a1e4e --- /dev/null +++ b/Amalgam/src/Hooks/EngineVGui_Paint.cpp @@ -0,0 +1,55 @@ +#include "../SDK/SDK.h" +#include "../Features/CameraWindow/CameraWindow.h" +#include "../Features/CritHack/CritHack.h" +#include "../Features/Visuals/ESP/ESP.h" +#include "../Features/Visuals/Notifications/Notifications.h" +#include "../Features/Visuals/PlayerArrows/PlayerArrows.h" +#include "../Features/Visuals/Radar/Radar.h" +#include "../Features/Visuals/SpectatorList/SpectatorList.h" +#include "../Features/Visuals/Visuals.h" + +void Paint() +{ + H::Draw.UpdateW2SMatrix(); + H::Draw.UpdateScreenSize(); + + I::MatSystemSurface->StartDrawing(); + { + if (Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()) + return I::MatSystemSurface->FinishDrawing(); + + F::Notifications.Draw(); + + auto pLocal = H::Entities.GetLocal(); + if (I::EngineVGui->IsGameUIVisible() || !pLocal) + return I::MatSystemSurface->FinishDrawing(); + + F::CameraWindow.Draw(); + F::Visuals.DrawServerHitboxes(pLocal); + F::Visuals.DrawAntiAim(pLocal); + + F::Visuals.PickupTimers(); + F::ESP.Run(pLocal); + F::PlayerArrows.Run(pLocal); + F::Radar.Run(pLocal); + + F::Visuals.DrawAimbotFOV(pLocal); + F::Visuals.DrawSeedPrediction(pLocal); + F::Visuals.DrawOnScreenConditions(pLocal); + F::Visuals.DrawOnScreenPing(pLocal); + F::SpectatorList.Run(pLocal); + F::CritHack.Draw(pLocal); + F::Visuals.DrawTickbaseText(pLocal); + F::Visuals.DrawDebugInfo(pLocal); + } + I::MatSystemSurface->FinishDrawing(); +} + +MAKE_HOOK(EngineVGui_Paint, U::Memory.GetVFunc(I::EngineVGui, 14), void, __fastcall, + void* ecx, int iMode) +{ + CALL_ORIGINAL(ecx, iMode); + + if (iMode & PAINT_UIPANELS) + Paint(); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/FX_FireBullets.cpp b/Amalgam/src/Hooks/FX_FireBullets.cpp new file mode 100644 index 0000000..b4d9d2b --- /dev/null +++ b/Amalgam/src/Hooks/FX_FireBullets.cpp @@ -0,0 +1,29 @@ +#include "../SDK/SDK.h" + +#include "../Features/Backtrack/Backtrack.h" +#include "../Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h" +#include "../Features/Resolver/Resolver.h" + +MAKE_SIGNATURE(FX_FireBullets, "client.dll", "48 89 5C 24 ? 48 89 74 24 ? 4C 89 4C 24 ? 55", 0x0); +MAKE_SIGNATURE(CTFWeaponBaseGun_FireBullet_Call, "client.dll", "0F 28 7C 24 ? 4C 8D 9C 24 ? ? ? ? 49 8B 5B ? 49 8B 6B ? 49 8B 73 ? 41 0F 28 73 ? 49 8B E3", 0x0); + +MAKE_HOOK(FX_FireBullets, S::FX_FireBullets(), void, __cdecl, + void* pWpn, int iPlayer, const Vec3& vecOrigin, const Vec3& vecAngles, int iWeapon, int iMode, int iSeed, float flSpread, float flDamage, bool bCritical) +{ + static auto dwDesired = S::CTFWeaponBaseGun_FireBullet_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (iPlayer != I::EngineClient->GetLocalPlayer()) + { + F::Backtrack.ReportShot(iPlayer); + F::Resolver.FXFireBullet(iPlayer, vecAngles); + } + + if (dwRetAddr != dwDesired) + return; + + if (Vars::Aimbot::General::NoSpread.Value) + iSeed = F::NoSpreadHitscan.iSeed; + + return CALL_ORIGINAL(pWpn, iPlayer, vecOrigin, vecAngles, iWeapon, iMode, iSeed, flSpread, flDamage, bCritical); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/GetClientInterpAmount.cpp b/Amalgam/src/Hooks/GetClientInterpAmount.cpp new file mode 100644 index 0000000..885039c --- /dev/null +++ b/Amalgam/src/Hooks/GetClientInterpAmount.cpp @@ -0,0 +1,13 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(GetClientInterpAmount, "client.dll", "40 53 48 83 EC ? 8B 05 ? ? ? ? A8 ? 75 ? 48 8B 0D ? ? ? ? 48 8D 15", 0x0); +MAKE_SIGNATURE(CNetGraphPanel_DrawTextFields_Call, "client.dll", "F3 41 0F 59 C1 4C 8D 05", 0x0); + +MAKE_HOOK(GetClientInterpAmount, S::GetClientInterpAmount(), float, __cdecl, + ) +{ + static auto dwDesired = S::CNetGraphPanel_DrawTextFields_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + return dwRetAddr == dwDesired ? CALL_ORIGINAL() : 0.f; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ISteamNetworkingUtils_GetDirectPingToPOP.cpp b/Amalgam/src/Hooks/ISteamNetworkingUtils_GetDirectPingToPOP.cpp new file mode 100644 index 0000000..7551ef3 --- /dev/null +++ b/Amalgam/src/Hooks/ISteamNetworkingUtils_GetDirectPingToPOP.cpp @@ -0,0 +1,105 @@ +#include "../SDK/SDK.h" + +/* +const std::unordered_map DATA_CENTER_HASH +{ + { "atl", DC_ATL }, + { "ord", DC_ORD }, + { "dfw", DC_DFW }, + { "lax", DC_LAX }, + { "eat", DC_EAT }, + { "jfk", DC_JFK }, + { "sea", DC_SEA }, + { "iad", DC_IAD }, + { "ams", DC_AMS }, + { "fra", DC_FRA }, + { "hel", DC_HEL }, + { "lhr", DC_LHR }, + { "mad", DC_MAD }, + { "par", DC_PAR }, + { "sto", DC_STO }, + { "sto2", DC_STO }, + { "vie", DC_VIE }, + { "waw", DC_WAW }, + { "eze", DC_EZE }, + { "lim", DC_LIM }, + { "scl", DC_SCL }, + { "gru", DC_GRU }, + { "bom2", DC_BOM2 }, + { "maa", DC_MAA }, + { "dxb", DC_DXB }, + { "hkg", DC_HKG }, + { "maa2", DC_MAA2 }, + { "bom", DC_BOM }, + { "seo", DC_SEO }, + { "sgp", DC_SGP }, + { "tyo", DC_TYO }, + { "syd", DC_SYD }, + { "jnb", DC_JNB } +}; +*/ + +void POPID_ToString(SteamNetworkingPOPID popID, char* out) +{ + out[0] = static_cast(popID >> 16); + out[1] = static_cast(popID >> 8); + out[2] = static_cast(popID); + out[3] = static_cast(popID >> 24); + out[4] = 0; +} + +unsigned int GetDatacenter(FNV1A_t uHash) +{ + switch (uHash) + { + case FNV1A::HashConst("atl"): return DC_ATL; + case FNV1A::HashConst("ord"): return DC_ORD; + case FNV1A::HashConst("dfw"): return DC_DFW; + case FNV1A::HashConst("lax"): return DC_LAX; + case FNV1A::HashConst("eat"): return DC_EAT; + case FNV1A::HashConst("jfk"): return DC_JFK; + case FNV1A::HashConst("sea"): return DC_SEA; + case FNV1A::HashConst("iad"): return DC_IAD; + case FNV1A::HashConst("ams"): return DC_AMS; + case FNV1A::HashConst("fra"): return DC_FRA; + case FNV1A::HashConst("hel"): return DC_HEL; + case FNV1A::HashConst("lhr"): return DC_LHR; + case FNV1A::HashConst("mad"): return DC_MAD; + case FNV1A::HashConst("par"): return DC_PAR; + case FNV1A::HashConst("sto"): return DC_STO; + case FNV1A::HashConst("sto2"): return DC_STO; + case FNV1A::HashConst("vie"): return DC_VIE; + case FNV1A::HashConst("waw"): return DC_WAW; + case FNV1A::HashConst("eze"): return DC_EZE; + case FNV1A::HashConst("lim"): return DC_LIM; + case FNV1A::HashConst("scl"): return DC_SCL; + case FNV1A::HashConst("gru"): return DC_GRU; + case FNV1A::HashConst("bom2"): return DC_BOM2; + case FNV1A::HashConst("maa"): return DC_MAA; + case FNV1A::HashConst("dxb"): return DC_DXB; + case FNV1A::HashConst("hkg"): return DC_HKG; + case FNV1A::HashConst("maa2"): return DC_MAA2; + case FNV1A::HashConst("bom"): return DC_BOM; + case FNV1A::HashConst("seo"): return DC_SEO; + case FNV1A::HashConst("sgp"): return DC_SGP; + case FNV1A::HashConst("tyo"): return DC_TYO; + case FNV1A::HashConst("syd"): return DC_SYD; + case FNV1A::HashConst("jnb"): return DC_JNB; + } + return 0; +} + +MAKE_HOOK(ISteamNetworkingUtils_GetDirectPingToPOP, U::Memory.GetVFunc(I::SteamNetworkingUtils, 9), int, __fastcall, + void* ecx, SteamNetworkingPOPID popID) +{ + int iOriginal = CALL_ORIGINAL(ecx, popID); + if (!Vars::Misc::Queueing::ForceRegions.Value) + return iOriginal; + + char popIDName[5]; + POPID_ToString(popID, popIDName); + if (auto uDatacenter = GetDatacenter(FNV1A::Hash(popIDName))) + return Vars::Misc::Queueing::ForceRegions.Value & uDatacenter ? 1 : 999999; + + return iOriginal; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/Input_GetUserCmd.cpp b/Amalgam/src/Hooks/Input_GetUserCmd.cpp new file mode 100644 index 0000000..4ae1385 --- /dev/null +++ b/Amalgam/src/Hooks/Input_GetUserCmd.cpp @@ -0,0 +1,7 @@ +#include "../SDK/SDK.h" + +MAKE_HOOK(IInput_GetUserCmd, U::Memory.GetVFunc(I::Input, 8), + CUserCmd*, __fastcall, void* ecx, int sequence_number) +{ + return &I::Input->GetCommands()[sequence_number % MULTIPLAYER_BACKUP]; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/KeyValues_SetInt.cpp b/Amalgam/src/Hooks/KeyValues_SetInt.cpp new file mode 100644 index 0000000..cb40226 --- /dev/null +++ b/Amalgam/src/Hooks/KeyValues_SetInt.cpp @@ -0,0 +1,22 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(KeyValues_SetInt, "client.dll", "40 53 48 83 EC ? 41 8B D8 41 B0", 0x0); +MAKE_SIGNATURE(KeyValues_SetInt_Desired, "client.dll", "49 8B 06 4C 8B C3 8B D7", 0x0); +MAKE_SIGNATURE(KeyValues_SetInt_Jump, "client.dll", "8B F0 E8 ? ? ? ? 3B C7", 0x0); + +MAKE_HOOK(KeyValues_SetInt, S::KeyValues_SetInt(), void, __fastcall, + void* ecx, const char* keyName, int value) +{ + static auto dwDesired = S::KeyValues_SetInt_Desired(); + static auto dwJump = S::KeyValues_SetInt_Jump(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + CALL_ORIGINAL(ecx, keyName, value); + + if (!Vars::Visuals::UI::RevealScoreboard.Value || !keyName) + return; + + /* Scoreboard class reveal */ + if (dwRetAddr == dwDesired && FNV1A::Hash(keyName) == FNV1A::HashConst("nemesis")) + *static_cast(_AddressOfReturnAddress()) = dwJump; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ModelRender_DrawModelExecute.cpp b/Amalgam/src/Hooks/ModelRender_DrawModelExecute.cpp new file mode 100644 index 0000000..8b29c7c --- /dev/null +++ b/Amalgam/src/Hooks/ModelRender_DrawModelExecute.cpp @@ -0,0 +1,62 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Chams/Chams.h" +#include "../Features/Visuals/Glow/Glow.h" + +MAKE_SIGNATURE(CBaseAnimating_DrawModel, "client.dll", "4C 8B DC 49 89 5B ? 89 54 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC ? 48 8B 05 ? ? ? ? 48 8D 3D", 0x0); +MAKE_SIGNATURE(ViewmodelAttachment_DrawModel, "client.dll", "41 8B D5 FF 50 ? 8B 97", 0x6); + +MAKE_HOOK(ModelRender_DrawModelExecute, U::Memory.GetVFunc(I::ModelRender, 19), void, __fastcall, + void* ecx, const DrawModelState_t& pState, const ModelRenderInfo_t& pInfo, matrix3x4* pBoneToWorld) +{ + /* + if (!F::Chams.iRendering && !F::Glow.bRendering && !I::EngineVGui->IsGameUIVisible()) + { + if (const auto& pEntity = I::ClientEntityList->GetClientEntity(pInfo.m_nEntIndex)) + Utils::ConLog("Entity", std::format("{}, {}, {}", pInfo.m_nEntIndex, int(pEntity->GetClassID()), I::ModelInfoClient->GetModelName(pInfo.m_pModel)).c_str()); + else + Utils::ConLog("Model", std::format("{}, {}", pInfo.m_nEntIndex, I::ModelInfoClient->GetModelName(pInfo.m_pModel)).c_str()); + } + */ + + if (Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot() || G::Unload) + return CALL_ORIGINAL(ecx, pState, pInfo, pBoneToWorld); + + if (F::Chams.bRendering) + return F::Chams.RenderHandler(pState, pInfo, pBoneToWorld); + if (F::Glow.bRendering) + return F::Glow.RenderHandler(pState, pInfo, pBoneToWorld); + + if (F::Chams.mEntities[pInfo.entity_index]) + return; + + const auto& pEntity = I::ClientEntityList->GetClientEntity(pInfo.entity_index); + if (pEntity && pEntity->GetClassID() == ETFClassID::CTFViewModel) + { + F::Glow.RenderViewmodel(pState, pInfo, pBoneToWorld); + if (F::Chams.RenderViewmodel(pState, pInfo, pBoneToWorld)) + return; + } + + CALL_ORIGINAL(ecx, pState, pInfo, pBoneToWorld); +} + +MAKE_HOOK(CBaseAnimating_DrawModel, S::CBaseAnimating_DrawModel(), int, __fastcall, + void* ecx, int flags) +{ + static const auto dwDrawModel = S::ViewmodelAttachment_DrawModel(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot() || G::Unload) + return CALL_ORIGINAL(ecx, flags); + + if (dwRetAddr == dwDrawModel && flags & STUDIO_RENDER) + { + int iReturn; + F::Glow.RenderViewmodel(ecx, flags); + if (F::Chams.RenderViewmodel(ecx, flags, &iReturn)) + return iReturn; + } + + return CALL_ORIGINAL(ecx, flags); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/NetChannel_SendDatagram.cpp b/Amalgam/src/Hooks/NetChannel_SendDatagram.cpp new file mode 100644 index 0000000..afe9051 --- /dev/null +++ b/Amalgam/src/Hooks/NetChannel_SendDatagram.cpp @@ -0,0 +1,23 @@ +#include "../SDK/SDK.h" + +#include "../Features/Backtrack/Backtrack.h" + +MAKE_SIGNATURE(NetChannel_SendDatagram, "engine.dll", "40 55 57 41 56 48 8D AC 24", 0x0); + +MAKE_HOOK(NetChannel_SendDatagram, S::NetChannel_SendDatagram(), int, __fastcall, + CNetChannel* netChannel, bf_write* datagram) +{ + if (!netChannel || datagram) + return CALL_ORIGINAL(netChannel, datagram); + + F::Backtrack.bFakeLatency = H::Entities.GetLocal() && Vars::Backtrack::Enabled.Value && Vars::Backtrack::Latency.Value; + if (!F::Backtrack.bFakeLatency) + return CALL_ORIGINAL(netChannel, datagram); + + const int nInSequenceNr = netChannel->m_nInSequenceNr, nInReliableState = netChannel->m_nInReliableState; + F::Backtrack.AdjustPing(netChannel); + const int original = CALL_ORIGINAL(netChannel, datagram); + netChannel->m_nInSequenceNr = nInSequenceNr, netChannel->m_nInReliableState = nInReliableState; + + return original; +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/NotificationQueue_Add.cpp b/Amalgam/src/Hooks/NotificationQueue_Add.cpp new file mode 100644 index 0000000..daff7f4 --- /dev/null +++ b/Amalgam/src/Hooks/NotificationQueue_Add.cpp @@ -0,0 +1,22 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(NotificationQueue_Add, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B F9 48 8B 0D ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 84 C0 75", 0x0); +MAKE_SIGNATURE(CTFPlayer_OnHasNewItems_Call, "client.dll", "E9 ? ? ? ? 48 8B 5C 24 ? 48 83 C4 ? C3 CC CC CC CC CC CC CC CC CC 40 53", 0x5); + +MAKE_HOOK(NotificationQueue_Add, S::NotificationQueue_Add(), int, __cdecl, + CEconNotification* pNotification) +{ + static const auto dwDesired = S::CTFPlayer_OnHasNewItems_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (Vars::Misc::Automation::AcceptItemDrops.Value && dwRetAddr == dwDesired) + { + pNotification->Accept(); + pNotification->Trigger(); + pNotification->UpdateTick(); + pNotification->MarkForDeletion(); + return 0; + } + + return CALL_ORIGINAL(pNotification); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/S_StartDynamicSound.cpp b/Amalgam/src/Hooks/S_StartDynamicSound.cpp new file mode 100644 index 0000000..6cf6273 --- /dev/null +++ b/Amalgam/src/Hooks/S_StartDynamicSound.cpp @@ -0,0 +1,12 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Visuals.h" + +MAKE_SIGNATURE(S_StartDynamicSound, "engine.dll", "4C 8B DC 57 48 81 EC", 0x0); + +MAKE_HOOK(S_StartDynamicSound, S::S_StartDynamicSound(), int, __cdecl, + StartSoundParams_t& params) +{ + F::Visuals.ManualNetwork(params); + return CALL_ORIGINAL(params); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/StudioRender_SetAlphaModulation.cpp b/Amalgam/src/Hooks/StudioRender_SetAlphaModulation.cpp new file mode 100644 index 0000000..bd96f54 --- /dev/null +++ b/Amalgam/src/Hooks/StudioRender_SetAlphaModulation.cpp @@ -0,0 +1,10 @@ +#include "../SDK/SDK.h" + +MAKE_HOOK(StudioRender_SetAlphaModulation, U::Memory.GetVFunc(I::StudioRender, 28), void, __fastcall, + void* ecx, float flAlpha) +{ + if (Vars::Visuals::World::Modulations.Value & (1 << 2) && G::DrawingProps && !(Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot())) + return CALL_ORIGINAL(ecx, float(Vars::Colors::PropModulation.Value.a) / 255.f * flAlpha); + + CALL_ORIGINAL(ecx, flAlpha); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/StudioRender_SetColorModulation.cpp b/Amalgam/src/Hooks/StudioRender_SetColorModulation.cpp new file mode 100644 index 0000000..84c9bab --- /dev/null +++ b/Amalgam/src/Hooks/StudioRender_SetColorModulation.cpp @@ -0,0 +1,18 @@ +#include "../SDK/SDK.h" + +MAKE_HOOK(StudioRender_SetColorModulation, U::Memory.GetVFunc(I::StudioRender, 27), void, __fastcall, + void* ecx, const float* pColor) +{ + if (Vars::Visuals::World::Modulations.Value & (1 << 2) && G::DrawingProps && !(Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot())) + { + const float flCustomBlend[3] = { + float(Vars::Colors::PropModulation.Value.r) / 255.f, + float(Vars::Colors::PropModulation.Value.g) / 255.f, + float(Vars::Colors::PropModulation.Value.b) / 255.f + }; + + return CALL_ORIGINAL(ecx, flCustomBlend); + } + + CALL_ORIGINAL(ecx, pColor); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/VGuiMenuBuilder_AddMenuItem.cpp b/Amalgam/src/Hooks/VGuiMenuBuilder_AddMenuItem.cpp new file mode 100644 index 0000000..14b686a --- /dev/null +++ b/Amalgam/src/Hooks/VGuiMenuBuilder_AddMenuItem.cpp @@ -0,0 +1,85 @@ +#include "../SDK/SDK.h" + +#include "../Features/Players/PlayerUtils.h" + +MAKE_SIGNATURE(CVoiceStatus_IsPlayerBlocked, "client.dll", "40 53 48 81 EC ? ? ? ? 48 8B D9 4C 8D 44 24", 0x0); +MAKE_SIGNATURE(VGuiMenuBuilder_AddMenuItem, "client.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B EA 49 8B F9 48 8B 51 ? 49 8B F0 48 8B D9 48 85 D2 74 ? 49 8B C9 E8 ? ? ? ? 85 C0 74 ? 48 8B 0B 48 8B 01 FF 90 ? ? ? ? 48 8B 0B 4C 8B C6 4C 8B 4B ? 48 8B D5 48 89 7B ? 48 C7 44 24 ? ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 13 3B 82 ? ? ? ? 73 ? 3B 82 ? ? ? ? 7F ? 48 8B 92 ? ? ? ? 8B C8 48 03 C9 39 44 CA ? 75 ? 39 44 CA ? 75 ? 48 8B 04 CA EB ? 33 C0 48 8B 5C 24 ? 48 8B 6C 24 ? 48 8B 74 24 ? 48 83 C4 ? 5F C3 CC CC CC CC 48 89 5C 24", 0x0); +MAKE_SIGNATURE(CTFClientScoreBoardDialog_OnCommand, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B DA 48 8B F9 48 8B CB 48 8D 15 ? ? ? ? E8 ? ? ? ? 48 85 C0 74 ? 48 8B 0D", 0x0); +MAKE_SIGNATURE(CVoiceStatus_IsPlayerBlocked_Call, "client.dll", "84 C0 48 8D 0D ? ? ? ? 48 8D 15 ? ? ? ? 48 0F 45 D1 4C 8D 0D", 0x0); +MAKE_SIGNATURE(VGuiMenuBuilder_AddMenuItem_Call, "client.dll", "48 8B 0D ? ? ? ? 4C 8D 84 24 ? ? ? ? 48 8D 94 24 ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 44 8B 84 24 ? ? ? ? 8B 94 24", 0x0); + +static int PlayerIndex; +static std::string PlayerName; +static uint32_t FriendsID; + +MAKE_HOOK(CVoiceStatus_IsPlayerBlocked, S::CVoiceStatus_IsPlayerBlocked(), bool, __fastcall, + void* ecx, int playerIndex) +{ + static auto dwDesired = S::CVoiceStatus_IsPlayerBlocked_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (!Vars::Visuals::UI::ScoreboardPlayerlist.Value) + return CALL_ORIGINAL(ecx, playerIndex); + + if (dwRetAddr == dwDesired) + PlayerIndex = playerIndex; + + return CALL_ORIGINAL(ecx, playerIndex); +} + +MAKE_HOOK(VGuiMenuBuilder_AddMenuItem, S::VGuiMenuBuilder_AddMenuItem(), void*, __fastcall, + void* ecx, const char* pszButtonText, const char* pszCommand, const char* pszCategoryName) +{ + static auto dwDesired = S::VGuiMenuBuilder_AddMenuItem_Call(); + const auto dwRetAddr = std::uintptr_t(_ReturnAddress()); + + if (!Vars::Visuals::UI::ScoreboardPlayerlist.Value) + return CALL_ORIGINAL(ecx, pszButtonText, pszCommand, pszCategoryName); + + if (dwRetAddr == dwDesired && PlayerIndex != -1) + { + auto ret = CALL_ORIGINAL(ecx, pszButtonText, pszCommand, pszCategoryName); + + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(PlayerIndex, &pi) && !pi.fakeplayer) + { + PlayerName = pi.name; + FriendsID = pi.friendsID; + + const bool bIgnored = F::PlayerUtils.HasTag(FriendsID, "Ignored"); + const bool bCheater = F::PlayerUtils.HasTag(FriendsID, "Cheater"); + + CALL_ORIGINAL(ecx, std::format("{} {}", bIgnored ? "Unignore" : "Ignore", PlayerName).c_str(), "ignoreplayer", "tags"); + CALL_ORIGINAL(ecx, std::format("{} {}", bCheater ? "Unmark" : "Mark", PlayerName).c_str(), "markplayer", "tags"); + } + + return ret; + } + + return CALL_ORIGINAL(ecx, pszButtonText, pszCommand, pszCategoryName); +} + +MAKE_HOOK(CTFClientScoreBoardDialog_OnCommand, S::CTFClientScoreBoardDialog_OnCommand(), void, __fastcall, + void* ecx, const char* command) +{ + if (!Vars::Visuals::UI::ScoreboardPlayerlist.Value) + return CALL_ORIGINAL(ecx, command); + + auto uHash = FNV1A::Hash(command); + if (uHash == FNV1A::HashConst("ignoreplayer")) + { + if (!F::PlayerUtils.HasTag(FriendsID, "Ignored")) + F::PlayerUtils.AddTag(FriendsID, "Ignored", true, PlayerName); + else + F::PlayerUtils.RemoveTag(FriendsID, "Ignored", true, PlayerName); + } + else if (uHash == FNV1A::HashConst("markplayer")) + { + if (!F::PlayerUtils.HasTag(FriendsID, "Cheater")) + F::PlayerUtils.AddTag(FriendsID, "Cheater", true, PlayerName); + else + F::PlayerUtils.RemoveTag(FriendsID, "Cheater", true, PlayerName); + } + + CALL_ORIGINAL(ecx, command); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ViewRender_LevelInit.cpp b/Amalgam/src/Hooks/ViewRender_LevelInit.cpp new file mode 100644 index 0000000..3d5037e --- /dev/null +++ b/Amalgam/src/Hooks/ViewRender_LevelInit.cpp @@ -0,0 +1,22 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Materials/Materials.h" +#include "../Features/Visuals/Visuals.h" +#include "../Features/Backtrack/Backtrack.h" +#include "../Features/CheaterDetection/CheaterDetection.h" +#include "../Features/NoSpread/NoSpreadHitscan/NoSpreadHitscan.h" +#include "../Features/TickHandler/TickHandler.h" + +MAKE_HOOK(ViewRender_LevelInit, U::Memory.GetVFunc(I::ViewRender, 1), void, __fastcall, + void* ecx) +{ + F::Materials.ReloadMaterials(); + F::Visuals.OverrideWorldTextures(); + + F::Backtrack.Restart(); + F::Ticks.Reset(); + F::NoSpreadHitscan.Reset(true); + F::CheaterDetection.Reset(); + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ViewRender_LevelShutdown.cpp b/Amalgam/src/Hooks/ViewRender_LevelShutdown.cpp new file mode 100644 index 0000000..b10b050 --- /dev/null +++ b/Amalgam/src/Hooks/ViewRender_LevelShutdown.cpp @@ -0,0 +1,11 @@ +#include "../SDK/SDK.h" + +#include "../Features/Visuals/Materials/Materials.h" + +MAKE_HOOK(ViewRender_LevelShutdown, U::Memory.GetVFunc(I::ViewRender, 2), void, __fastcall, + void* ecx) +{ + F::Materials.UnloadMaterials(); + + CALL_ORIGINAL(ecx); +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ViewRender_PerformScreenSpaceEffects.cpp b/Amalgam/src/Hooks/ViewRender_PerformScreenSpaceEffects.cpp new file mode 100644 index 0000000..c066f58 --- /dev/null +++ b/Amalgam/src/Hooks/ViewRender_PerformScreenSpaceEffects.cpp @@ -0,0 +1,11 @@ +// what is this for? + +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(ViewRender_PerformScreenSpaceEffects, "client.dll", "55 8B EC 83 EC ? 8B 0D ? ? ? ? 53 56 57 33 F6 33 FF 89 75 ? 89 7D ? 8B 01 85 C0 74 ? 68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 57 57 57 57 8D 4D ? 51 50 8B 40 ? FF D0 8B 7D ? 83 C4 ? 8B 75 ? 8B 0D ? ? ? ? 8B 19 8B 0D", 0x0); + +MAKE_HOOK(ViewRender_PerformScreenSpaceEffects, S::ViewRender_PerformScreenSpaceEffects(), void, __fastcall, + void* ecx, int x, int y, int w, int h) +{ + // Do nothing. +} \ No newline at end of file diff --git a/Amalgam/src/Hooks/ViewRender_RenderView.cpp b/Amalgam/src/Hooks/ViewRender_RenderView.cpp new file mode 100644 index 0000000..9c8ec5d --- /dev/null +++ b/Amalgam/src/Hooks/ViewRender_RenderView.cpp @@ -0,0 +1,13 @@ +#include "../SDK/SDK.h" + +#include "../Features/CameraWindow/CameraWindow.h" + +MAKE_HOOK(ViewRender_RenderView, U::Memory.GetVFunc(I::ViewRender, 6), void, __fastcall, + void* ecx, const CViewSetup& view, ClearFlags_t nClearFlags, RenderViewInfo_t whatToDraw) +{ + CALL_ORIGINAL(ecx, view, nClearFlags, whatToDraw); + if (Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot() || G::Unload) + return; + + F::CameraWindow.RenderView(ecx, view); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Classes.h b/Amalgam/src/SDK/Definitions/Classes.h new file mode 100644 index 0000000..0e86f95 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Classes.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Main/CBaseAnimating.h" +#include "Main/CBaseCombatCharacter.h" +#include "Main/CBaseCombatWeapon.h" +#include "Main/CBaseEntity.h" +#include "Main/CBaseFlex.h" +#include "Main/CBaseHandle.h" +#include "Main/CBaseObject.h" +#include "Main/CBasePlayer.h" +#include "Main/CBaseProjectile.h" +#include "Main/CEconDefinition.h" +#include "Main/CEntitySphereQuery.h" +#include "Main/CHalloweenPickup.h" +#include "Main/CMultiPlayerAnimState.h" +#include "Main/CTFPlayer.h" +#include "Main/CTFPlayerResource.h" +#include "Main/CTFWeaponBase.h" +#include "Main/CUserCmd.h" +#include "Main/IAchievementMgr.h" +#include "Main/IClientEntity.h" +#include "Main/IClientNetworkable.h" +#include "Main/IClientRenderable.h" +#include "Main/IClientThinkable.h" +#include "Main/IClientUnknown.h" +#include "Main/IMaterial.h" +#include "Main/IMaterialVar.h" +#include "Main/IHandleEntity.h" +#include "Main/INetChannel.h" +#include "Main/ITexture.h" +#include "Main/KeyValues.h" +#include "Main/MD5.h" \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Definitions.h b/Amalgam/src/SDK/Definitions/Definitions.h new file mode 100644 index 0000000..ba7315a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Definitions.h @@ -0,0 +1,2925 @@ +#pragma once +#include "Misc/BaseTypes.h" +#include "Types.h" + +#define TICK_INTERVAL I::GlobalVars->interval_per_tick +#define TIME_TO_TICKS(dt) (static_cast(0.5f + static_cast(dt) / TICK_INTERVAL)) +#define TICKS_TO_TIME(t) (TICK_INTERVAL * (t)) + +#define ANIMATION_CYCLE_BITS 10 +#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 + +//#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.4f +#define TIME_TO_DUCK_MS 400.0f +#endif +#define TIME_TO_UNDUCK 0.2f +#define TIME_TO_UNDUCK_MS 200.0f + +#define MAX_WEAPON_SLOTS 6 +#define MAX_WEAPON_POSITIONS 20 +#define MAX_ITEM_TYPES 6 +#define MAX_WEAPONS 48 + +#define MAX_ITEMS 5 + +#define WEAPON_NOCLIP -1 + +#define MAX_AMMO_TYPES 32 +#define MAX_AMMO_SLOTS 32 + +#define HUD_PRINTNOTIFY 1 +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 + +#define MAX_VOTE_DETAILS_LENGTH 64 +#define INVALID_ISSUE -1 +#define MAX_VOTE_OPTIONS 5 +#define DEDICATED_SERVER 99 + +#define TEAM_ANY -2 +#define TEAM_INVALID -1 +#define TEAM_UNASSIGNED 0 +#define TEAM_SPECTATOR 1 +#define LAST_SHARED_TEAM TEAM_SPECTATOR +#define FIRST_GAME_TEAM (LAST_SHARED_TEAM+1) +#define MAX_TEAMS 32 +#define MAX_TEAM_NAME_LENGTH 32 + +#define TRACER_FLAG_WHIZ 0x0001 +#define TRACER_FLAG_USEATTACHMENT 0x0002 +#define TRACER_DONT_USE_ATTACHMENT -1 + +#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 + +#define DMG_GENERIC 0 +#define DMG_CRUSH (1 << 0) +#define DMG_BULLET (1 << 1) +#define DMG_SLASH (1 << 2) +#define DMG_BURN (1 << 3) +#define DMG_VEHICLE (1 << 4) +#define DMG_FALL (1 << 5) +#define DMG_BLAST (1 << 6) +#define DMG_CLUB (1 << 7) +#define DMG_SHOCK (1 << 8) +#define DMG_SONIC (1 << 9) +#define DMG_ENERGYBEAM (1 << 10) +#define DMG_PREVENT_PHYSICS_FORCE (1 << 11) +#define DMG_NEVERGIB (1 << 12) +#define DMG_ALWAYSGIB (1 << 13) +#define DMG_DROWN (1 << 14) + + +#define DMG_PARALYZE (1 << 15) +#define DMG_NERVEGAS (1 << 16) +#define DMG_POISON (1 << 17) +#define DMG_RADIATION (1 << 18) +#define DMG_DROWNRECOVER (1 << 19) +#define DMG_ACID (1 << 20) +#define DMG_SLOWBURN (1 << 21) + +#define DMG_REMOVENORAGDOLL (1<<22) + +#define DMG_PHYSGUN (1<<23) +#define DMG_PLASMA (1<<24) +#define DMG_AIRBOAT (1<<25) + +#define DMG_DISSOLVE (1<<26) +#define DMG_BLAST_SURFACE (1<<27) +#define DMG_DIRECT (1<<28) +#define DMG_BUCKSHOT (1<<29) + +#define DMG_LASTGENERICFLAG DMG_BUCKSHOT + +#define DAMAGE_NO 0 +#define DAMAGE_EVENTS_ONLY 1 +#define DAMAGE_YES 2 +#define DAMAGE_AIM 3 + +#define LAST_PLAYER_OBSERVERMODE OBS_MODE_ROAMING + +#define TF_VISION_FILTER_NONE 0 +#define TF_VISION_FILTER_PYRO (1<<0) +#define TF_VISION_FILTER_HALLOWEEN (1<<1) +#define TF_VISION_FILTER_ROME (1<<2) + +#define MAX_MVM_WAVE_STRING 256 + +#define TF_DAMAGE_CRIT_CHANCE 0.02f +#define TF_DAMAGE_CRIT_CHANCE_RAPID 0.02f +#define TF_DAMAGE_CRIT_DURATION_RAPID 2.0f +#define TF_DAMAGE_CRIT_CHANCE_MELEE 0.15f +#define TF_DAMAGE_CRITMOD_MAXTIME 20 +#define TF_DAMAGE_CRITMOD_MINTIME 2 +#define TF_DAMAGE_CRITMOD_DAMAGE 800 +#define TF_DAMAGE_CRITMOD_MAXMULT 6 +#define TF_DAMAGE_CRIT_MULTIPLIER 3.0f +#define TF_DAMAGE_MINICRIT_MULTIPLIER 1.35f + +#define WEAPON_RANDOM_RANGE 10000 + +#define TF_HEALTH_UNDEFINED 1 +#define TF_SPY_UNDEFINED TEAM_UNASSIGNED +#define TF_CLASS_COUNT ( TF_CLASS_COUNT_ALL ) +#define TF_FIRST_NORMAL_CLASS ( TF_CLASS_UNDEFINED + 1 ) +#define TF_LAST_NORMAL_CLASS ( TF_CLASS_CIVILIAN ) +#define TF_CLASS_MENU_BUTTONS ( TF_CLASS_RANDOM + 1 ) + +#define TF_TEAM_AUTOASSIGN (TF_TEAM_COUNT + 1 ) +#define TF_TEAM_HALLOWEEN TF_TEAM_AUTOASSIGN +#define TF_TEAM_PVE_INVADERS TF_TEAM_BLUE +#define TF_TEAM_PVE_DEFENDERS TF_TEAM_RED +#define TF_TEAM_PVE_INVADERS_GIANTS 4 + +#define COLOR_TF_SPECTATOR Color( 245, 229, 196, 255 ) +#define COLOR_TF_RED Color( 175, 73, 73, 255 ) +#define COLOR_TF_BLUE Color( 79, 117, 143, 255 ) + +#define TF_PLAYER_WEAPON_COUNT 6 +#define TF_PLAYER_GRENADE_COUNT 2 +#define TF_PLAYER_BUILDABLE_COUNT 3 +#define TF_PLAYER_BLUEPRINT_COUNT 6 +#define TF_WEAPON_PRIMARY_MODE 0 +#define TF_WEAPON_SECONDARY_MODE 1 +#define TF_WEAPON_GRENADE_FRICTION 0.6f +#define TF_WEAPON_GRENADE_GRAVITY 0.81f +#define TF_WEAPON_GRENADE_INITPRIME 0.8f +#define TF_WEAPON_GRENADE_CONCUSSION_TIME 15.0f +#define TF_WEAPON_GRENADE_MIRV_BOMB_COUNT 4 +#define TF_WEAPON_GRENADE_CALTROP_TIME 8.0f +#define TF_WEAPON_PIPEBOMB_WORLD_COUNT 15 +#define TF_WEAPON_PIPEBOMB_COUNT 8 +#define TF_WEAPON_PIPEBOMB_INTERVAL 0.6f +#define TF_WEAPON_ROCKET_INTERVAL 0.8f +#define TF_WEAPON_FLAMETHROWER_INTERVAL 0.15f +#define TF_WEAPON_FLAMETHROWER_ROCKET_INTERVAL 0.8f +#define TF_WEAPON_ZOOM_FOV 20 + +#define TF_PLAYER_VIEW_OFFSET Vector( 0, 0, 64.0 ) +#define TF_BURNING_FREQUENCY 0.5f +#define TF_BURNING_FLAME_LIFE 10.0 +#define TF_BURNING_FLAME_LIFE_PYRO 0.25 +#define TF_BURNING_FLAME_LIFE_FLARE 10.0 +#define TF_BURNING_FLAME_LIFE_PLASMA 6.0 +#define TF_BURNING_DMG 3 +#define TF_BLEEDING_FREQUENCY 0.5f +#define TF_BLEEDING_DMG 4 +#define TF_TIME_TO_DISGUISE 2.0f +#define TF_TIME_TO_QUICK_DISGUISE 0.5f +#define TF_TIME_TO_SHOW_DISGUISED_FINISHED_EFFECT 5.0 +#define TF_SCOUT_NUMBEROFPHASEATTACHMENTS 5 +#define SHOW_DISGUISE_EFFECT +#define TF_DISGUISE_TARGET_INDEX_NONE ( MAX_PLAYERS + 1 ) +#define TF_PLAYER_INDEX_NONE ( MAX_PLAYERS + 1 ) + +#define TF_FLAGINFO_HOME 0 +#define TF_FLAGINFO_STOLEN (1<<0) +#define TF_FLAGINFO_DROPPED (1<<1) + +#define TF_REGEN_TIME 1.0 +#define TF_REGEN_AMOUNT 3 +#define TF_REGEN_TIME_RUNE 0.25 +#define TF_TIME_ASSIST_KILL 3.0f +#define TF_TIME_SUICIDE_KILL_CREDIT 10.0f +#define TF_KILLS_DOMINATION 4 + +#define DMG_USE_HITLOCATIONS (DMG_AIRBOAT) +#define DMG_HALF_FALLOFF (DMG_RADIATION) +#define DMG_CRITICAL (DMG_ACID) +#define DMG_RADIUS_MAX (DMG_ENERGYBEAM) +#define DMG_IGNITE (DMG_PLASMA) +#define DMG_USEDISTANCEMOD (DMG_SLOWBURN) +#define DMG_NOCLOSEDISTANCEMOD (DMG_POISON) +#define DMG_FROM_OTHER_SAPPER (DMG_IGNITE) +#define DMG_MELEE (DMG_BLAST_SURFACE) +#define DMG_DONT_COUNT_DAMAGE_TOWARDS_CRIT_RATE (DMG_DISSOLVE) +#define DMG_IGNORE_MAXHEALTH (DMG_BULLET) +#define DMG_IGNORE_DEBUFFS (DMG_SLASH) + +#define TF_STUN_NONE 0 +#define TF_STUN_MOVEMENT (1<<0) +#define TF_STUN_CONTROLS (1<<1) +#define TF_STUN_MOVEMENT_FORWARD_ONLY (1<<2) +#define TF_STUN_SPECIAL_SOUND (1<<3) +#define TF_STUN_DODGE_COOLDOWN (1<<4) +#define TF_STUN_NO_EFFECTS (1<<5) +#define TF_STUN_LOSER_STATE (1<<6) +#define TF_STUN_BY_TRIGGER (1<<7) +#define TF_STUN_BOTH TF_STUN_MOVEMENT | TF_STUN_CONTROLS + +#define SENTRYGUN_UPGRADE_COST 130 +#define SENTRYGUN_UPGRADE_METAL 200 +#define SENTRYGUN_EYE_OFFSET_LEVEL_1 Vector( 0, 0, 32 ) +#define SENTRYGUN_EYE_OFFSET_LEVEL_2 Vector( 0, 0, 40 ) +#define SENTRYGUN_EYE_OFFSET_LEVEL_3 Vector( 0, 0, 46 ) +#define SENTRYGUN_MAX_SHELLS_1 150 +#define SENTRYGUN_MAX_SHELLS_2 200 +#define SENTRYGUN_MAX_SHELLS_3 200 +#define SENTRYGUN_MAX_ROCKETS 20 + +#define DISPENSER_MAX_METAL_AMMO 400 +#define MAX_DISPENSER_HEALING_TARGETS 32 +#define MINI_DISPENSER_MAX_METAL 200 + +#define BUILDING_MODE_ANY -1 + +#define TF_SCORE_KILL 1 +#define TF_SCORE_DEATH 0 +#define TF_SCORE_CAPTURE 2 +#define TF_SCORE_DEFEND 1 +#define TF_SCORE_DESTROY_BUILDING 1 +#define TF_SCORE_HEADSHOT_DIVISOR 2 +#define TF_SCORE_BACKSTAB 1 +#define TF_SCORE_INVULN 1 +#define TF_SCORE_REVENGE 1 +#define TF_SCORE_KILL_ASSISTS_PER_POINT 2 +#define TF_SCORE_TELEPORTS_PER_POINT 2 +#define TF_SCORE_HEAL_HEALTHUNITS_PER_POINT 600 +#define TF_SCORE_BONUS_POINT_DIVISOR 10 +#define TF_SCORE_DAMAGE 250 +#define TF_SCORE_CURRENCY_COLLECTED 20 +#define TF_SCORE_CAPTURE_POWERUPMODE 10 +#define TF_SCORE_FLAG_RETURN 4 +#define TF_SCORE_KILL_RUNECARRIER 1 + +#define TELEPORTER_TYPE_ENTRANCE 0 +#define TELEPORTER_TYPE_EXIT 1 + +#define TF_DEATH_DOMINATION 0x0001 +#define TF_DEATH_ASSISTER_DOMINATION 0x0002 +#define TF_DEATH_REVENGE 0x0004 +#define TF_DEATH_ASSISTER_REVENGE 0x0008 +#define TF_DEATH_FIRST_BLOOD 0x0010 +#define TF_DEATH_FEIGN_DEATH 0x0020 +#define TF_DEATH_INTERRUPTED 0x0040 +#define TF_DEATH_GIBBED 0x0080 +#define TF_DEATH_PURGATORY 0x0100 +#define TF_DEATH_MINIBOSS 0x0200 +#define TF_DEATH_AUSTRALIUM 0x0400 + +#define MAX_DECAPITATIONS 4 + +#define PLAYER_ROLL_MIN 1 +#define PLAYER_ROLL_MAX 500 + +#define TF_PLAYER_ROCKET_JUMPED ( 1 << 0 ) +#define TF_PLAYER_STICKY_JUMPED ( 1 << 1 ) +#define TF_PLAYER_ENEMY_BLASTED_ME ( 1 << 2 ) + +#define MVM_BUYBACK_COST_PER_SEC 5 +#define MVM_CLASS_TYPES_PER_WAVE_MAX 12 +#define MVM_CLASS_TYPES_PER_WAVE_MAX_NEW ( MVM_CLASS_TYPES_PER_WAVE_MAX * 2 ) +#define MVM_CLASS_FLAG_NONE 0 +#define MVM_CLASS_FLAG_NORMAL (1<<0) +#define MVM_CLASS_FLAG_SUPPORT (1<<1) +#define MVM_CLASS_FLAG_MISSION (1<<2) +#define MVM_CLASS_FLAG_MINIBOSS (1<<3) +#define MVM_CLASS_FLAG_ALWAYSCRIT (1<<4) +#define MVM_CLASS_FLAG_SUPPORT_LIMITED (1<<5) + +#define RD_MAX_ROBOT_GROUPS_PER_TEAM 6 +#define MAX_RAIDMODE_UPGRADES 60 + +#define MAX_PLAYERS 33 + +#define STEAM_PARM "-steam" +#define AUTO_RESTART "-autoupdate" +#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" + +#define DEFAULT_TICK_INTERVAL (0.015) +#define MINIMUM_TICK_INTERVAL (0.001) +#define MAXIMUM_TICK_INTERVAL (0.1) +#define ABSOLUTE_PLAYER_LIMIT 255 +#define ABSOLUTE_PLAYER_LIMIT_DW ((ABSOLUTE_PLAYER_LIMIT/32) + 1) +#define MAX_PLAYER_NAME_LENGTH 32 +#define MAX_PLAYERS_PER_CLIENT 1 +#define MAX_MAP_NAME 96 +#define MAX_MAP_NAME_SAVE 32 +#define MAX_DISPLAY_MAP_NAME 32 +#define MAX_NETWORKID_LENGTH 64 +#define SP_MODEL_INDEX_BITS 13 +#define MAX_EDICT_BITS 11 +#define MAX_EDICTS (1<=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) ); \ + + +enum MoveType_t +{ + MOVETYPE_NONE = 0, + MOVETYPE_ISOMETRIC, + MOVETYPE_WALK, + MOVETYPE_STEP, + MOVETYPE_FLY, + MOVETYPE_FLYGRAVITY, + MOVETYPE_VPHYSICS, + MOVETYPE_PUSH, + MOVETYPE_NOCLIP, + MOVETYPE_LADDER, + MOVETYPE_OBSERVER, + MOVETYPE_CUSTOM, + MOVETYPE_LAST = MOVETYPE_CUSTOM, + MOVETYPE_MAX_BITS = 4 +}; + +enum MoveCollide_t +{ + MOVECOLLIDE_DEFAULT = 0, + MOVECOLLIDE_FLY_BOUNCE, + MOVECOLLIDE_FLY_CUSTOM, + MOVECOLLIDE_FLY_SLIDE, + MOVECOLLIDE_COUNT, + MOVECOLLIDE_MAX_BITS = 3 +}; + +enum SolidType_t +{ + SOLID_NONE = 0, + SOLID_BSP = 1, + SOLID_BBOX = 2, + SOLID_OBB = 3, + SOLID_OBB_YAW = 4, + SOLID_CUSTOM = 5, + SOLID_VPHYSICS = 6, + SOLID_LAST +}; + +enum SolidFlags_t +{ + FSOLID_CUSTOMRAYTEST = 0x0001, + FSOLID_CUSTOMBOXTEST = 0x0002, + FSOLID_NOT_SOLID = 0x0004, + FSOLID_TRIGGER = 0x0008, + FSOLID_NOT_STANDABLE = 0x0010, + FSOLID_VOLUME_CONTENTS = 0x0020, + FSOLID_FORCE_WORLD_ALIGNED = 0x0040, + FSOLID_USE_TRIGGER_BOUNDS = 0x0080, + FSOLID_ROOT_PARENT_ALIGNED = 0x0100, + FSOLID_TRIGGER_TOUCH_DEBRIS = 0x0200, + FSOLID_MAX_BITS = 10 +}; + +inline bool IsSolid(SolidType_t solidType, int nSolidFlags) +{ + return (solidType != SOLID_NONE) && ((nSolidFlags & FSOLID_NOT_SOLID) == 0); +} + +enum +{ + EF_BONEMERGE = 0x001, + EF_BRIGHTLIGHT = 0x002, + EF_DIMLIGHT = 0x004, + EF_NOINTERP = 0x008, + EF_NOSHADOW = 0x010, + EF_NODRAW = 0x020, + EF_NORECEIVESHADOW = 0x040, + EF_BONEMERGE_FASTCULL = 0x080, + EF_ITEM_BLINK = 0x100, + EF_PARENT_ANIMATES = 0x200, + EF_MAX_BITS = 10 +}; + +enum RenderMode_t +{ + kRenderNormal = 0, + kRenderTransColor, + kRenderTransTexture, + kRenderGlow, + kRenderTransAlpha, + kRenderTransAdd, + kRenderEnvironmental, + kRenderTransAddFrameBlend, + kRenderTransAlphaAdd, + kRenderWorldGlow, + kRenderNone, + kRenderModeCount +}; + +enum RenderFx_t +{ + kRenderFxNone = 0, + kRenderFxPulseSlow, + kRenderFxPulseFast, + kRenderFxPulseSlowWide, + kRenderFxPulseFastWide, + kRenderFxFadeSlow, + kRenderFxFadeFast, + kRenderFxSolidSlow, + kRenderFxSolidFast, + kRenderFxStrobeSlow, + kRenderFxStrobeFast, + kRenderFxStrobeFaster, + kRenderFxFlickerSlow, + kRenderFxFlickerFast, + kRenderFxNoDissipation, + kRenderFxDistort, + kRenderFxHologram, + kRenderFxExplode, + kRenderFxGlowShell, + kRenderFxClampMinScale, + kRenderFxEnvRain, + kRenderFxEnvSnow, + kRenderFxSpotlight, + kRenderFxRagdoll, + kRenderFxPulseFastWider, + kRenderFxMax +}; + +enum Collision_Group_t +{ + COLLISION_GROUP_NONE = 0, + COLLISION_GROUP_DEBRIS, + COLLISION_GROUP_DEBRIS_TRIGGER, + COLLISION_GROUP_INTERACTIVE_DEBRIS, + COLLISION_GROUP_INTERACTIVE, + COLLISION_GROUP_PLAYER, + COLLISION_GROUP_BREAKABLE_GLASS, + COLLISION_GROUP_VEHICLE, + COLLISION_GROUP_PLAYER_MOVEMENT, + COLLISION_GROUP_NPC, + COLLISION_GROUP_IN_VEHICLE, + COLLISION_GROUP_WEAPON, + COLLISION_GROUP_VEHICLE_CLIP, + COLLISION_GROUP_PROJECTILE, + COLLISION_GROUP_DOOR_BLOCKER, + COLLISION_GROUP_PASSABLE_DOOR, + COLLISION_GROUP_DISSOLVING, + COLLISION_GROUP_PUSHAWAY, + COLLISION_GROUP_NPC_ACTOR, + COLLISION_GROUP_NPC_SCRIPTED, + LAST_SHARED_COLLISION_GROUP +}; + +class CThreadMutex; +typedef CThreadMutex CSourceMutex; + +enum ETFHitboxes +{ + HITBOX_HEAD, + HITBOX_NECK, + HITBOX_LOWER_NECK, + HITBOX_PELVIS, + HITBOX_BODY, + HITBOX_THORAX, + HITBOX_CHEST, + HITBOX_UPPER_CHEST, + HITBOX_RIGHT_THIGH, + HITBOX_LEFT_THIGH, + HITBOX_RIGHT_CALF, + HITBOX_LEFT_CALF, + HITBOX_RIGHT_FOOT, + HITBOX_LEFT_FOOT, + HITBOX_RIGHT_HAND, + HITBOX_LEFT_HAND, + HITBOX_RIGHT_UPPER_ARM, + HITBOX_RIGHT_FOREARM, + HITBOX_LEFT_UPPER_ARM, + HITBOX_LEFT_FOREARM, + HITBOX_MAX +}; + +enum MinigunState_t +{ + AC_STATE_IDLE = 0, + AC_STATE_STARTFIRING, + AC_STATE_FIRING, + AC_STATE_SPINNING, + AC_STATE_DRYFIRE +}; + +enum minigun_weapontypes_t +{ + MINIGUN_STANDARD = 0, + MINIGUN_STUN +}; + +typedef enum +{ + GROUND = 0, + STUCK, + LADDER +} IntervalType_t; + +enum +{ + SPEED_CROPPED_RESET = 0, + SPEED_CROPPED_DUCK = 1, + SPEED_CROPPED_WEAPON = 2 +}; + +typedef enum +{ + PREDICTION_SIMULATION_RESULTS_ARRIVING_ON_SEND_FRAME = 0, + PREDICTION_NORMAL +} PREDICTION_REASON; + +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 +}; + +enum medigun_weapontypes_t +{ + MEDIGUN_STANDARD = 0, + MEDIGUN_UBER, + MEDIGUN_QUICKFIX, + MEDIGUN_RESIST +}; + +enum medigun_resist_types_t +{ + MEDIGUN_BULLET_RESIST = 0, + MEDIGUN_BLAST_RESIST, + MEDIGUN_FIRE_RESIST, + MEDIGUN_NUM_RESISTS +}; + +enum PrecipitationType_t +{ + PRECIPITATION_TYPE_RAIN = 0, + PRECIPITATION_TYPE_SNOW, + PRECIPITATION_TYPE_ASH, + PRECIPITATION_TYPE_SNOWFALL, + NUM_PRECIPITATION_TYPES +}; + +class CViewVectors +{ +public: + Vector m_vView; + Vector m_vHullMin; + Vector m_vHullMax; + Vector m_vDuckHullMin; + Vector m_vDuckHullMax; + Vector m_vDuckView; + Vector m_vObsHullMin; + Vector m_vObsHullMax; + Vector m_vDeadViewHeight; +}; + +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, + VOTE_FAILED_KICK_DENIED_BY_GC, + VOTE_FAILED_MODIFICATION_ALREADY_ACTIVE +} vote_create_failed_t; + +enum UserMessageType +{ + Geiger = 0, + Train, + HudText, + SayText, + SayText2, + TextMsg, + ResetHUD, + GameTitle, + ItemPickup, + ShowMenu, + Shake, + Fade, + VGUIMenu, + Rumble, + CloseCaption, + SendAudio, + VoiceMask, + RequestState, + Damage, + HintText, + KeyHintText, + HudMsg, + AmmoDenied, + AchievementEvent, + UpdateRadar, + VoiceSubtitle, + HudNotify, + HudNotifyCustom, + PlayerStatsUpdate, + MapStatsUpdate, + PlayerIgnited, + PlayerIgnitedInv, + HudArenaNotify, + UpdateAchievement, + TrainingMsg, + TrainingObjective, + DamageDodged, + PlayerJarated, + PlayerExtinguished, + PlayerJaratedFade, + PlayerShieldBlocked, + BreakModel, + CheapBreakModel, + BreakModel_Pumpkin, + BreakModelRocketDud, + CallVoteFailed, + VoteStart, + VotePass, + VoteFailed, + VoteSetup, + PlayerBonusPoints, + RDTeamPointsChanged, + SpawnFlyingBird, + PlayerGodRayEffect, + PlayerTeleportHomeEffect, + MVMStatsReset, + MVMPlayerEvent, + MVMResetPlayerStats, + MVMWaveFailed, + MVMAnnouncement, + MVMPlayerUpgradedEvent, + MVMVictory, + MVMWaveChange, + MVMLocalPlayerUpgradesClear, + MVMLocalPlayerUpgradesValue, + MVMResetPlayerWaveSpendingStats, + MVMLocalPlayerWaveSpendingValue, + MVMResetPlayerUpgradeSpending, + MVMServerKickTimeUpdate, + PlayerLoadoutUpdated, + PlayerTauntSoundLoopStart, + PlayerTauntSoundLoopEnd, + ForcePlayerViewAngles, + BonusDucks, + EOTLDuckEvent, + PlayerPickupWeapon, + QuestObjectiveCompleted, + SPHapWeapEvent, + HapDmg, + HapPunch, + HapSetDrag, + HapSetConst, + HapMeleeContact +}; + +enum +{ + SERVER_MODIFICATION_ITEM_DURATION_IN_MINUTES = 120 +}; + +enum CastVote +{ + VOTE_OPTION1, + VOTE_OPTION2, + VOTE_OPTION3, + VOTE_OPTION4, + VOTE_OPTION5, + VOTE_UNCAST +}; + +enum +{ + ENTITY_DISSOLVE_NORMAL = 0, + ENTITY_DISSOLVE_ELECTRICAL, + ENTITY_DISSOLVE_ELECTRICAL_LIGHT, + ENTITY_DISSOLVE_CORE, + ENTITY_DISSOLVE_BITS = 3 +}; + +enum EObserverModes +{ + 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_FIRSTPERSON, // follow a player in first person view + OBS_MODE_THIRDPERSON, // follow a player in third person view + OBS_MODE_ROAMING, // free roaming +}; + +enum +{ + OBS_ALLOW_ALL = 0, + OBS_ALLOW_TEAM, + OBS_ALLOW_NONE, + OBS_ALLOW_NUM_MODES +}; + +enum +{ + TYPE_TEXT = 0, + TYPE_INDEX, + TYPE_URL, + TYPE_FILE +}; + +enum +{ + EFL_KILLME = (1 << 0), + EFL_DORMANT = (1 << 1), + EFL_NOCLIP_ACTIVE = (1 << 2), + EFL_SETTING_UP_BONES = (1 << 3), + EFL_KEEP_ON_RECREATE_ENTITIES = (1 << 4), + EFL_HAS_PLAYER_CHILD = (1 << 4), + EFL_DIRTY_SHADOWUPDATE = (1 << 5), + EFL_NOTIFY = (1 << 6), + EFL_FORCE_CHECK_TRANSMIT = (1 << 7), + EFL_BOT_FROZEN = (1 << 8), + EFL_SERVER_ONLY = (1 << 9), + EFL_NO_AUTO_EDICT_ATTACH = (1 << 10), + EFL_DIRTY_ABSTRANSFORM = (1 << 11), + EFL_DIRTY_ABSVELOCITY = (1 << 12), + EFL_DIRTY_ABSANGVELOCITY = (1 << 13), + EFL_DIRTY_SURROUNDING_COLLISION_BOUNDS = (1 << 14), + EFL_DIRTY_SPATIAL_PARTITION = (1 << 15), + EFL_IN_SKYBOX = (1 << 17), + EFL_USE_PARTITION_WHEN_NOT_SOLID = (1 << 18), + EFL_TOUCHING_FLUID = (1 << 19), + EFL_IS_BEING_LIFTED_BY_BARNACLE = (1 << 20), + EFL_NO_ROTORWASH_PUSH = (1 << 21), + EFL_NO_THINK_FUNCTION = (1 << 22), + EFL_NO_GAME_PHYSICS_SIMULATION = (1 << 23), + EFL_CHECK_UNTOUCH = (1 << 24), + EFL_DONTBLOCKLOS = (1 << 25), + EFL_DONTWALKON = (1 << 26), + EFL_NO_DISSOLVE = (1 << 27), + EFL_NO_MEGAPHYSCANNON_RAGDOLL = (1 << 28), + EFL_NO_WATER_VELOCITY_CHANGE = (1 << 29), + EFL_NO_PHYSCANNON_INTERACTION = (1 << 30), + EFL_NO_DAMAGE_FORCES = (1 << 31) +}; + +class CBaseEntity; + +struct FireBulletsInfo_t +{ + int m_iShots; + Vector m_vecSrc; + Vector m_vecDirShooting; + Vector m_vecSpread; + float m_flDistance; + int m_iAmmoType; + int m_iTracerFreq; + float m_flDamage; + int m_iPlayerDamage; + int m_nFlags; + float m_flDamageForceScale; + CBaseEntity* m_pAttacker; + CBaseEntity* m_pAdditionalIgnoreEnt; + bool m_bPrimaryAttack; + bool m_bUseServerRandomSeed; +}; + +enum +{ + VISION_MODE_NONE = 0, + VISION_MODE_PYRO, + VISION_MODE_HALLOWEEN, + VISION_MODE_ROME, + MAX_VISION_MODES +}; + +class CHudTexture +{ +public: + void* vftp; + char szShortName[64]; + char szTextureFile[64]; + bool bRenderUsingFont; + bool bPrecached; + char cCharacterInFont; + unsigned long hFont; + int textureId; + float texCoords[4]; + wrect_t rc; + +public: + int Width() const + { + return rc.right - rc.left; + } + int Height() const + { + return rc.bottom - rc.top; + } +}; + +enum class ETFClassID +{ + CTFWearableRazorback = 341, + CTFWearableDemoShield = 338, + CTFWearableLevelableItem = 340, + CTFWearableCampaignItem = 337, + CTFBaseRocket = 185, + CTFWeaponBaseMerasmusGrenade = 325, + CTFWeaponBaseMelee = 324, + CTFWeaponBaseGun = 323, + CTFWeaponBaseGrenadeProj = 322, + CTFWeaponBase = 321, + CTFWearableRobotArm = 342, + CTFRobotArm = 287, + CTFWrench = 344, + CTFProjectile_ThrowableBreadMonster = 279, + CTFProjectile_ThrowableBrick = 280, + CTFProjectile_ThrowableRepel = 281, + CTFProjectile_Throwable = 278, + CTFThrowable = 319, + CTFSyringeGun = 315, + CTFKatana = 225, + CTFSword = 314, + CSniperDot = 118, + CTFSniperRifleClassic = 308, + CTFSniperRifleDecap = 309, + CTFSniperRifle = 307, + CTFChargedSMG = 197, + CTFSMG = 306, + CTFSlap = 305, + CTFShovel = 304, + CTFShotgunBuildingRescue = 303, + CTFPEPBrawlerBlaster = 241, + CTFSodaPopper = 310, + CTFShotgun_Revenge = 301, + CTFScatterGun = 297, + CTFShotgun_Pyro = 300, + CTFShotgun_HWG = 299, + CTFShotgun_Soldier = 302, + CTFShotgun = 298, + CTFRocketPack = 296, + CTFCrossbow = 201, + CTFRocketLauncher_Mortar = 295, + CTFRocketLauncher_AirStrike = 293, + CTFRocketLauncher_DirectHit = 294, + CTFRocketLauncher = 292, + CTFRevolver = 286, + CTFDRGPomson = 202, + CTFRaygun = 284, + CTFPistol_ScoutSecondary = 246, + CTFPistol_ScoutPrimary = 245, + CTFPistol_Scout = 244, + CTFPistol = 243, + CTFPipebombLauncher = 242, + CTFWeaponPDA_Spy = 332, + CTFWeaponPDA_Engineer_Destroy = 331, + CTFWeaponPDA_Engineer_Build = 330, + CTFWeaponPDAExpansion_Teleporter = 334, + CTFWeaponPDAExpansion_Dispenser = 333, + CTFWeaponPDA = 329, + CTFParticleCannon = 239, + CTFParachute_Secondary = 238, + CTFParachute_Primary = 237, + CTFParachute = 236, + CTFMinigun = 234, + CTFMedigunShield = 231, + CWeaponMedigun = 352, + CTFProjectile_MechanicalArmOrb = 263, + CTFMechanicalArm = 230, + CTFLunchBox_Drink = 229, + CTFLunchBox = 228, + CLaserDot = 78, + CTFLaserPointer = 227, + CTFKnife = 226, + CTFGasManager = 212, + CTFProjectile_JarGas = 261, + CTFJarGas = 223, + CTFProjectile_Cleaver = 254, + CTFProjectile_JarMilk = 262, + CTFProjectile_Jar = 260, + CTFCleaver = 198, + CTFJarMilk = 224, + CTFJar = 222, + CTFWeaponInvis = 328, + CTFCannon = 196, + CTFGrenadeLauncher = 216, + CTFGrenadePipebombProjectile = 217, + CTFGrapplingHook = 215, + CTFFlareGun_Revenge = 210, + CTFFlareGun = 209, + CTFFlameRocket = 207, + CTFFlameThrower = 208, + CTFFists = 205, + CTFFireAxe = 204, + CTFWeaponFlameBall = 327, + CTFCompoundBow = 200, + CTFClub = 199, + CTFBuffItem = 195, + CTFStickBomb = 312, + CTFBreakableSign = 194, + CTFBottle = 192, + CTFBreakableMelee = 193, + CTFBonesaw = 190, + CTFBall_Ornament = 182, + CTFStunBall = 313, + CTFBat_Giftwrap = 188, + CTFBat_Wood = 189, + CTFBat_Fish = 187, + CTFBat = 186, + CTFProjectile_EnergyRing = 256, + CTFDroppedWeapon = 203, + CTFWeaponSapper = 335, + CTFWeaponBuilder = 326, + C_TFWeaponBuilder = 0, + CTFProjectile_Rocket = 264, + CTFProjectile_Flare = 257, + CTFProjectile_EnergyBall = 255, + CTFProjectile_GrapplingHook = 258, + CTFProjectile_HealingBolt = 259, + CTFProjectile_Arrow = 252, + CMannVsMachineStats = 80, + CTFTankBoss = 316, + CTFBaseBoss = 183, + CBossAlpha = 0, + NextBotCombatCharacter = 357, + CTFProjectile_SpellKartBats = 268, + CTFProjectile_SpellKartOrb = 269, + CTFHellZap = 220, + CTFProjectile_SpellLightningOrb = 270, + CTFProjectile_SpellTransposeTeleport = 277, + CTFProjectile_SpellMeteorShower = 271, + CTFProjectile_SpellSpawnBoss = 274, + CTFProjectile_SpellMirv = 272, + CTFProjectile_SpellPumpkin = 273, + CTFProjectile_SpellSpawnHorde = 275, + CTFProjectile_SpellSpawnZombie = 276, + CTFProjectile_SpellBats = 266, + CTFProjectile_SpellFireball = 267, + CTFSpellBook = 311, + CHightower_TeleportVortex = 74, + CTeleportVortex = 160, + CZombie = 354, + CMerasmusDancer = 83, + CMerasmus = 82, + CHeadlessHatman = 73, + CEyeballBoss = 48, + CTFBotHintEngineerNest = 191, + CBotNPCMinion = 0, + CBotNPC = 0, + CPasstimeGun = 94, + CTFViewModel = 320, + CRobotDispenser = 112, + CTFRobotDestruction_Robot = 288, + CTFReviveMarker = 285, + CTFPumpkinBomb = 282, + CTFProjectile_BallOfFire = 253, + CTFBaseProjectile = 184, + CTFPointManager = 250, + CBaseObjectUpgrade = 11, + CTFRobotDestructionLogic = 291, + CTFRobotDestruction_RobotGroup = 289, + CTFRobotDestruction_RobotSpawn = 290, + CTFPlayerDestructionLogic = 248, + CPlayerDestructionDispenser = 101, + CTFMinigameLogic = 233, + CTFHalloweenMinigame_FallingPlatforms = 219, + CTFHalloweenMinigame = 218, + CTFMiniGame = 232, + CTFPowerupBottle = 251, + CTFItem = 221, + CHalloweenSoulPack = 71, + CTFGenericBomb = 213, + CBonusRoundLogic = 23, + CTFGameRulesProxy = 211, + CTETFParticleEffect = 179, + CTETFExplosion = 178, + CTETFBlood = 177, + CTFFlameManager = 206, + CHalloweenGiftPickup = 69, + CBonusDuckPickup = 21, + CHalloweenPickup = 70, + CCaptureFlagReturnIcon = 27, + CCaptureFlag = 26, + CBonusPack = 22, + CTFTeam = 318, + CTFTauntProp = 317, + CTFPlayerResource = 249, + CTFPlayer = 247, + CTFRagdoll = 283, + CTEPlayerAnimEvent = 165, + CTFPasstimeLogic = 240, + CPasstimeBall = 93, + CTFObjectiveResource = 235, + CTFGlow = 214, + CTEFireBullets = 152, + CTFBuffBanner = 0, + CTFAmmoPack = 181, + CObjectTeleporter = 89, + CObjectSentrygun = 88, + CTFProjectile_SentryRocket = 265, + CObjectSapper = 87, + CObjectCartDispenser = 85, + CObjectDispenser = 86, + CMonsterResource = 84, + CFuncRespawnRoomVisualizer = 64, + CFuncRespawnRoom = 63, + CFuncPasstimeGoal = 61, + CFuncForceField = 57, + CCaptureZone = 28, + CCurrencyPack = 31, + CBaseObject = 10, + CTestTraceline = 176, + CTEWorldDecal = 180, + CTESpriteSpray = 174, + CTESprite = 173, + CTESparks = 172, + CTESmoke = 171, + CTEShowLine = 169, + CTEProjectedDecal = 167, + CTEPlayerDecal = 166, + CTEPhysicsProp = 164, + CTEParticleSystem = 163, + CTEMuzzleFlash = 162, + CTELargeFunnel = 159, + CTEKillPlayerAttachments = 158, + CTEImpact = 157, + CTEGlowSprite = 156, + CTEShatterSurface = 168, + CTEFootprintDecal = 154, + CTEFizz = 153, + CTEExplosion = 151, + CTEEnergySplash = 150, + CTEEffectDispatch = 149, + CTEDynamicLight = 148, + CTEDecal = 146, + CTEClientProjectile = 145, + CTEBubbleTrail = 144, + CTEBubbles = 143, + CTEBSPDecal = 142, + CTEBreakModel = 141, + CTEBloodStream = 140, + CTEBloodSprite = 139, + CTEBeamSpline = 138, + CTEBeamRingPoint = 137, + CTEBeamRing = 136, + CTEBeamPoints = 135, + CTEBeamLaser = 134, + CTEBeamFollow = 133, + CTEBeamEnts = 132, + CTEBeamEntPoint = 131, + CTEBaseBeam = 130, + CTEArmorRicochet = 129, + CTEMetalSparks = 161, + CSteamJet = 123, + CSmokeStack = 117, + DustTrail = 355, + CFireTrail = 50, + SporeTrail = 362, + SporeExplosion = 361, + RocketTrail = 359, + SmokeTrail = 360, + CPropVehicleDriveable = 108, + ParticleSmokeGrenade = 358, + CParticleFire = 90, + MovieExplosion = 356, + CTEGaussExplosion = 155, + CEnvQuadraticBeam = 43, + CEmbers = 36, + CEnvWind = 47, + CPrecipitation = 107, + CBaseTempEntity = 17, + CWeaponIFMSteadyCam = 351, + CWeaponIFMBaseCamera = 350, + CWeaponIFMBase = 349, + CTFWearableVM = 343, + CTFWearable = 336, + CTFWearableItem = 339, + CEconWearable = 35, + CBaseAttributableItem = 3, + CEconEntity = 34, + CHandleTest = 72, + CTeamplayRoundBasedRulesProxy = 126, + CTeamRoundTimer = 127, + CSpriteTrail = 122, + CSpriteOriented = 121, + CSprite = 120, + CRagdollPropAttached = 111, + CRagdollProp = 110, + CPoseController = 106, + CGameRulesProxy = 68, + CInfoLadderDismount = 75, + CFuncLadder = 58, + CEnvDetailController = 40, + CWorld = 353, + CWaterLODControl = 348, + CWaterBullet = 347, + CVoteController = 346, + CVGuiScreen = 345, + CPropJeep = 0, + CPropVehicleChoreoGeneric = 0, + CTest_ProxyToggle_Networkable = 175, + CTesla = 170, + CTeamTrainWatcher = 128, + CBaseTeamObjectiveResource = 16, + CTeam = 125, + CSun = 124, + CParticlePerformanceMonitor = 91, + CSpotlightEnd = 119, + CSlideshowDisplay = 116, + CShadowControl = 115, + CSceneEntity = 114, + CRopeKeyframe = 113, + CRagdollManager = 109, + CPhysicsPropMultiplayer = 98, + CPhysBoxMultiplayer = 96, + CBasePropDoor = 15, + CDynamicProp = 33, + CPointWorldText = 105, + CPointCommentaryNode = 104, + CPointCamera = 103, + CPlayerResource = 102, + CPlasma = 100, + CPhysMagnet = 99, + CPhysicsProp = 97, + CPhysBox = 95, + CParticleSystem = 92, + CMaterialModifyControl = 81, + CLightGlow = 79, + CInfoOverlayAccessor = 77, + CFuncTrackTrain = 67, + CFuncSmokeVolume = 66, + CFuncRotating = 65, + CFuncReflectiveGlass = 62, + CFuncOccluder = 60, + CFuncMonitor = 59, + CFunc_LOD = 54, + CTEDust = 147, + CFunc_Dust = 53, + CFuncConveyor = 56, + CBreakableSurface = 25, + CFuncAreaPortalWindow = 55, + CFish = 51, + CEntityFlame = 38, + CFireSmoke = 49, + CEnvTonemapController = 46, + CEnvScreenEffect = 44, + CEnvScreenOverlay = 45, + CEnvProjectedTexture = 42, + CEnvParticleScript = 41, + CFogController = 52, + CEntityParticleTrail = 39, + CEntityDissolve = 37, + CDynamicLight = 32, + CColorCorrectionVolume = 30, + CColorCorrection = 29, + CBreakableProp = 24, + CBasePlayer = 13, + CBaseFlex = 8, + CBaseEntity = 7, + CBaseDoor = 6, + CBaseCombatCharacter = 4, + CBaseAnimatingOverlay = 2, + CBoneFollower = 20, + CBaseAnimating = 1, + CInfoLightingRelative = 76, + CAI_BaseNPC = 0, + CBeam = 19, + CBaseViewModel = 18, + CBaseProjectile = 14, + CBaseParticleEntity = 12, + CBaseGrenade = 9, + CBaseCombatWeapon = 5 +}; + +enum +{ + TF_STATE_ACTIVE = 0, + TF_STATE_WELCOME, + TF_STATE_OBSERVER, + TF_STATE_DYING, + TF_STATE_COUNT +}; + +enum +{ + TF_CLASS_UNDEFINED = 0, + TF_CLASS_SCOUT, + TF_CLASS_SNIPER, + TF_CLASS_SOLDIER, + TF_CLASS_DEMOMAN, + TF_CLASS_MEDIC, + TF_CLASS_HEAVY, + TF_CLASS_PYRO, + TF_CLASS_SPY, + TF_CLASS_ENGINEER, + TF_CLASS_CIVILIAN, + TF_CLASS_COUNT_ALL, + TF_CLASS_RANDOM +}; + +enum +{ + TF_TEAM_RED = LAST_SHARED_TEAM + 1, + TF_TEAM_BLUE, + TF_TEAM_COUNT +}; + +enum +{ + TEAM_ROLE_NONE = 0, + TEAM_ROLE_DEFENDERS, + TEAM_ROLE_ATTACKERS, + NUM_TEAM_ROLES +}; + +enum ETFWeaponType +{ + TF_WEAPON_NONE, + TF_WEAPON_BAT, + TF_WEAPON_BAT_WOOD, + TF_WEAPON_BOTTLE, + TF_WEAPON_FIREAXE, + TF_WEAPON_CLUB, + TF_WEAPON_CROWBAR, + TF_WEAPON_KNIFE, + TF_WEAPON_FISTS, + TF_WEAPON_SHOVEL, + TF_WEAPON_WRENCH, + TF_WEAPON_BONESAW, + TF_WEAPON_SHOTGUN_PRIMARY, + TF_WEAPON_SHOTGUN_SOLDIER, + TF_WEAPON_SHOTGUN_HWG, + TF_WEAPON_SHOTGUN_PYRO, + TF_WEAPON_SCATTERGUN, + TF_WEAPON_SNIPERRIFLE, + TF_WEAPON_MINIGUN, + TF_WEAPON_SMG, + TF_WEAPON_SYRINGEGUN_MEDIC, + TF_WEAPON_TRANQ, + TF_WEAPON_ROCKETLAUNCHER, + TF_WEAPON_GRENADELAUNCHER, + TF_WEAPON_PIPEBOMBLAUNCHER, + TF_WEAPON_FLAMETHROWER, + TF_WEAPON_GRENADE_NORMAL, + TF_WEAPON_GRENADE_CONCUSSION, + TF_WEAPON_GRENADE_NAIL, + TF_WEAPON_GRENADE_MIRV, + TF_WEAPON_GRENADE_MIRV_DEMOMAN, + TF_WEAPON_GRENADE_NAPALM, + TF_WEAPON_GRENADE_GAS, + TF_WEAPON_GRENADE_EMP, + TF_WEAPON_GRENADE_CALTROP, + TF_WEAPON_GRENADE_PIPEBOMB, + TF_WEAPON_GRENADE_SMOKE_BOMB, + TF_WEAPON_GRENADE_HEAL, + TF_WEAPON_GRENADE_STUNBALL, + TF_WEAPON_GRENADE_JAR, + TF_WEAPON_GRENADE_JAR_MILK, + TF_WEAPON_PISTOL, + TF_WEAPON_PISTOL_SCOUT, + TF_WEAPON_REVOLVER, + TF_WEAPON_NAILGUN, + TF_WEAPON_PDA, + TF_WEAPON_PDA_ENGINEER_BUILD, + TF_WEAPON_PDA_ENGINEER_DESTROY, + TF_WEAPON_PDA_SPY, + TF_WEAPON_BUILDER, + TF_WEAPON_MEDIGUN, + TF_WEAPON_GRENADE_MIRVBOMB, + TF_WEAPON_FLAMETHROWER_ROCKET, + TF_WEAPON_GRENADE_DEMOMAN, + TF_WEAPON_SENTRY_BULLET, + TF_WEAPON_SENTRY_ROCKET, + TF_WEAPON_DISPENSER, + TF_WEAPON_INVIS, + TF_WEAPON_FLAREGUN, + TF_WEAPON_LUNCHBOX, + TF_WEAPON_JAR, + TF_WEAPON_COMPOUND_BOW, + TF_WEAPON_BUFF_ITEM, + TF_WEAPON_PUMPKIN_BOMB, + TF_WEAPON_SWORD, + TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT, + TF_WEAPON_LIFELINE, + TF_WEAPON_LASER_POINTER, + TF_WEAPON_DISPENSER_GUN, + TF_WEAPON_SENTRY_REVENGE, + TF_WEAPON_JAR_MILK, + TF_WEAPON_HANDGUN_SCOUT_PRIMARY, + TF_WEAPON_BAT_FISH, + TF_WEAPON_CROSSBOW, + TF_WEAPON_STICKBOMB, + TF_WEAPON_HANDGUN_SCOUT_SECONDARY, + TF_WEAPON_SODA_POPPER, + TF_WEAPON_SNIPERRIFLE_DECAP, + TF_WEAPON_RAYGUN, + TF_WEAPON_PARTICLE_CANNON, + TF_WEAPON_MECHANICAL_ARM, + TF_WEAPON_DRG_POMSON, + TF_WEAPON_BAT_GIFTWRAP, + TF_WEAPON_GRENADE_ORNAMENT_BALL, + TF_WEAPON_FLAREGUN_REVENGE, + TF_WEAPON_PEP_BRAWLER_BLASTER, + TF_WEAPON_CLEAVER, + TF_WEAPON_GRENADE_CLEAVER, + TF_WEAPON_STICKY_BALL_LAUNCHER, + TF_WEAPON_GRENADE_STICKY_BALL, + TF_WEAPON_SHOTGUN_BUILDING_RESCUE, + TF_WEAPON_CANNON, + TF_WEAPON_THROWABLE, + TF_WEAPON_GRENADE_THROWABLE, + TF_WEAPON_PDA_SPY_BUILD, + TF_WEAPON_GRENADE_WATERBALLOON, + TF_WEAPON_HARVESTER_SAW, + TF_WEAPON_SPELLBOOK, + TF_WEAPON_SPELLBOOK_PROJECTILE, + TF_WEAPON_SNIPERRIFLE_CLASSIC, + TF_WEAPON_PARACHUTE, + TF_WEAPON_GRAPPLINGHOOK, + TF_WEAPON_PASSTIME_GUN, + TF_WEAPON_CHARGED_SMG, + TF_WEAPON_BREAKABLE_SIGN, + TF_WEAPON_ROCKETPACK, + TF_WEAPON_SLAP, + TF_WEAPON_JAR_GAS, + TF_WEAPON_GRENADE_JAR_GAS, + TF_WEAPON_FLAME_BALL +}; + +enum ETFWeapons +{ + Scout_m_Scattergun = 13, + Scout_m_ScattergunR = 200, + Scout_m_ForceANature = 45, + Scout_m_TheShortstop = 220, + Scout_m_TheSodaPopper = 448, + Scout_m_FestiveScattergun = 669, + Scout_m_BabyFacesBlaster = 772, + Scout_m_SilverBotkillerScattergunMkI = 799, + Scout_m_GoldBotkillerScattergunMkI = 808, + Scout_m_RustBotkillerScattergunMkI = 888, + Scout_m_BloodBotkillerScattergunMkI = 897, + Scout_m_CarbonadoBotkillerScattergunMkI = 906, + Scout_m_DiamondBotkillerScattergunMkI = 915, + Scout_m_SilverBotkillerScattergunMkII = 964, + Scout_m_GoldBotkillerScattergunMkII = 973, + Scout_m_FestiveForceANature = 1078, + Scout_m_TheBackScatter = 1103, + Scout_m_NightTerror = 15002, + Scout_m_TartanTorpedo = 15015, + Scout_m_CountryCrusher = 15021, + Scout_m_BackcountryBlaster = 15029, + Scout_m_SpruceDeuce = 15036, + Scout_m_CurrentEvent = 15053, + Scout_m_MacabreWeb = 15065, + Scout_m_Nutcracker = 15069, + Scout_m_BlueMew = 15106, + Scout_m_FlowerPower = 15107, + Scout_m_ShottoHell = 15108, + Scout_m_CoffinNail = 15131, + Scout_m_KillerBee = 15151, + Scout_m_Corsair = 15157, + Scout_s_ScoutsPistol = 23, + Scout_s_PistolR = 209, + Scout_s_BonkAtomicPunch = 46, + Scout_s_VintageLugermorph = 160, + Scout_s_CritaCola = 163, + Scout_s_MadMilk = 222, + Scout_s_Lugermorph = 294, + Scout_s_TheWinger = 449, + Scout_s_PrettyBoysPocketPistol = 773, + Scout_s_TheFlyingGuillotine = 812, + Scout_s_TheFlyingGuillotineG = 833, + Scout_s_MutatedMilk = 1121, + Scout_s_FestiveBonk = 1145, + Scout_s_RedRockRoscoe = 15013, + Scout_s_HomemadeHeater = 15018, + Scout_s_HickoryHolepuncher = 15035, + Scout_s_LocalHero = 15041, + Scout_s_BlackDahlia = 15046, + Scout_s_SandstoneSpecial = 15056, + Scout_s_MacabreWeb = 15060, + Scout_s_Nutcracker = 15061, + Scout_s_BlueMew = 15100, + Scout_s_BrainCandy = 15101, + Scout_s_ShottoHell = 15102, + Scout_s_DressedToKill = 15126, + Scout_s_Blitzkrieg = 15148, + Scout_s_TheCAPPER = 30666, + Scout_t_Bat = 0, + Scout_t_BatR = 190, + Scout_t_TheSandman = 44, + Scout_t_TheHolyMackerel = 221, + Scout_t_TheCandyCane = 317, + Scout_t_TheBostonBasher = 325, + Scout_t_SunonaStick = 349, + Scout_t_TheFanOWar = 355, + Scout_t_TheAtomizer = 450, + Scout_t_ThreeRuneBlade = 452, + Scout_t_TheConscientiousObjector = 474, + Scout_t_UnarmedCombat = 572, + Scout_t_TheWrapAssassin = 648, + Scout_t_FestiveBat = 660, + Scout_t_TheFreedomStaff = 880, + Scout_t_TheBatOuttaHell = 939, + Scout_t_TheMemoryMaker = 954, + Scout_t_FestiveHolyMackerel = 999, + Scout_t_TheHamShank = 1013, + Scout_t_TheNecroSmasher = 1123, + Scout_t_TheCrossingGuard = 1127, + Scout_t_Batsaber = 30667, + Scout_t_PrinnyMachete = 30758, + Soldier_m_RocketLauncher = 18, + Soldier_m_RocketLauncherR = 205, + Soldier_m_TheDirectHit = 127, + Soldier_m_TheBlackBox = 228, + Soldier_m_RocketJumper = 237, + Soldier_m_TheLibertyLauncher = 414, + Soldier_m_TheCowMangler5000 = 441, + Soldier_m_TheOriginal = 513, + Soldier_m_FestiveRocketLauncher = 658, + Soldier_m_TheBeggarsBazooka = 730, + Soldier_m_SilverBotkillerRocketLauncherMkI = 800, + Soldier_m_GoldBotkillerRocketLauncherMkI = 809, + Soldier_m_RustBotkillerRocketLauncherMkI = 889, + Soldier_m_BloodBotkillerRocketLauncherMkI = 898, + Soldier_m_CarbonadoBotkillerRocketLauncherMkI = 907, + Soldier_m_DiamondBotkillerRocketLauncherMkI = 916, + Soldier_m_SilverBotkillerRocketLauncherMkII = 965, + Soldier_m_GoldBotkillerRocketLauncherMkII = 974, + Soldier_m_FestiveBlackBox = 1085, + Soldier_m_TheAirStrike = 1104, + Soldier_m_WoodlandWarrior = 15006, + Soldier_m_SandCannon = 15014, + Soldier_m_AmericanPastoral = 15028, + Soldier_m_SmalltownBringdown = 15043, + Soldier_m_ShellShocker = 15052, + Soldier_m_AquaMarine = 15057, + Soldier_m_Autumn = 15081, + Soldier_m_BlueMew = 15104, + Soldier_m_BrainCandy = 15105, + Soldier_m_CoffinNail = 15129, + Soldier_m_HighRollers = 15130, + Soldier_m_Warhawk = 15150, + Soldier_s_SoldiersShotgun = 10, + Soldier_s_ShotgunR = 199, + Soldier_s_TheBuffBanner = 129, + Soldier_s_Gunboats = 133, + Soldier_s_TheBattalionsBackup = 226, + Soldier_s_TheConcheror = 354, + Soldier_s_TheReserveShooter = 415, + Soldier_s_TheRighteousBison = 442, + Soldier_s_TheMantreads = 444, + Soldier_s_FestiveBuffBanner = 1001, + Soldier_s_TheBASEJumper = 1101, + Soldier_s_FestiveShotgun = 1141, + Soldier_s_PanicAttack = 1153, + Soldier_s_BackwoodsBoomstick = 15003, + Soldier_s_RusticRuiner = 15016, + Soldier_s_CivicDuty = 15044, + Soldier_s_LightningRod = 15047, + Soldier_s_Autumn = 15085, + Soldier_s_FlowerPower = 15109, + Soldier_s_CoffinNail = 15132, + Soldier_s_DressedtoKill = 15133, + Soldier_s_RedBear = 15152, + Soldier_t_Shovel = 6, + Soldier_t_ShovelR = 196, + Soldier_t_TheEqualizer = 128, + Soldier_t_ThePainTrain = 154, + Soldier_t_TheHalfZatoichi = 357, + Soldier_t_TheMarketGardener = 416, + Soldier_t_TheDisciplinaryAction = 447, + Soldier_t_TheConscientiousObjector = 474, + Soldier_t_TheEscapePlan = 775, + Soldier_t_TheFreedomStaff = 880, + Soldier_t_TheBatOuttaHell = 939, + Soldier_t_TheMemoryMaker = 954, + Soldier_t_TheHamShank = 1013, + Soldier_t_TheNecroSmasher = 1123, + Soldier_t_TheCrossingGuard = 1127, + Soldier_t_PrinnyMachete = 30758, + Pyro_m_FlameThrower = 21, + Pyro_m_FlameThrowerR = 208, + Pyro_m_TheBackburner = 40, + Pyro_m_TheDegreaser = 215, + Pyro_m_ThePhlogistinator = 594, + Pyro_m_FestiveFlameThrower = 659, + Pyro_m_TheRainblower = 741, + Pyro_m_SilverBotkillerFlameThrowerMkI = 798, + Pyro_m_GoldBotkillerFlameThrowerMkI = 807, + Pyro_m_RustBotkillerFlameThrowerMkI = 887, + Pyro_m_BloodBotkillerFlameThrowerMkI = 896, + Pyro_m_CarbonadoBotkillerFlameThrowerMkI = 905, + Pyro_m_DiamondBotkillerFlameThrowerMkI = 914, + Pyro_m_SilverBotkillerFlameThrowerMkII = 963, + Pyro_m_GoldBotkillerFlameThrowerMkII = 972, + Pyro_m_FestiveBackburner = 1146, + Pyro_m_DragonsFury = 1178, + Pyro_m_ForestFire = 15005, + Pyro_m_BarnBurner = 15017, + Pyro_m_BovineBlazemaker = 15030, + Pyro_m_EarthSkyandFire = 15034, + Pyro_m_FlashFryer = 15049, + Pyro_m_TurbineTorcher = 15054, + Pyro_m_Autumn = 15066, + Pyro_m_PumpkinPatch = 15067, + Pyro_m_Nutcracker = 15068, + Pyro_m_Balloonicorn = 15089, + Pyro_m_Rainbow = 15090, + Pyro_m_CoffinNail = 15115, + Pyro_m_Warhawk = 15141, + Pyro_m_NostromoNapalmer = 30474, + Pyro_s_PyrosShotgun = 12, + Pyro_s_ShotgunR = 199, + Pyro_s_TheFlareGun = 39, + Pyro_s_TheDetonator = 351, + Pyro_s_TheReserveShooter = 415, + Pyro_s_TheManmelter = 595, + Pyro_s_TheScorchShot = 740, + Pyro_s_FestiveFlareGun = 1081, + Pyro_s_FestiveShotgun = 1141, + Pyro_s_PanicAttack = 1153, + Pyro_s_ThermalThruster = 1179, + Pyro_s_GasPasser = 1180, + Pyro_s_BackwoodsBoomstick = 15003, + Pyro_s_RusticRuiner = 15016, + Pyro_s_CivicDuty = 15044, + Pyro_s_LightningRod = 15047, + Pyro_s_Autumn = 15085, + Pyro_s_FlowerPower = 15109, + Pyro_s_CoffinNail = 15132, + Pyro_s_DressedtoKill = 15133, + Pyro_s_RedBear = 15152, + Pyro_t_FireAxe = 2, + Pyro_t_FireAxeR = 192, + Pyro_t_TheAxtinguisher = 38, + Pyro_t_Homewrecker = 153, + Pyro_t_ThePowerjack = 214, + Pyro_t_TheBackScratcher = 326, + Pyro_t_SharpenedVolcanoFragment = 348, + Pyro_t_ThePostalPummeler = 457, + Pyro_t_TheMaul = 466, + Pyro_t_TheConscientiousObjector = 474, + Pyro_t_TheThirdDegree = 593, + Pyro_t_TheLollichop = 739, + Pyro_t_NeonAnnihilator = 813, + Pyro_t_NeonAnnihilatorG = 834, + Pyro_t_TheFreedomStaff = 880, + Pyro_t_TheBatOuttaHell = 939, + Pyro_t_TheMemoryMaker = 954, + Pyro_t_TheFestiveAxtinguisher = 1000, + Pyro_t_TheHamShank = 1013, + Pyro_t_TheNecroSmasher = 1123, + Pyro_t_TheCrossingGuard = 1127, + Pyro_t_HotHand = 1181, + Pyro_t_PrinnyMachete = 30758, + Demoman_m_GrenadeLauncher = 19, + Demoman_m_GrenadeLauncherR = 206, + Demoman_m_TheLochnLoad = 308, + Demoman_m_AliBabasWeeBooties = 405, + Demoman_m_TheBootlegger = 608, + Demoman_m_TheLooseCannon = 996, + Demoman_m_FestiveGrenadeLauncher = 1007, + Demoman_m_TheBASEJumper = 1101, + Demoman_m_TheIronBomber = 1151, + Demoman_m_Autumn = 15077, + Demoman_m_MacabreWeb = 15079, + Demoman_m_Rainbow = 15091, + Demoman_m_SweetDreams = 15092, + Demoman_m_CoffinNail = 15116, + Demoman_m_TopShelf = 15117, + Demoman_m_Warhawk = 15142, + Demoman_m_ButcherBird = 15158, + Demoman_s_StickybombLauncher = 20, + Demoman_s_StickybombLauncherR = 207, + Demoman_s_TheScottishResistance = 130, + Demoman_s_TheCharginTarge = 131, + Demoman_s_StickyJumper = 265, + Demoman_s_TheSplendidScreen = 406, + Demoman_s_FestiveStickybombLauncher = 661, + Demoman_s_SilverBotkillerStickybombLauncherMkI = 797, + Demoman_s_GoldBotkillerStickybombLauncherMkI = 806, + Demoman_s_RustBotkillerStickybombLauncherMkI = 886, + Demoman_s_BloodBotkillerStickybombLauncherMkI = 895, + Demoman_s_CarbonadoBotkillerStickybombLauncherMkI = 904, + Demoman_s_DiamondBotkillerStickybombLauncherMkI = 913, + Demoman_s_SilverBotkillerStickybombLauncherMkII = 962, + Demoman_s_GoldBotkillerStickybombLauncherMkII = 971, + Demoman_s_TheTideTurner = 1099, + Demoman_s_FestiveTarge = 1144, + Demoman_s_TheQuickiebombLauncher = 1150, + Demoman_s_SuddenFlurry = 15009, + Demoman_s_CarpetBomber = 15012, + Demoman_s_BlastedBombardier = 15024, + Demoman_s_RooftopWrangler = 15038, + Demoman_s_LiquidAsset = 15045, + Demoman_s_PinkElephant = 15048, + Demoman_s_Autumn = 15082, + Demoman_s_PumpkinPatch = 15083, + Demoman_s_MacabreWeb = 15084, + Demoman_s_SweetDreams = 15113, + Demoman_s_CoffinNail = 15137, + Demoman_s_DressedtoKill = 15138, + Demoman_s_Blitzkrieg = 15155, + Demoman_t_Bottle = 1, + Demoman_t_BottleR = 191, + Demoman_t_TheEyelander = 132, + Demoman_t_ThePainTrain = 154, + Demoman_t_TheScotsmansSkullcutter = 172, + Demoman_t_HorselessHeadlessHorsemannsHeadtaker = 266, + Demoman_t_UllapoolCaber = 307, + Demoman_t_TheClaidheamhMor = 327, + Demoman_t_TheHalfZatoichi = 357, + Demoman_t_ThePersianPersuader = 404, + Demoman_t_TheConscientiousObjector = 474, + Demoman_t_NessiesNineIron = 482, + Demoman_t_TheScottishHandshake = 609, + Demoman_t_TheFreedomStaff = 880, + Demoman_t_TheBatOuttaHell = 939, + Demoman_t_TheMemoryMaker = 954, + Demoman_t_TheHamShank = 1013, + Demoman_t_FestiveEyelander = 1082, + Demoman_t_TheNecroSmasher = 1123, + Demoman_t_TheCrossingGuard = 1127, + Demoman_t_PrinnyMachete = 30758, + Heavy_m_Minigun = 15, + Heavy_m_MinigunR = 202, + Heavy_m_Natascha = 41, + Heavy_m_IronCurtain = 298, + Heavy_m_TheBrassBeast = 312, + Heavy_m_Tomislav = 424, + Heavy_m_FestiveMinigun = 654, + Heavy_m_SilverBotkillerMinigunMkI = 793, + Heavy_m_GoldBotkillerMinigunMkI = 802, + Heavy_m_TheHuoLongHeater = 811, + Heavy_m_TheHuoLongHeaterG = 832, + Heavy_m_Deflector_mvm = 850, + Heavy_m_RustBotkillerMinigunMkI = 882, + Heavy_m_BloodBotkillerMinigunMkI = 891, + Heavy_m_CarbonadoBotkillerMinigunMkI = 900, + Heavy_m_DiamondBotkillerMinigunMkI = 909, + Heavy_m_SilverBotkillerMinigunMkII = 958, + Heavy_m_GoldBotkillerMinigunMkII = 967, + Heavy_m_KingoftheJungle = 15004, + Heavy_m_IronWood = 15020, + Heavy_m_AntiqueAnnihilator = 15026, + Heavy_m_WarRoom = 15031, + Heavy_m_CitizenPain = 15040, + Heavy_m_BrickHouse = 15055, + Heavy_m_MacabreWeb = 15086, + Heavy_m_PumpkinPatch = 15087, + Heavy_m_Nutcracker = 15088, + Heavy_m_BrainCandy = 15098, + Heavy_m_MisterCuddles = 15099, + Heavy_m_CoffinNail = 15123, + Heavy_m_DressedtoKill = 15124, + Heavy_m_TopShelf = 15125, + Heavy_m_ButcherBird = 15147, + Heavy_s_HeavysShotgun = 11, + Heavy_s_ShotgunR = 199, + Heavy_s_Sandvich = 42, + Heavy_s_TheDalokohsBar = 159, + Heavy_s_TheBuffaloSteakSandvich = 311, + Heavy_s_TheFamilyBusiness = 425, + Heavy_s_Fishcake = 433, + Heavy_s_RoboSandvich = 863, + Heavy_s_FestiveSandvich = 1002, + Heavy_s_FestiveShotgun = 1141, + Heavy_s_PanicAttack = 1153, + Heavy_s_SecondBanana = 1190, + Heavy_s_BackwoodsBoomstick = 15003, + Heavy_s_RusticRuiner = 15016, + Heavy_s_CivicDuty = 15044, + Heavy_s_LightningRod = 15047, + Heavy_s_Autumn = 15085, + Heavy_s_FlowerPower = 15109, + Heavy_s_CoffinNail = 15132, + Heavy_s_DressedtoKill = 15133, + Heavy_s_RedBear = 15152, + Heavy_t_Fists = 5, + Heavy_t_FistsR = 195, + Heavy_t_TheKillingGlovesofBoxing = 43, + Heavy_t_GlovesofRunningUrgently = 239, + Heavy_t_WarriorsSpirit = 310, + Heavy_t_FistsofSteel = 331, + Heavy_t_TheEvictionNotice = 426, + Heavy_t_TheConscientiousObjector = 474, + Heavy_t_ApocoFists = 587, + Heavy_t_TheHolidayPunch = 656, + Heavy_t_TheFreedomStaff = 880, + Heavy_t_TheBatOuttaHell = 939, + Heavy_t_TheMemoryMaker = 954, + Heavy_t_TheHamShank = 1013, + Heavy_t_FestiveGlovesofRunningUrgently = 1084, + Heavy_t_TheBreadBite = 1100, + Heavy_t_TheNecroSmasher = 1123, + Heavy_t_TheCrossingGuard = 1127, + Heavy_t_GlovesofRunningUrgentlyMvM = 1184, + Heavy_t_PrinnyMachete = 30758, + Engi_m_EngineersShotgun = 9, + Engi_m_ShotgunR = 199, + Engi_m_TheFrontierJustice = 141, + Engi_m_TheWidowmaker = 527, + Engi_m_ThePomson6000 = 588, + Engi_m_TheRescueRanger = 997, + Engi_m_FestiveFrontierJustice = 1004, + Engi_m_FestiveShotgun = 1141, + Engi_m_PanicAttack = 1153, + Engi_m_BackwoodsBoomstick = 15003, + Engi_m_RusticRuiner = 15016, + Engi_m_CivicDuty = 15044, + Engi_m_LightningRod = 15047, + Engi_m_Autumn = 15085, + Engi_m_FlowerPower = 15109, + Engi_m_CoffinNail = 15132, + Engi_m_DressedtoKill = 15133, + Engi_m_RedBear = 15152, + Engi_s_EngineersPistol = 22, + Engi_s_PistolR = 209, + Engi_s_TheWrangler = 140, + Engi_s_VintageLugermorph = 160, + Engi_s_Lugermorph = 294, + Engi_s_TheShortCircuit = 528, + Engi_s_FestiveWrangler = 1086, + Engi_s_RedRockRoscoe = 15013, + Engi_s_HomemadeHeater = 15018, + Engi_s_HickoryHolepuncher = 15035, + Engi_s_LocalHero = 15041, + Engi_s_BlackDahlia = 15046, + Engi_s_SandstoneSpecial = 15056, + Engi_s_MacabreWeb = 15060, + Engi_s_Nutcracker = 15061, + Engi_s_BlueMew = 15100, + Engi_s_BrainCandy = 15101, + Engi_s_ShottoHell = 15102, + Engi_s_DressedToKill = 15126, + Engi_s_Blitzkrieg = 15148, + Engi_s_TheCAPPER = 30666, + Engi_s_TheGigarCounter = 30668, + Engi_t_Wrench = 7, + Engi_t_WrenchR = 197, + Engi_t_TheGunslinger = 142, + Engi_t_TheSouthernHospitality = 155, + Engi_t_GoldenWrench = 169, + Engi_t_TheJag = 329, + Engi_t_TheEurekaEffect = 589, + Engi_t_FestiveWrench = 662, + Engi_t_SilverBotkillerWrenchMkI = 795, + Engi_t_GoldBotkillerWrenchMkI = 804, + Engi_t_RustBotkillerWrenchMkI = 884, + Engi_t_BloodBotkillerWrenchMkI = 893, + Engi_t_CarbonadoBotkillerWrenchMkI = 902, + Engi_t_DiamondBotkillerWrenchMkI = 911, + Engi_t_SilverBotkillerWrenchMkII = 960, + Engi_t_GoldBotkillerWrenchMkII = 969, + Engi_t_TheNecroSmasher = 1123, + Engi_t_Nutcracker = 15073, + Engi_t_Autumn = 15074, + Engi_t_Boneyard = 15075, + Engi_t_DressedtoKill = 15139, + Engi_t_TopShelf = 15140, + Engi_t_TorquedtoHell = 15114, + Engi_t_Airwolf = 15156, + Engi_t_PrinnyMachete = 30758, + Engi_p_ConstructionPDA = 25, + Engi_p_ConstructionPDAR = 737, + Engi_p_DestructionPDA = 26, + Engi_p_PDA = 28, + Medic_m_SyringeGun = 17, + Medic_m_SyringeGunR = 204, + Medic_m_TheBlutsauger = 36, + Medic_m_CrusadersCrossbow = 305, + Medic_m_TheOverdose = 412, + Medic_m_FestiveCrusadersCrossbow = 1079, + Medic_s_MediGun = 29, + Medic_s_MediGunR = 211, + Medic_s_TheKritzkrieg = 35, + Medic_s_TheQuickFix = 411, + Medic_s_FestiveMediGun = 663, + Medic_s_SilverBotkillerMediGunMkI = 796, + Medic_s_GoldBotkillerMediGunMkI = 805, + Medic_s_RustBotkillerMediGunMkI = 885, + Medic_s_BloodBotkillerMediGunMkI = 894, + Medic_s_CarbonadoBotkillerMediGunMkI = 903, + Medic_s_DiamondBotkillerMediGunMkI = 912, + Medic_s_SilverBotkillerMediGunMkII = 961, + Medic_s_GoldBotkillerMediGunMkII = 970, + Medic_s_TheVaccinator = 998, + Medic_s_MaskedMender = 15008, + Medic_s_WrappedReviver = 15010, + Medic_s_ReclaimedReanimator = 15025, + Medic_s_CivilServant = 15039, + Medic_s_SparkofLife = 15050, + Medic_s_Wildwood = 15078, + Medic_s_FlowerPower = 15097, + Medic_s_DressedToKill = 15121, + Medic_s_HighRollers = 15122, + Medic_s_CoffinNail = 15123, + Medic_s_Blitzkrieg = 15145, + Medic_s_Corsair = 15146, + Medic_t_Bonesaw = 8, + Medic_t_BonesawR = 198, + Medic_t_TheUbersaw = 37, + Medic_t_TheVitaSaw = 173, + Medic_t_Amputator = 304, + Medic_t_TheSolemnVow = 413, + Medic_t_TheConscientiousObjector = 474, + Medic_t_TheFreedomStaff = 880, + Medic_t_TheBatOuttaHell = 939, + Medic_t_TheMemoryMaker = 954, + Medic_t_FestiveUbersaw = 1003, + Medic_t_TheHamShank = 1013, + Medic_t_TheNecroSmasher = 1123, + Medic_t_TheCrossingGuard = 1127, + Medic_t_FestiveBonesaw = 1143, + Medic_t_PrinnyMachete = 30758, + Sniper_m_SniperRifle = 14, + Sniper_m_SniperRifleR = 201, + Sniper_m_TheHuntsman = 56, + Sniper_m_TheSydneySleeper = 230, + Sniper_m_TheBazaarBargain = 402, + Sniper_m_TheMachina = 526, + Sniper_m_FestiveSniperRifle = 664, + Sniper_m_TheHitmansHeatmaker = 752, + Sniper_m_SilverBotkillerSniperRifleMkI = 792, + Sniper_m_GoldBotkillerSniperRifleMkI = 801, + Sniper_m_TheAWPerHand = 851, + Sniper_m_RustBotkillerSniperRifleMkI = 881, + Sniper_m_BloodBotkillerSniperRifleMkI = 890, + Sniper_m_CarbonadoBotkillerSniperRifleMkI = 899, + Sniper_m_DiamondBotkillerSniperRifleMkI = 908, + Sniper_m_SilverBotkillerSniperRifleMkII = 957, + Sniper_m_GoldBotkillerSniperRifleMkII = 966, + Sniper_m_FestiveHuntsman = 1005, + Sniper_m_TheFortifiedCompound = 1092, + Sniper_m_TheClassic = 1098, + Sniper_m_NightOwl = 15000, + Sniper_m_PurpleRange = 15007, + Sniper_m_LumberFromDownUnder = 15019, + Sniper_m_ShotintheDark = 15023, + Sniper_m_Bogtrotter = 15033, + Sniper_m_Thunderbolt = 15059, + Sniper_m_PumpkinPatch = 15070, + Sniper_m_Boneyard = 15071, + Sniper_m_Wildwood = 15072, + Sniper_m_Balloonicorn = 15111, + Sniper_m_Rainbow = 15112, + Sniper_m_CoffinNail = 15135, + Sniper_m_DressedtoKill = 15136, + Sniper_m_Airwolf = 15154, + Sniper_m_ShootingStar = 30665, + Sniper_s_SMG = 16, + Sniper_s_SMGR = 203, + Sniper_s_TheRazorback = 57, + Sniper_s_Jarate = 58, + Sniper_s_DarwinsDangerShield = 231, + Sniper_s_CozyCamper = 642, + Sniper_s_TheCleanersCarbine = 751, + Sniper_s_FestiveJarate = 1083, + Sniper_s_TheSelfAwareBeautyMark = 1105, + Sniper_s_FestiveSMG = 1149, + Sniper_s_WoodsyWidowmaker = 15001, + Sniper_s_PlaidPotshotter = 15022, + Sniper_s_TreadplateTormenter = 15032, + Sniper_s_TeamSprayer = 15037, + Sniper_s_LowProfile = 15058, + Sniper_s_Wildwood = 15076, + Sniper_s_BlueMew = 15110, + Sniper_s_HighRollers = 15134, + Sniper_s_Blitzkrieg = 15153, + Sniper_t_Kukri = 3, + Sniper_t_KukriR = 193, + Sniper_t_TheTribalmansShiv = 171, + Sniper_t_TheBushwacka = 232, + Sniper_t_TheShahanshah = 401, + Sniper_t_TheConscientiousObjector = 474, + Sniper_t_TheFreedomStaff = 880, + Sniper_t_TheBatOuttaHell = 939, + Sniper_t_TheMemoryMaker = 954, + Sniper_t_TheHamShank = 1013, + Sniper_t_TheNecroSmasher = 1123, + Sniper_t_TheCrossingGuard = 1127, + Sniper_t_PrinnyMachete = 30758, + Spy_m_Revolver = 24, + Spy_m_RevolverR = 210, + Spy_m_TheAmbassador = 61, + Spy_m_BigKill = 161, + Spy_m_LEtranger = 224, + Spy_m_TheEnforcer = 460, + Spy_m_TheDiamondback = 525, + Spy_m_FestiveAmbassador = 1006, + Spy_m_FestiveRevolver = 1142, + Spy_m_PsychedelicSlugger = 15011, + Spy_m_OldCountry = 15027, + Spy_m_Mayor = 15042, + Spy_m_DeadReckoner = 15051, + Spy_m_Boneyard = 15062, + Spy_m_Wildwood = 15063, + Spy_m_MacabreWeb = 15064, + Spy_m_FlowerPower = 15103, + Spy_m_TopShelf = 15128, + Spy_m_CoffinNail = 15129, + Spy_m_Blitzkrieg = 15149, + Spy_s_Sapper = 735, + Spy_s_SapperR = 736, + Spy_s_TheRedTapeRecorder = 810, + Spy_s_TheRedTapeRecorderG = 831, + Spy_s_TheApSapG = 933, + Spy_s_FestiveSapper = 1080, + Spy_s_TheSnackAttack = 1102, + Spy_t_Knife = 4, + Spy_t_KnifeR = 194, + Spy_t_YourEternalReward = 225, + Spy_t_ConniversKunai = 356, + Spy_t_TheBigEarner = 461, + Spy_t_TheWangaPrick = 574, + Spy_t_TheSharpDresser = 638, + Spy_t_TheSpycicle = 649, + Spy_t_FestiveKnife = 665, + Spy_t_TheBlackRose = 727, + Spy_t_SilverBotkillerKnifeMkI = 794, + Spy_t_GoldBotkillerKnifeMkI = 803, + Spy_t_RustBotkillerKnifeMkI = 883, + Spy_t_BloodBotkillerKnifeMkI = 892, + Spy_t_CarbonadoBotkillerKnifeMkI = 901, + Spy_t_DiamondBotkillerKnifeMkI = 910, + Spy_t_SilverBotkillerKnifeMkII = 959, + Spy_t_GoldBotkillerKnifeMkII = 968, + Spy_t_Boneyard = 15062, + Spy_t_BlueMew = 15094, + Spy_t_BrainCandy = 15095, + Spy_t_StabbedtoHell = 15096, + Spy_t_DressedtoKill = 15118, + Spy_t_TopShelf = 15119, + Spy_t_Blitzkrieg = 15143, + Spy_t_Airwolf = 15144, + Spy_t_PrinnyMachete = 30758, + Spy_d_DisguiseKitPDA = 27, + Spy_w_InvisWatch = 30, + Spy_w_InvisWatchR = 212, + Spy_w_TheDeadRinger = 59, + Spy_w_TheCloakandDagger = 60, + Spy_w_EnthusiastsTimepiece = 297, + Spy_w_TheQuackenbirdt = 947, + Misc_t_FryingPan = 264, + Misc_t_GoldFryingPan = 1071, + Misc_t_Saxxy = 423 +}; + +enum struct EWeaponType +{ + UNKNOWN, + HITSCAN, + PROJECTILE, + MELEE +}; + +enum EWeaponSlot +{ + SLOT_PRIMARY, + SLOT_SECONDARY, + SLOT_MELEE +}; + +enum ProjectileType_t +{ + TF_PROJECTILE_NONE, + TF_PROJECTILE_BULLET, + TF_PROJECTILE_ROCKET, + TF_PROJECTILE_PIPEBOMB, + TF_PROJECTILE_PIPEBOMB_REMOTE, + TF_PROJECTILE_SYRINGE, + TF_PROJECTILE_FLARE, + TF_PROJECTILE_JAR, + TF_PROJECTILE_ARROW, + TF_PROJECTILE_FLAME_ROCKET, + TF_PROJECTILE_JAR_MILK, + TF_PROJECTILE_HEALING_BOLT, + TF_PROJECTILE_ENERGY_BALL, + TF_PROJECTILE_ENERGY_RING, + TF_PROJECTILE_PIPEBOMB_PRACTICE, + TF_PROJECTILE_CLEAVER, + TF_PROJECTILE_STICKY_BALL, + TF_PROJECTILE_CANNONBALL, + TF_PROJECTILE_BUILDING_REPAIR_BOLT, + TF_PROJECTILE_FESTIVE_ARROW, + TF_PROJECTILE_THROWABLE, + TF_PROJECTILE_SPELL, + TF_PROJECTILE_FESTIVE_JAR, + TF_PROJECTILE_FESTIVE_HEALING_BOLT, + TF_PROJECTILE_BREADMONSTER_JARATE, + TF_PROJECTILE_BREADMONSTER_MADMILK, + TF_PROJECTILE_GRAPPLINGHOOK, + TF_PROJECTILE_SENTRY_ROCKET, + TF_PROJECTILE_BREAD_MONSTER, + TF_PROJECTILE_JAR_GAS, + TF_PROJECTILE_BALLOFFIRE, + TF_NUM_PROJECTILES +}; + +enum ArrowModels +{ + MODEL_ARROW_REGULAR, + MODEL_ARROW_BUILDING_REPAIR, + MODEL_SNOWBALL, + MODEL_FESTIVE_ARROW_REGULAR, + MODEL_SYRINGE, + MODEL_FESTIVE_HEALING_BOLT, + MODEL_BREAD_MONSTER, + MODEL_GRAPPLINGHOOK, + MODEL_THROWING_KNIFE, + TF_ARROW_MODEL_COUNT +}; + +enum MedigunChargeTypes +{ + MEDIGUN_CHARGE_INVALID = -1, + MEDIGUN_CHARGE_INVULN = 0, + MEDIGUN_CHARGE_CRITICALBOOST, + MEDIGUN_CHARGE_MEGAHEAL, + MEDIGUN_CHARGE_BULLET_RESIST, + MEDIGUN_CHARGE_BLAST_RESIST, + MEDIGUN_CHARGE_FIRE_RESIST, + MEDIGUN_NUM_CHARGE_TYPES +}; + +enum MedicCallerType +{ + CALLER_TYPE_NORMAL, + CALLER_TYPE_AUTO, + CALLER_TYPE_REVIVE_EASY, + CALLER_TYPE_REVIVE_MEDIUM, + CALLER_TYPE_REVIVE_HARD +}; + +enum ETFCond +{ + TF_COND_INVALID = -1, + TF_COND_AIMING, + TF_COND_ZOOMED, + TF_COND_DISGUISING, + TF_COND_DISGUISED, + TF_COND_STEALTHED, + TF_COND_INVULNERABLE, + TF_COND_TELEPORTED, + TF_COND_TAUNTING, + TF_COND_INVULNERABLE_WEARINGOFF, + TF_COND_STEALTHED_BLINK, + TF_COND_SELECTED_TO_TELEPORT, + TF_COND_CRITBOOSTED, + TF_COND_TMPDAMAGEBONUS, + TF_COND_FEIGN_DEATH, + TF_COND_PHASE, + TF_COND_STUNNED, + TF_COND_OFFENSEBUFF, + TF_COND_SHIELD_CHARGE, + TF_COND_DEMO_BUFF, + TF_COND_ENERGY_BUFF, + TF_COND_RADIUSHEAL, + TF_COND_HEALTH_BUFF, + TF_COND_BURNING, + TF_COND_HEALTH_OVERHEALED, + TF_COND_URINE, + TF_COND_BLEEDING, + TF_COND_DEFENSEBUFF, + TF_COND_MAD_MILK, + TF_COND_MEGAHEAL, + TF_COND_REGENONDAMAGEBUFF, + TF_COND_MARKEDFORDEATH, + TF_COND_NOHEALINGDAMAGEBUFF, + TF_COND_SPEED_BOOST, + TF_COND_CRITBOOSTED_PUMPKIN, + TF_COND_CRITBOOSTED_USER_BUFF, + TF_COND_CRITBOOSTED_DEMO_CHARGE, + TF_COND_SODAPOPPER_HYPE, + TF_COND_CRITBOOSTED_FIRST_BLOOD, + TF_COND_CRITBOOSTED_BONUS_TIME, + TF_COND_CRITBOOSTED_CTF_CAPTURE, + TF_COND_CRITBOOSTED_ON_KILL, + TF_COND_CANNOT_SWITCH_FROM_MELEE, + TF_COND_DEFENSEBUFF_NO_CRIT_BLOCK, + TF_COND_REPROGRAMMED, + TF_COND_CRITBOOSTED_RAGE_BUFF, + TF_COND_DEFENSEBUFF_HIGH, + TF_COND_SNIPERCHARGE_RAGE_BUFF, + TF_COND_DISGUISE_WEARINGOFF, + TF_COND_MARKEDFORDEATH_SILENT, + TF_COND_DISGUISED_AS_DISPENSER, + TF_COND_SAPPED, + TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED, + TF_COND_INVULNERABLE_USER_BUFF, + TF_COND_HALLOWEEN_BOMB_HEAD, + TF_COND_HALLOWEEN_THRILLER, + TF_COND_RADIUSHEAL_ON_DAMAGE, + TF_COND_CRITBOOSTED_CARD_EFFECT, + TF_COND_INVULNERABLE_CARD_EFFECT, + TF_COND_MEDIGUN_UBER_BULLET_RESIST, + TF_COND_MEDIGUN_UBER_BLAST_RESIST, + TF_COND_MEDIGUN_UBER_FIRE_RESIST, + TF_COND_MEDIGUN_SMALL_BULLET_RESIST, + TF_COND_MEDIGUN_SMALL_BLAST_RESIST, + TF_COND_MEDIGUN_SMALL_FIRE_RESIST, + TF_COND_STEALTHED_USER_BUFF, + TF_COND_MEDIGUN_DEBUFF, + TF_COND_STEALTHED_USER_BUFF_FADING, + TF_COND_BULLET_IMMUNE, + TF_COND_BLAST_IMMUNE, + TF_COND_FIRE_IMMUNE, + TF_COND_PREVENT_DEATH, + TF_COND_MVM_BOT_STUN_RADIOWAVE, + TF_COND_HALLOWEEN_SPEED_BOOST, + TF_COND_HALLOWEEN_QUICK_HEAL, + TF_COND_HALLOWEEN_GIANT, + TF_COND_HALLOWEEN_TINY, + TF_COND_HALLOWEEN_IN_HELL, + TF_COND_HALLOWEEN_GHOST_MODE, + TF_COND_MINICRITBOOSTED_ON_KILL, + TF_COND_OBSCURED_SMOKE, + TF_COND_PARACHUTE_ACTIVE, + TF_COND_BLASTJUMPING, + TF_COND_HALLOWEEN_KART, + TF_COND_HALLOWEEN_KART_DASH, + TF_COND_BALLOON_HEAD, + TF_COND_MELEE_ONLY, + TF_COND_SWIMMING_CURSE, + TF_COND_FREEZE_INPUT, + TF_COND_HALLOWEEN_KART_CAGE, + TF_COND_HASRUNE, //TF_COND_DONOTUSE_0 + TF_COND_RUNE_STRENGTH, + TF_COND_RUNE_HASTE, + TF_COND_RUNE_REGEN, + TF_COND_RUNE_RESIST, + TF_COND_RUNE_VAMPIRE, + TF_COND_RUNE_REFLECT, + TF_COND_RUNE_PRECISION, + TF_COND_RUNE_AGILITY, + TF_COND_GRAPPLINGHOOK, + TF_COND_GRAPPLINGHOOK_SAFEFALL, + TF_COND_GRAPPLINGHOOK_LATCHED, + TF_COND_GRAPPLINGHOOK_BLEEDING, + TF_COND_AFTERBURN_IMMUNE, + TF_COND_RUNE_KNOCKOUT, + TF_COND_RUNE_IMBALANCE, + TF_COND_CRITBOOSTED_RUNE_TEMP, + TF_COND_PASSTIME_INTERCEPTION, + TF_COND_SWIMMING_NO_EFFECTS, + TF_COND_PURGATORY, + TF_COND_RUNE_KING, + TF_COND_RUNE_PLAGUE, + TF_COND_RUNE_SUPERNOVA, + TF_COND_PLAGUE, + TF_COND_KING_BUFFED, + TF_COND_TEAM_GLOWS, + TF_COND_KNOCKED_INTO_AIR, + TF_COND_COMPETITIVE_WINNER, + TF_COND_COMPETITIVE_LOSER, + TF_COND_HEALING_DEBUFF, + TF_COND_PASSTIME_PENALTY_DEBUFF, + TF_COND_GRAPPLED_TO_PLAYER, + TF_COND_GRAPPLED_BY_PLAYER, + TF_COND_PARACHUTE_DEPLOYED, + TF_COND_GAS, + TF_COND_BURNING_PYRO, + TF_COND_ROCKETPACK, + TF_COND_LOST_FOOTING, + TF_COND_AIR_CURRENT, + TF_COND_HALLOWEEN_HELL_HEAL, + TF_COND_POWERUPMODE_DOMINANT +}; + +enum ETFConds +{ + TFCond_Slowed = (1 << 0), // 0 + TFCond_Zoomed = (1 << 1), // 1 + TFCond_Disguised = (1 << 3), // 3 + TFCond_Stealthed = (1 << 4), // 4 + TFCond_Ubercharged = (1 << 5), // 5 + TFCond_Taunting = (1 << 7), // 7 + TFCond_Bonked = (1 << 14), // 14 + TFCond_Stunned = (1 << 15), // 15 + TFCond_Charging = (1 << 17), // 17 + TFCond_OnFire = (1 << 22), // 22 + TFCond_Jarated = (1 << 24), // 24 + TFCond_Bleeding = (1 << 25), // 25 + TFCond_Milked = (1 << 27), // 27 + TFCond_MegaHeal = (1 << 28), // 28 + + TFCondEx_PyroCrits = (1 << 12), // 44 + TFCondEx_BulletCharge = (1 << 26), // 58 + TFCondEx_ExplosiveCharge = (1 << 27), // 59 + TFCondEx_FireCharge = (1 << 28), // 60 + + TFCondEx2_BulletImmune = (1 << 3), // 67 + TFCondEx2_BlastImmune = (1 << 4), // 68 + TFCondEx2_FireImmune = (1 << 5), // 69 + TFCondEx2_HalloweenGhostMode = (1 << 13), // 77 + TFCondEx2_InKart = (1 << 18), // 82 + TFCondEx2_StrengthRune = (1 << 26), // 90 + TFCondEx2_HasteRune = (1 << 27), // 91 + TFCondEx2_RegenRune = (1 << 28), // 92 + TFCondEx2_ResistRune = (1 << 29), // 93 + TFCondEx2_VampireRune = (1 << 30), // 94 + TFCondEx2_ReflectRune = (1 << 31), // 95 + + TFCondEx3_PrecisionRune = (1 << 0), // 96 + TFCondEx3_AgilityRune = (1 << 1), // 97 + TFCondEx3_KnockoutRune = (1 << 7), // 103 + TFCondEx3_ImbalanceRune = (1 << 8), // 104 + TFCondEx3_CritboostedTempRune = (1 << 9), // 105 + TFCondEx3_KingRune = (1 << 13), // 109 + TFCondEx3_PlagueRune = (1 << 14), // 110 + TFCondEx3_SupernovaRune = (1 << 15), // 111 + TFCondEx3_KingBuff = (1 << 17), // 113 +}; + +enum ETFDmgCustom +{ + TF_DMG_CUSTOM_NONE = 0, + TF_DMG_CUSTOM_HEADSHOT, + TF_DMG_CUSTOM_BACKSTAB, + TF_DMG_CUSTOM_BURNING, + TF_DMG_WRENCH_FIX, + TF_DMG_CUSTOM_MINIGUN, + TF_DMG_CUSTOM_SUICIDE, + TF_DMG_CUSTOM_TAUNTATK_HADOUKEN, + TF_DMG_CUSTOM_BURNING_FLARE, + TF_DMG_CUSTOM_TAUNTATK_HIGH_NOON, + TF_DMG_CUSTOM_TAUNTATK_GRAND_SLAM, + TF_DMG_CUSTOM_PENETRATE_MY_TEAM, + TF_DMG_CUSTOM_PENETRATE_ALL_PLAYERS, + TF_DMG_CUSTOM_TAUNTATK_FENCING, + TF_DMG_CUSTOM_PENETRATE_NONBURNING_TEAMMATE, + TF_DMG_CUSTOM_TAUNTATK_ARROW_STAB, + TF_DMG_CUSTOM_TELEFRAG, + TF_DMG_CUSTOM_BURNING_ARROW, + TF_DMG_CUSTOM_FLYINGBURN, + TF_DMG_CUSTOM_PUMPKIN_BOMB, + TF_DMG_CUSTOM_DECAPITATION, + TF_DMG_CUSTOM_TAUNTATK_GRENADE, + TF_DMG_CUSTOM_BASEBALL, + TF_DMG_CUSTOM_CHARGE_IMPACT, + TF_DMG_CUSTOM_TAUNTATK_BARBARIAN_SWING, + TF_DMG_CUSTOM_AIR_STICKY_BURST, + TF_DMG_CUSTOM_DEFENSIVE_STICKY, + TF_DMG_CUSTOM_PICKAXE, + TF_DMG_CUSTOM_ROCKET_DIRECTHIT, + TF_DMG_CUSTOM_TAUNTATK_UBERSLICE, + TF_DMG_CUSTOM_PLAYER_SENTRY, + TF_DMG_CUSTOM_STANDARD_STICKY, + TF_DMG_CUSTOM_SHOTGUN_REVENGE_CRIT, + TF_DMG_CUSTOM_TAUNTATK_ENGINEER_GUITAR_SMASH, + TF_DMG_CUSTOM_BLEEDING, + TF_DMG_CUSTOM_GOLD_WRENCH, + TF_DMG_CUSTOM_CARRIED_BUILDING, + TF_DMG_CUSTOM_COMBO_PUNCH, + TF_DMG_CUSTOM_TAUNTATK_ENGINEER_ARM_KILL, + TF_DMG_CUSTOM_FISH_KILL, + TF_DMG_CUSTOM_TRIGGER_HURT, + TF_DMG_CUSTOM_DECAPITATION_BOSS, + TF_DMG_CUSTOM_STICKBOMB_EXPLOSION, + TF_DMG_CUSTOM_AEGIS_ROUND, + TF_DMG_CUSTOM_FLARE_EXPLOSION, + TF_DMG_CUSTOM_BOOTS_STOMP, + TF_DMG_CUSTOM_PLASMA, + TF_DMG_CUSTOM_PLASMA_CHARGED, + TF_DMG_CUSTOM_PLASMA_GIB, + TF_DMG_CUSTOM_PRACTICE_STICKY, + TF_DMG_CUSTOM_EYEBALL_ROCKET, + TF_DMG_CUSTOM_HEADSHOT_DECAPITATION, + TF_DMG_CUSTOM_TAUNTATK_ARMAGEDDON, + TF_DMG_CUSTOM_FLARE_PELLET, + TF_DMG_CUSTOM_CLEAVER, + TF_DMG_CUSTOM_CLEAVER_CRIT, + TF_DMG_CUSTOM_SAPPER_RECORDER_DEATH, + TF_DMG_CUSTOM_MERASMUS_PLAYER_BOMB, + TF_DMG_CUSTOM_MERASMUS_GRENADE, + TF_DMG_CUSTOM_MERASMUS_ZAP, + TF_DMG_CUSTOM_MERASMUS_DECAPITATION, + TF_DMG_CUSTOM_CANNONBALL_PUSH, + TF_DMG_CUSTOM_TAUNTATK_ALLCLASS_GUITAR_RIFF, + TF_DMG_CUSTOM_THROWABLE, + TF_DMG_CUSTOM_THROWABLE_KILL, + TF_DMG_CUSTOM_SPELL_TELEPORT, + TF_DMG_CUSTOM_SPELL_SKELETON, + TF_DMG_CUSTOM_SPELL_MIRV, + TF_DMG_CUSTOM_SPELL_METEOR, + TF_DMG_CUSTOM_SPELL_LIGHTNING, + TF_DMG_CUSTOM_SPELL_FIREBALL, + TF_DMG_CUSTOM_SPELL_MONOCULUS, + TF_DMG_CUSTOM_SPELL_BLASTJUMP, + TF_DMG_CUSTOM_SPELL_BATS, + TF_DMG_CUSTOM_SPELL_TINY, + TF_DMG_CUSTOM_KART, + TF_DMG_CUSTOM_GIANT_HAMMER, + TF_DMG_CUSTOM_RUNE_REFLECT, + TF_DMG_CUSTOM_END +}; + +enum HalloweenBossType +{ + HALLOWEEN_BOSS_INVALID = 0, + HALLOWEEN_BOSS_HHH = 1, + HALLOWEEN_BOSS_MONOCULUS = 2, + HALLOWEEN_BOSS_MERASMUS = 3 +}; + +enum PowerupBottleType_t +{ + POWERUP_BOTTLE_NONE, + POWERUP_BOTTLE_CRITBOOST, + POWERUP_BOTTLE_UBERCHARGE, + POWERUP_BOTTLE_RECALL, + POWERUP_BOTTLE_REFILL_AMMO, + POWERUP_BOTTLE_BUILDINGS_INSTANT_UPGRADE, + POWERUP_BOTTLE_RADIUS_STEALTH, + POWERUP_BOTTLE_TOTAL +}; + +enum ETFFlagType +{ + TF_FLAGTYPE_CTF = 0, + TF_FLAGTYPE_ATTACK_DEFEND, + TF_FLAGTYPE_TERRITORY_CONTROL, + TF_FLAGTYPE_INVADE, + TF_FLAGTYPE_RESOURCE_CONTROL, + TF_FLAGTYPE_ROBOT_DESTRUCTION, + TF_FLAGTYPE_PLAYER_DESTRUCTION +}; + +enum ETFGameType +{ + TF_GAMETYPE_UNDEFINED = 0, + TF_GAMETYPE_CTF, + TF_GAMETYPE_CP, + TF_GAMETYPE_ESCORT, + TF_GAMETYPE_ARENA, + TF_GAMETYPE_MVM, + TF_GAMETYPE_RD, + TF_GAMETYPE_PASSTIME, + TF_GAMETYPE_PD, + TF_GAMETYPE_COUNT +}; + +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 +{ + TF_ARENA_NOTIFICATION_CAREFUL = 0, + TF_ARENA_NOTIFICATION_SITOUT, + TF_ARENA_NOTIFICATION_NOPLAYERS +}; + +enum +{ + MVM_EVENT_POPFILE_NONE = 0, + MVM_EVENT_POPFILE_HALLOWEEN, + MVM_EVENT_POPFILE_MAX_TYPES +}; + +enum +{ + DRAW_ARROW_UP, + DRAW_ARROW_LEFT, + DRAW_ARROW_RIGHT +}; + +enum +{ + TF_HUDTYPE_UNDEFINED = 0, + TF_HUDTYPE_CTF, + TF_HUDTYPE_CP, + TF_HUDTYPE_ESCORT, + TF_HUDTYPE_ARENA, + TF_HUDTYPE_TRAINING +}; + +enum +{ + TF_BUILDING_SENTRY = (1 << 0), + TF_BUILDING_DISPENSER = (1 << 1), + TF_BUILDING_TELEPORT = (1 << 2) +}; + +enum +{ + TF_ITEM_UNDEFINED = 0, + TF_ITEM_CAPTURE_FLAG = (1 << 0), + TF_ITEM_HEALTH_KIT = (1 << 1), + TF_ITEM_ARMOR = (1 << 2), + TF_ITEM_AMMO_PACK = (1 << 3), + TF_ITEM_GRENADE_PACK = (1 << 4) +}; + +enum ETFFlagEventTypes +{ + TF_FLAGEVENT_PICKUP = 1, + TF_FLAGEVENT_CAPTURE, + TF_FLAGEVENT_DEFEND, + TF_FLAGEVENT_DROPPED, + TF_FLAGEVENT_RETURNED, + TF_NUM_FLAG_EVENTS +}; + +enum TauntAttack_t +{ + TAUNTATK_NONE = 0, + TAUNTATK_PYRO_HADOUKEN, + TAUNTATK_HEAVY_EAT, + TAUNTATK_HEAVY_RADIAL_BUFF, + TAUNTATK_HEAVY_HIGH_NOON, + TAUNTATK_SCOUT_DRINK, + TAUNTATK_SCOUT_GRAND_SLAM, + TAUNTATK_MEDIC_INHALE, + TAUNTATK_SPY_FENCING_SLASH_A, + TAUNTATK_SPY_FENCING_SLASH_B, + TAUNTATK_SPY_FENCING_STAB, + TAUNTATK_RPS_KILL, + TAUNTATK_SNIPER_ARROW_STAB_IMPALE, + TAUNTATK_SNIPER_ARROW_STAB_KILL, + TAUNTATK_SOLDIER_GRENADE_KILL, + TAUNTATK_DEMOMAN_BARBARIAN_SWING, + TAUNTATK_MEDIC_UBERSLICE_IMPALE, + TAUNTATK_MEDIC_UBERSLICE_KILL, + TAUNTATK_FLIP_LAND_PARTICLE, + TAUNTATK_RPS_PARTICLE, + TAUNTATK_HIGHFIVE_PARTICLE, + TAUNTATK_ENGINEER_GUITAR_SMASH, + TAUNTATK_ENGINEER_ARM_IMPALE, + TAUNTATK_ENGINEER_ARM_KILL, + TAUNTATK_ENGINEER_ARM_BLEND, + TAUNTATK_SOLDIER_GRENADE_KILL_WORMSIGN, + TAUNTATK_SHOW_ITEM, + TAUNTATK_MEDIC_RELEASE_DOVES, + TAUNTATK_PYRO_ARMAGEDDON, + TAUNTATK_PYRO_SCORCHSHOT, + TAUNTATK_ALLCLASS_GUITAR_RIFF, + TAUNTATK_MEDIC_HEROIC_TAUNT, + TAUNTATK_COUNT +}; + +enum ObjectType_t +{ + OBJ_DISPENSER = 0, + OBJ_TELEPORTER, + OBJ_SENTRYGUN, + OBJ_ATTACHMENT_SAPPER, + OBJ_LAST +}; + +typedef enum +{ + BUILDING_HUD_ALERT_NONE = 0, + BUILDING_HUD_ALERT_LOW_AMMO, + BUILDING_HUD_ALERT_LOW_HEALTH, + BUILDING_HUD_ALERT_VERY_LOW_AMMO, + BUILDING_HUD_ALERT_VERY_LOW_HEALTH, + BUILDING_HUD_ALERT_SAPPER, + MAX_BUILDING_HUD_ALERT_LEVEL +} BuildingHudAlert_t; + +typedef enum +{ + BUILDING_DAMAGE_LEVEL_NONE = 0, + BUILDING_DAMAGE_LEVEL_LIGHT, + BUILDING_DAMAGE_LEVEL_MEDIUM, + BUILDING_DAMAGE_LEVEL_HEAVY, + BUILDING_DAMAGE_LEVEL_CRITICAL, + MAX_BUILDING_DAMAGE_LEVEL +} BuildingDamageLevel_t; + +enum +{ + MODE_TELEPORTER_ENTRANCE = 0, + MODE_TELEPORTER_EXIT +}; + +enum +{ + MODE_SENTRYGUN_NORMAL = 0, + MODE_SENTRYGUN_DISPOSABLE +}; + +enum +{ + MODE_SAPPER_NORMAL = 0, + MODE_SAPPER_ANTI_ROBOT, + MODE_SAPPER_ANTI_ROBOT_RADIUS +}; + +enum ESpyTrapType_t +{ + MODE_SPY_TRAP_RADIUS_STEALTH = 0, + MODE_SPY_TRAP_REPROGRAM, + MODE_SPY_TRAP_MAGNET +}; + +enum +{ + DISPENSER_STATE_IDLE, + DISPENSER_STATE_UPGRADING +}; + +enum +{ + TELEPORTER_STATE_BUILDING = 0, + TELEPORTER_STATE_IDLE, + TELEPORTER_STATE_READY, + TELEPORTER_STATE_SENDING, + TELEPORTER_STATE_RECEIVING, + TELEPORTER_STATE_RECEIVING_RELEASE, + TELEPORTER_STATE_RECHARGING, + TELEPORTER_STATE_UPGRADING, +}; +enum +{ + SENTRY_STATE_INACTIVE = 0, + SENTRY_STATE_SEARCHING, + SENTRY_STATE_ATTACKING, + SENTRY_STATE_UPGRADING, + SENTRY_NUM_STATES +}; + +enum +{ + OF_ALLOW_REPEAT_PLACEMENT = 0x01, + OF_MUST_BE_BUILT_ON_ATTACHMENT = 0x02, + OF_DOESNT_HAVE_A_MODEL = 0x04, + OF_PLAYER_DESTRUCTION = 0x08, + OF_BIT_COUNT = 4 +}; + +enum +{ + BS_IDLE = 0, + BS_SELECTING, + BS_PLACING, + BS_PLACING_INVALID +}; + +enum +{ + BUILDER_OBJECT_BITS = 8, + BUILDER_INVALID_OBJECT = ((1 << BUILDER_OBJECT_BITS) - 1) +}; + +enum CurrencyRewards_t +{ + TF_CURRENCY_KILLED_PLAYER, + TF_CURRENCY_KILLED_OBJECT, + TF_CURRENCY_ASSISTED_PLAYER, + TF_CURRENCY_BONUS_POINTS, + TF_CURRENCY_CAPTURED_OBJECTIVE, + TF_CURRENCY_ESCORT_REWARD, + TF_CURRENCY_PACK_SMALL, + TF_CURRENCY_PACK_MEDIUM, + TF_CURRENCY_PACK_LARGE, + TF_CURRENCY_PACK_CUSTOM, + TF_CURRENCY_TIME_REWARD, + TF_CURRENCY_WAVE_COLLECTION_BONUS +}; + +enum MVMAnnouncement_t +{ + TF_MVM_ANNOUNCEMENT_WAVE_COMPLETE, + TF_MVM_ANNOUNCEMENT_WAVE_FAILED, + TF_MVM_ANNOUNCEMENT_TOTAL +}; + +enum MVMUpgradeUIGroups_t +{ + UIGROUP_UPGRADE_ATTACHED_TO_ITEM = 0, + UIGROUP_UPGRADE_ATTACHED_TO_PLAYER, + UIGROUP_POWERUPBOTTLE +}; + +enum +{ + MVM_UPGRADE_QUALITY_LOW = 1, + MVM_UPGRADE_QUALITY_NORMAL, + MVM_UPGRADE_QAULITY_HIGH +}; + +enum +{ + TF_SAPEVENT_NONE = 0, + TF_SAPEVENT_PLACED, + TF_SAPEVENT_DONE +}; + +enum RuneTypes_t +{ + RUNE_NONE = -1, + RUNE_STRENGTH, + RUNE_HASTE, + RUNE_REGEN, + RUNE_RESIST, + RUNE_VAMPIRE, + RUNE_REFLECT, + RUNE_PRECISION, + RUNE_AGILITY, + RUNE_KNOCKOUT, + RUNE_KING, + RUNE_PLAGUE, + RUNE_SUPERNOVA, + RUNE_TYPES_MAX +}; + +enum ETFMatchGroup +{ + k_eTFMatchGroup_Invalid = -1, + k_eTFMatchGroup_MvM_Practice = 0, + k_eTFMatchGroup_MvM_MannUp = 1, + k_eTFMatchGroup_First = 0, + k_eTFMatchGroup_MvM_Default = 0, + k_eTFMatchGroup_MvM_First = 0, + k_eTFMatchGroup_MvM_Last = 1, + k_eTFMatchGroup_Ladder_6v6 = 2, + k_eTFMatchGroup_Ladder_9v9 = 3, + k_eTFMatchGroup_Ladder_12v12 = 4, + k_eTFMatchGroup_Ladder_Default = 2, + k_eTFMatchGroup_Ladder_First = 2, + k_eTFMatchGroup_Ladder_Last = 4, + k_eTFMatchGroup_Casual_6v6 = 5, + k_eTFMatchGroup_Casual_9v9 = 6, + k_eTFMatchGroup_Casual_12v12 = 7, + k_eTFMatchGroup_Casual_Default = 7, + k_eTFMatchGroup_Casual_First = 5, + k_eTFMatchGroup_Casual_Last = 7, + k_eTFMatchGroup_Event_Placeholder = 8, + k_eTFMatchGroup_Event_Default = 8, + k_eTFMatchGroup_Event_First = 8, + k_eTFMatchGroup_Event_Last = 8, +}; + +enum +{ + PARTITION_ENGINE_SOLID_EDICTS = (1 << 0), + PARTITION_ENGINE_TRIGGER_EDICTS = (1 << 1), + PARTITION_CLIENT_SOLID_EDICTS = (1 << 2), + PARTITION_CLIENT_RESPONSIVE_EDICTS = (1 << 3), + PARTITION_ENGINE_NON_STATIC_EDICTS = (1 << 4), + PARTITION_CLIENT_STATIC_PROPS = (1 << 5), + PARTITION_ENGINE_STATIC_PROPS = (1 << 6), + PARTITION_CLIENT_NON_STATIC_EDICTS = (1 << 7) +}; + +enum soundlevel_t +{ + SNDLVL_NONE = 0, + SNDLVL_20dB = 20, + SNDLVL_25dB = 25, + SNDLVL_30dB = 30, + SNDLVL_35dB = 35, + SNDLVL_40dB = 40, + SNDLVL_45dB = 45, + SNDLVL_50dB = 50, + SNDLVL_55dB = 55, + SNDLVL_IDLE = 60, + SNDLVL_60dB = 60, + SNDLVL_65dB = 65, + SNDLVL_STATIC = 66, + SNDLVL_70dB = 70, + SNDLVL_NORM = 75, + SNDLVL_75dB = 75, + SNDLVL_80dB = 80, + SNDLVL_TALKING = 80, + SNDLVL_85dB = 85, + SNDLVL_90dB = 90, + SNDLVL_95dB = 95, + SNDLVL_100dB = 100, + SNDLVL_105dB = 105, + SNDLVL_110dB = 110, + SNDLVL_120dB = 120, + SNDLVL_130dB = 130, + SNDLVL_GUNFIRE = 140, + SNDLVL_140dB = 140, + SNDLVL_150dB = 150, + SNDLVL_180dB = 180 +}; + +enum +{ + WL_NotInWater = 0, + WL_Feet, + WL_Waist, + WL_Eyes +}; + +struct StartSoundParams_t +{ + bool staticsound; + int userdata; + int soundsource; + int entchannel; + void* pSfx; //CSfxTable + Vec3 origin; + Vec3 direction; + bool bUpdatePositions; + float fvol; + soundlevel_t soundlevel; + int flags; + int pitch; + int specialdsp; + bool fromserver; + float delay; + int speakerentity; + bool suppressrecording; + int initialStreamPosition; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces.h b/Amalgam/src/SDK/Definitions/Interfaces.h new file mode 100644 index 0000000..fc5ff37 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces.h @@ -0,0 +1,43 @@ +#pragma once + +#include "../../Utils/Feature/Feature.h" + +#include "Interfaces/CClientModeShared.h" +#include "Interfaces/CClientState.h" +#include "Interfaces/CGlobalVarsBase.h" +#include "Interfaces/CTFGameRules.h" +#include "Interfaces/CTFPartyClient.h" +#include "Interfaces/IClientEntityList.h" +#include "Interfaces/ICVar.h" +#include "Interfaces/IEngineTrace.h" +#include "Interfaces/IEngineVGui.h" +#include "Interfaces/IGameEvents.h" +#include "Interfaces/IGameMovement.h" +#include "Interfaces/IInput.h" +#include "Interfaces/IInputSystem.h" +#include "Interfaces/IMaterialSystem.h" +#include "Interfaces/IMatSystemSurface.h" +#include "Interfaces/IMoveHelper.h" +#include "Interfaces/IStudioRender.h" +#include "Interfaces/IUniformRandomStream.h" +#include "Interfaces/IVEngineClient.h" +#include "Interfaces/IViewRender.h" +#include "Interfaces/IVModelInfo.h" +#include "Interfaces/IVModelRender.h" +#include "Interfaces/IVRenderView.h" +#include "Interfaces/Prediction.h" +#include "Interfaces/SteamInterfaces.h" +#include "Interfaces/VGuiPanel.h" +#include "Interfaces/ViewRenderBeams.h" +#include "Interfaces/VPhysics.h" + +#include +MAKE_INTERFACE_SIGNATURE_SEARCH(IDirect3DDevice9, DirectXDevice, "shaderapi", "48 8B 0D ? ? ? ? 48 8B 01 FF 50 ? 8B F8", 0x0, 1) + +class CNullInterfaces +{ +public: + void Initialize(); +}; + +ADD_FEATURE_CUSTOM(CNullInterfaces, Interfaces, H); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/CClientModeShared.h b/Amalgam/src/SDK/Definitions/Interfaces/CClientModeShared.h new file mode 100644 index 0000000..5ed7379 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/CClientModeShared.h @@ -0,0 +1,87 @@ +#pragma once +#include "../Misc/IClientMode.h" +#include "../Misc/CGameEventListener.h" +#include "../../../Utils/Memory/Memory.h" + +class CBaseEntity; +class CBasePlayer; +class CViewSetup; + +class CBaseHudChat +{ +public: + void ChatPrintf(int pIndex, const char* fmt, ...) + { + typedef void(_cdecl* FN)(void*, int, int, const char*, ...); + reinterpret_cast(U::Memory.GetVFunc(this, 19))(this, pIndex, 0, fmt); + } + + void StartMessageMode(int iMessageModeType) + { + typedef void(__fastcall* FN)(void*, int); + reinterpret_cast(U::Memory.GetVFunc(this, 20))(this, iMessageModeType); + } +}; + +class CClientModeShared : public IClientMode, public CGameEventListener +{ +public: + virtual ~CClientModeShared() {}; + virtual void Init() = 0; + virtual void InitViewport() = 0; + virtual void VGui_Shutdown() = 0; + virtual void Shutdown() = 0; + virtual void LevelInit(const char* newmap) = 0; + virtual void LevelShutdown(void) = 0; + virtual void Enable() = 0; + virtual void Disable() = 0; + virtual void Layout() = 0; + virtual void ReloadScheme(bool flushLowLevel) = 0; + virtual void OverrideView(CViewSetup* pSetup) = 0; + virtual bool ShouldDrawDetailObjects() = 0; + virtual bool ShouldDrawEntity(CBaseEntity* pEnt) = 0; + virtual bool ShouldDrawLocalPlayer(CBasePlayer* pPlayer) = 0; + virtual bool ShouldDrawViewModel() = 0; + virtual bool ShouldDrawParticles() = 0; + virtual bool ShouldDrawCrosshair(void) = 0; + virtual bool ShouldBlackoutAroundHUD() override = 0; + virtual HeadtrackMovementMode_t ShouldOverrideHeadtrackControl() override = 0; + virtual void AdjustEngineViewport(int& x, int& y, int& width, int& height) = 0; + virtual void PreRender(CViewSetup* pSetup) = 0; + virtual void PostRender() = 0; + virtual void PostRenderVGui() = 0; + virtual void ProcessInput(bool bActive) = 0; + virtual bool CreateMove(float flInputSampleTime, CUserCmd* cmd) = 0; + virtual void Update() = 0; + virtual int KeyInput(int down, ButtonCode_t keynum, const char* pszCurrentBinding) = 0; + virtual int HudElementKeyInput(int down, ButtonCode_t keynum, const char* pszCurrentBinding) = 0; + virtual void OverrideMouseInput(float* x, float* y) = 0; + virtual void StartMessageMode(int iMessageModeType) = 0; + virtual Panel* GetMessagePanel() = 0; + virtual void ActivateInGameVGuiContext(Panel* pPanel) = 0; + virtual void DeactivateInGameVGuiContext() = 0; + virtual bool ShouldDrawFog(void) = 0; + virtual float GetViewModelFOV(void) = 0; + virtual Panel* GetViewport() {} + virtual AnimationController* GetViewportAnimationController() {} + virtual void FireGameEvent(IGameEvent* event) = 0; + virtual bool CanRecordDemo(char* errorMsg, int length) const { return true; } + virtual int HandleSpectatorKeyInput(int down, ButtonCode_t keynum, const char* pszCurrentBinding) = 0; + virtual void ComputeVguiResConditions(KeyValues* pkvConditions) override = 0; + virtual wchar_t* GetServerName() { return nullptr; } + virtual void SetServerName(wchar_t* name) {} + virtual wchar_t* GetMapName() { return nullptr; } + virtual void SetMapName(wchar_t* name) {} + virtual bool DoPostScreenSpaceEffects(const CViewSetup* pSetup) = 0; + virtual void DisplayReplayMessage(const char* pLocalizeName, float flDuration, bool bUrgent, const char* pSound, bool bDlg) = 0; + virtual bool IsInfoPanelAllowed() override { return true; } + virtual void InfoPanelDisplayed() override {} + virtual bool IsHTMLInfoPanelAllowed() override { return true; } + virtual void OnDemoRecordStart(char const* pDemoBaseName) override {} + virtual void OnDemoRecordStop() override {} + + char szPad[24]; + CBaseHudChat* m_pChatElement; +}; + +MAKE_INTERFACE_SIGNATURE(CClientModeShared, ClientModeShared, "client.dll", "48 8B 0D ? ? ? ? 48 8B 10 48 8B 19 48 8B C8 FF 92", 0x0, 1); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h b/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h new file mode 100644 index 0000000..c04100f --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/CClientState.h @@ -0,0 +1,99 @@ +#pragma once +#include "Interface.h" +#include "../Main/INetChannel.h" + +/* +class CClockDriftMgr +{ +public: + enum { NUM_CLOCKDRIFT_SAMPLES = 16 }; + + float m_ClockOffsets[NUM_CLOCKDRIFT_SAMPLES]{}; + int m_iCurClockOffset{}; + int m_nServerTick{}; + int m_nClientTick{}; +}; + +class CClientState +{ +public: + byte pad0[0x10]{}; + INetChannel* m_NetChannel{}; + byte pad1[0x140]{}; + CClockDriftMgr m_ClockDriftMgr{}; + int m_nDeltaTick{}; + byte pad2[0x110]{}; + int m_nMaxClients{}; + byte pad3[0x4868]{}; + float m_frameTime{}; + int lastoutgoingcommand{}; + int chokedcommands{}; + int last_command_ack{}; +}; +*/ + +struct CUtlString +{ + char* m_pString; +}; + +struct CClockDriftMgr +{ + float m_ClockOffsets[16]; + int m_iCurClockOffset; + int m_nServerTick; + int m_nClientTick; +}; + +class CClientState +{ +public: + byte gap0[24]; + int m_Socket; + INetChannel* m_NetChannel; + unsigned int m_nChallengeNr; + double m_flConnectTime; + int m_nRetryNumber; + char m_szRetryAddress[260]; + CUtlString m_sRetrySourceTag; + int m_retryChallenge; + int m_nSignonState; + double m_flNextCmdTime; + int m_nServerCount; + unsigned __int64 m_ulGameServerSteamID; + int m_nCurrentSequence; + CClockDriftMgr m_ClockDriftMgr; + int m_nDeltaTick; + bool m_bPaused; + float m_flPausedExpireTime; + int m_nViewEntity; + int m_nPlayerSlot; + char m_szLevelFileName[128]; + byte gap24C[132]; + char m_szLevelBaseName[128]; + byte gap350[116]; + int m_nMaxClients; + byte gap3C8[34856]; + void* m_StringTableContainer; + bool m_bRestrictServerCommands; + bool m_bRestrictClientCommands; + byte gap8BFC[106]; + bool insimulation; + int oldtickcount; + float m_tickRemainder; + float m_frameTime; + int lastoutgoingcommand; + int chokedcommands; + int last_command_ack; + int command_ack; + int m_nSoundSequence; + bool ishltv; + bool isreplay; + byte gap8C8A[278]; + int demonum; + CUtlString demos[32]; + byte gap8EE8[344184]; + bool m_bMarkedCRCsUnverified; +}; + +MAKE_INTERFACE_SIGNATURE(CClientState, ClientState, "engine.dll", "48 8D 0D ? ? ? ? E8 ? ? ? ? F3 0F 5E 05", 0x0, 0); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/CGlobalVarsBase.h b/Amalgam/src/SDK/Definitions/Interfaces/CGlobalVarsBase.h new file mode 100644 index 0000000..181de4c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/CGlobalVarsBase.h @@ -0,0 +1,26 @@ +#pragma once +#include "Interface.h" + +class CSaveRestoreData; + +class CGlobalVarsBase +{ +public: + float realtime; + int framecount; + float absoluteframetime; + float curtime; + float frametime; + int maxClients; + int tickcount; + float interval_per_tick; + float interpolation_amount; + int simTicksThisFrame; + int network_protocol; + CSaveRestoreData* pSaveData; + bool m_bClient; + int nTimestampNetworkingBase; + int nTimestampRandomizeWindow; +}; + +MAKE_INTERFACE_SIGNATURE(CGlobalVarsBase, GlobalVars, "engine.dll", "48 8D 05 ? ? ? ? C3 CC CC CC CC CC CC CC CC 48 8B CA", 0x0, 0); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/CTFGameRules.h b/Amalgam/src/SDK/Definitions/Interfaces/CTFGameRules.h new file mode 100644 index 0000000..79a7d59 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/CTFGameRules.h @@ -0,0 +1,120 @@ +#pragma once +#include "Interface.h" +#include "../Definitions.h" +#include "../../../Utils/NetVars/NetVars.h" + +MAKE_SIGNATURE(CTFGameRules_Get, "client.dll", "48 8B 0D ? ? ? ? 4C 8B C3 48 8B D7 48 8B 01 FF 90 ? ? ? ? 84 C0", 0x0); + +class CGameRulesProxy +{ +public: +}; + +class CTeamplayRoundBasedRulesProxy : public CGameRulesProxy +{ +public: + NETVAR(m_iRoundState, int, "CTeamplayRoundBasedRulesProxy", "m_iRoundState"); + NETVAR(m_bInWaitingForPlayers, bool, "CTeamplayRoundBasedRulesProxy", "m_bInWaitingForPlayers"); + NETVAR(m_iWinningTeam, int, "CTeamplayRoundBasedRulesProxy", "m_iWinningTeam"); + NETVAR(m_bInOvertime, bool, "CTeamplayRoundBasedRulesProxy", "m_bInOvertime"); + NETVAR(m_bInSetup, bool, "CTeamplayRoundBasedRulesProxy", "m_bInSetup"); + NETVAR(m_bSwitchedTeamsThisRound, bool, "CTeamplayRoundBasedRulesProxy", "m_bSwitchedTeamsThisRound"); + NETVAR(m_bAwaitingReadyRestart, bool, "CTeamplayRoundBasedRulesProxy", "m_bAwaitingReadyRestart"); + NETVAR(m_flRestartRoundTime, float, "CTeamplayRoundBasedRulesProxy", "m_flRestartRoundTime"); + NETVAR(m_flMapResetTime, float, "CTeamplayRoundBasedRulesProxy", "m_flMapResetTime"); + NETVAR(m_nRoundsPlayed, int, "CTeamplayRoundBasedRulesProxy", "m_nRoundsPlayed"); + NETVAR(m_flNextRespawnWave, void*, "CTeamplayRoundBasedRulesProxy", "m_flNextRespawnWave"); + NETVAR(m_TeamRespawnWaveTimes, void*, "CTeamplayRoundBasedRulesProxy", "m_TeamRespawnWaveTimes"); + NETVAR(m_bTeamReady, void*, "CTeamplayRoundBasedRulesProxy", "m_bTeamReady"); + NETVAR(m_bStopWatch, bool, "CTeamplayRoundBasedRulesProxy", "m_bStopWatch"); + NETVAR(m_bMultipleTrains, bool, "CTeamplayRoundBasedRulesProxy", "m_bMultipleTrains"); + NETVAR(m_bPlayerReady, void*, "CTeamplayRoundBasedRulesProxy", "m_bPlayerReady"); + NETVAR(m_bCheatsEnabledDuringLevel, bool, "CTeamplayRoundBasedRulesProxy", "m_bCheatsEnabledDuringLevel"); + NETVAR(m_flCountdownTime, float, "CTeamplayRoundBasedRulesProxy", "m_flCountdownTime"); + NETVAR(m_flStateTransitionTime, float, "CTeamplayRoundBasedRulesProxy", "m_flStateTransitionTime"); +}; + +class CTFGameRulesProxy : public CTeamplayRoundBasedRulesProxy +{ +public: + NETVAR(m_nGameType, int, "CTFGameRulesProxy", "m_nGameType"); + NETVAR(m_nStopWatchState, int, "CTFGameRulesProxy", "m_nStopWatchState"); + NETVAR(m_pszTeamGoalStringRed, const char*, "CTFGameRulesProxy", "m_pszTeamGoalStringRed"); + NETVAR(m_pszTeamGoalStringBlue, const char*, "CTFGameRulesProxy", "m_pszTeamGoalStringBlue"); + NETVAR(m_flCapturePointEnableTime, float, "CTFGameRulesProxy", "m_flCapturePointEnableTime"); + NETVAR(m_nHudType, int, "CTFGameRulesProxy", "m_nHudType"); + NETVAR(m_bIsInTraining, bool, "CTFGameRulesProxy", "m_bIsInTraining"); + NETVAR(m_bAllowTrainingAchievements, bool, "CTFGameRulesProxy", "m_bAllowTrainingAchievements"); + NETVAR(m_bIsWaitingForTrainingContinue, bool, "CTFGameRulesProxy", "m_bIsWaitingForTrainingContinue"); + NETVAR(m_bIsTrainingHUDVisible, bool, "CTFGameRulesProxy", "m_bIsTrainingHUDVisible"); + NETVAR(m_bIsInItemTestingMode, bool, "CTFGameRulesProxy", "m_bIsInItemTestingMode"); + NETVAR(m_hBonusLogic, int, "CTFGameRulesProxy", "m_hBonusLogic"); + NETVAR(m_bPlayingKoth, bool, "CTFGameRulesProxy", "m_bPlayingKoth"); + NETVAR(m_bPlayingMedieval, bool, "CTFGameRulesProxy", "m_bPlayingMedieval"); + NETVAR(m_bPlayingHybrid_CTF_CP, bool, "CTFGameRulesProxy", "m_bPlayingHybrid_CTF_CP"); + NETVAR(m_bPlayingSpecialDeliveryMode, bool, "CTFGameRulesProxy", "m_bPlayingSpecialDeliveryMode"); + NETVAR(m_bPlayingRobotDestructionMode, bool, "CTFGameRulesProxy", "m_bPlayingRobotDestructionMode"); + NETVAR(m_hRedKothTimer, int, "CTFGameRulesProxy", "m_hRedKothTimer"); + NETVAR(m_hBlueKothTimer, int, "CTFGameRulesProxy", "m_hBlueKothTimer"); + NETVAR(m_nMapHolidayType, int, "CTFGameRulesProxy", "m_nMapHolidayType"); + NETVAR(m_itHandle, int, "CTFGameRulesProxy", "m_itHandle"); + NETVAR(m_bPlayingMannVsMachine, bool, "CTFGameRulesProxy", "m_bPlayingMannVsMachine"); + NETVAR(m_hBirthdayPlayer, int, "CTFGameRulesProxy", "m_hBirthdayPlayer"); + NETVAR(m_nBossHealth, int, "CTFGameRulesProxy", "m_nBossHealth"); + NETVAR(m_nMaxBossHealth, int, "CTFGameRulesProxy", "m_nMaxBossHealth"); + NETVAR(m_fBossNormalizedTravelDistance, int, "CTFGameRulesProxy", "m_fBossNormalizedTravelDistance"); + NETVAR(m_bMannVsMachineAlarmStatus, bool, "CTFGameRulesProxy", "m_bMannVsMachineAlarmStatus"); + NETVAR(m_bHaveMinPlayersToEnableReady, bool, "CTFGameRulesProxy", "m_bHaveMinPlayersToEnableReady"); + NETVAR(m_bBountyModeEnabled, bool, "CTFGameRulesProxy", "m_bBountyModeEnabled"); + NETVAR(m_nHalloweenEffect, int, "CTFGameRulesProxy", "m_nHalloweenEffect"); + NETVAR(m_fHalloweenEffectStartTime, float, "CTFGameRulesProxy", "m_fHalloweenEffectStartTime"); + NETVAR(m_fHalloweenEffectDuration, float, "CTFGameRulesProxy", "m_fHalloweenEffectDuration"); + NETVAR(m_halloweenScenario, int, "CTFGameRulesProxy", "m_halloweenScenario"); + NETVAR(m_bHelltowerPlayersInHell, bool, "CTFGameRulesProxy", "m_bHelltowerPlayersInHell"); + NETVAR(m_bIsUsingSpells, bool, "CTFGameRulesProxy", "m_bIsUsingSpells"); + NETVAR(m_bCompetitiveMode, bool, "CTFGameRulesProxy", "m_bCompetitiveMode"); + NETVAR(m_nMatchGroupType, int, "CTFGameRulesProxy", "m_nMatchGroupType"); + NETVAR(m_bMatchEnded, bool, "CTFGameRulesProxy", "m_bMatchEnded"); + NETVAR(m_bPowerupMode, bool, "CTFGameRulesProxy", "m_bPowerupMode"); + NETVAR(m_pszCustomUpgradesFile, const char*, "CTFGameRulesProxy", "m_pszCustomUpgradesFile"); + NETVAR(m_bTruceActive, bool, "CTFGameRulesProxy", "m_bTruceActive"); + NETVAR(m_bShowMatchSummary, bool, "CTFGameRulesProxy", "m_bShowMatchSummary"); + NETVAR(m_bMapHasMatchSummaryStage, bool, "CTFGameRulesProxy", "m_bMapHasMatchSummaryStage"); + NETVAR(m_bPlayersAreOnMatchSummaryStage, bool, "CTFGameRulesProxy", "m_bPlayersAreOnMatchSummaryStage"); + NETVAR(m_bStopWatchWinner, bool, "CTFGameRulesProxy", "m_bStopWatchWinner"); + NETVAR(m_ePlayerWantsRematch, void*, "CTFGameRulesProxy", "m_ePlayerWantsRematch"); + NETVAR(m_eRematchState, int, "CTFGameRulesProxy", "m_eRematchState"); + NETVAR(m_nNextMapVoteOptions, void*, "CTFGameRulesProxy", "m_nNextMapVoteOptions"); + NETVAR(m_nForceUpgrades, int, "CTFGameRulesProxy", "m_nForceUpgrades"); + NETVAR(m_nForceEscortPushLogic, int, "CTFGameRulesProxy", "m_nForceEscortPushLogic"); + NETVAR(m_bRopesHolidayLightsAllowed, bool, "CTFGameRulesProxy", "m_bRopesHolidayLightsAllowed"); + + inline bool IsPlayerReady(int playerIndex) + { + if (playerIndex > 101) + return false; + + static int nOffset = U::NetVars.GetNetVar("CTeamplayRoundBasedRulesProxy", "m_bPlayerReady"); + bool* ReadyStatus = reinterpret_cast(std::uintptr_t(this) + nOffset); + if (!ReadyStatus) + return false; + + return ReadyStatus[playerIndex]; + } +}; + +class CTFGameRules +{ +public: + CTFGameRulesProxy* GetProxy() + { + return reinterpret_cast(this); + } + + CTFGameRules* Get() + { + return *reinterpret_cast(U::Memory.RelToAbs(S::CTFGameRules_Get())); + } +}; + +MAKE_INTERFACE_NULL(CTFGameRules, TFGameRules); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/CTFPartyClient.h b/Amalgam/src/SDK/Definitions/Interfaces/CTFPartyClient.h new file mode 100644 index 0000000..43e593d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/CTFPartyClient.h @@ -0,0 +1,27 @@ +#pragma once +#include "Interface.h" + +MAKE_SIGNATURE(CTFPartyClient_LoadSavedCasualCriteria, "client.dll", "48 83 79 ? ? C6 81 ? ? ? ? ? 74 ? 80 79 ? ? 74 ? C6 81 ? ? ? ? ? 48 8B 15", 0x0); +MAKE_SIGNATURE(CTFPartyClient_BInQueueForMatchGroup, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B F9 8B DA 8B CA E8 ? ? ? ? 84 C0", 0x0); +MAKE_SIGNATURE(CTFPartyClient_RequestQueueForMatch, "client.dll", "40 55 56 48 81 EC ? ? ? ? 48 63 F2", 0x0); + +class CTFPartyClient +{ +public: + void LoadSavedCasualCriteria() + { + return S::CTFPartyClient_LoadSavedCasualCriteria.As()(this); + } + + bool BInQueueForMatchGroup(int eMatchGroup) + { + return S::CTFPartyClient_BInQueueForMatchGroup.As()(this, eMatchGroup); + } + + void RequestQueueForMatch(int eMatchGroup) + { + return S::CTFPartyClient_RequestQueueForMatch.As()(this, eMatchGroup); + } +}; + +MAKE_INTERFACE_NULL(CTFPartyClient, TFPartyClient); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/ICVar.h b/Amalgam/src/SDK/Definitions/Interfaces/ICVar.h new file mode 100644 index 0000000..9797ba1 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/ICVar.h @@ -0,0 +1,114 @@ +#pragma once +#include "../Misc/IAppSystem.h" +#include "../Misc/ConVar.h" +#include "../Types.h" + +class ConCommandBase; +class ConCommand; + +typedef int CVarDLLIdentifier_t; + +class IConsoleDisplayFunc +{ +public: + virtual void ColorPrint(const Color_t& clr, const char* pMessage) = 0; + virtual void Print(const char* pMessage) = 0; + virtual void DPrint(const char* pMessage) = 0; +}; + +class ICvarQuery : public IAppSystem +{ +public: + virtual bool AreConVarsLinkable(const ConVar* child, const ConVar* parent) = 0; +}; + +class ICvar : public IAppSystem +{ +public: + virtual CVarDLLIdentifier_t AllocateDLLIdentifier() = 0; + virtual void RegisterConCommand(ConCommandBase* pCommandBase) = 0; + virtual void UnregisterConCommand(ConCommandBase* pCommandBase) = 0; + virtual void UnregisterConCommands(CVarDLLIdentifier_t id) = 0; + virtual const char* GetCommandLineValue(const char* pVariableName) = 0; + 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; + virtual ConCommandBase* GetCommands(void) = 0; + virtual const ConCommandBase* GetCommands(void) const = 0; + 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; + virtual void InstallConsoleDisplayFunc(IConsoleDisplayFunc* pDisplayFunc) = 0; + virtual void RemoveConsoleDisplayFunc(IConsoleDisplayFunc* pDisplayFunc) = 0; + virtual void ConsoleColorPrintf(const Color_t& clr, const char* pFormat, ...) const = 0; + virtual void ConsolePrintf(const char* pFormat, ...) const = 0; + virtual void ConsoleDPrintf(const char* pFormat, ...) const = 0; + virtual void RevertFlaggedConVars(int nFlag) = 0; + virtual void InstallCVarQuery(ICvarQuery* pQuery) = 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; + + class ICVarIteratorInternal + { + public: + virtual ~ICVarIteratorInternal() {} + virtual void SetFirst(void) = 0; + virtual void Next(void) = 0; + virtual bool IsValid(void) = 0; + virtual ConCommandBase* Get(void) = 0; + }; + + 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; + }; + + virtual ICVarIteratorInternal* FactoryInternalIterator(void) = 0; +}; + +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(); +} + +MAKE_INTERFACE_VERSION(ICvar, CVar, "vstdlib.dll", "VEngineCvar004"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IClientEntityList.h b/Amalgam/src/SDK/Definitions/Interfaces/IClientEntityList.h new file mode 100644 index 0000000..00520a3 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IClientEntityList.h @@ -0,0 +1,29 @@ +#pragma once +#include "Interface.h" +#include "../Main/CBaseHandle.h" + +class IClientEntity; +class ClientClass; +class IClientNetworkable; +class IClientUnknown; + +class IClientEntityList +{ +public: + virtual IClientNetworkable* GetClientNetworkable(int entnum) = 0; + virtual IClientNetworkable* GetClientNetworkableFromHandle(CBaseHandle hEnt) = 0; + virtual IClientUnknown* GetClientUnknownFromHandle(CBaseHandle hEnt) = 0; + virtual IClientEntity* GetClientEntity(int entnum) = 0; + virtual IClientEntity* GetClientEntityFromHandle(CBaseHandle hEnt) = 0; + virtual int NumberOfEntities(bool bIncludeNonNetworkable) = 0; + virtual int GetHighestEntityIndex(void) = 0; + virtual void SetMaxEntities(int maxents) = 0; + virtual int GetMaxEntities() = 0; +}; + +MAKE_INTERFACE_VERSION(IClientEntityList, ClientEntityList, "client.dll", "VClientEntityList003"); + +inline IHandleEntity* CBaseHandle::Get() const +{ + return reinterpret_cast(I::ClientEntityList->GetClientEntityFromHandle(m_Index)); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IEngineTrace.h b/Amalgam/src/SDK/Definitions/Interfaces/IEngineTrace.h new file mode 100644 index 0000000..661193a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IEngineTrace.h @@ -0,0 +1,59 @@ +#pragma once +#include "Interface.h" +#include "../Main/CBaseHandle.h" +#include "../Main/UtlVector.h" +#include "../Main/CModel.h" +#include "../Types.h" + +class CGameTrace; +typedef CGameTrace trace_t; +class ICollideable; +class CTraceListData; +class CPhysCollide; +struct cplane_t; + +enum TraceType_t +{ + TRACE_EVERYTHING = 0, + TRACE_WORLD_ONLY, + TRACE_ENTITIES_ONLY, + TRACE_EVERYTHING_FILTER_PROPS +}; + +class ITraceFilter +{ +public: + virtual bool ShouldHitEntity(IHandleEntity* pEntity, int contentsMask) = 0; + virtual TraceType_t GetTraceType() const = 0; +}; + +class IEntityEnumerator +{ +public: + virtual bool EnumEntity(IHandleEntity* pHandleEntity) = 0; +}; + +class IEngineTrace +{ +public: + virtual int GetPointContents(const Vector& vecAbsPosition, IHandleEntity** ppEntity = NULL) = 0; + virtual int GetPointContents_Collideable(ICollideable* pCollide, const Vector& vecAbsPosition) = 0; + virtual void ClipRayToEntity(const Ray_t& ray, unsigned int fMask, IHandleEntity* pEnt, trace_t* pTrace) = 0; + virtual void ClipRayToCollideable(const Ray_t& ray, unsigned int fMask, ICollideable* pCollide, trace_t* pTrace) = 0; + virtual void TraceRay(const Ray_t& ray, unsigned int fMask, ITraceFilter* pTraceFilter, trace_t* pTrace) = 0; + 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; + virtual void SweepCollideable(ICollideable* pCollide, const Vector& vecAbsStart, const Vector& vecAbsEnd, const QAngle& vecAngles, unsigned int fMask, ITraceFilter* pTraceFilter, trace_t* pTrace) = 0; + virtual void EnumerateEntities(const Ray_t& ray, bool triggers, IEntityEnumerator* pEnumerator) = 0; + virtual void EnumerateEntities(const Vector& vecAbsMins, const Vector& vecAbsMaxs, IEntityEnumerator* pEnumerator) = 0; + virtual ICollideable* GetCollideable(IHandleEntity* pEntity) = 0; + virtual int GetStatByIndex(int index, bool bClear) = 0; + virtual void GetBrushesInAABB(const Vector& vMins, const Vector& vMaxs, CUtlVector* pOutput, int iContentsMask = 0xFFFFFFFF) = 0; + virtual CPhysCollide* GetCollidableFromDisplacementsInAABB(const Vector& vMins, const Vector& vMaxs) = 0; + virtual bool GetBrushInfo(int iBrush, CUtlVector* pPlanesOut, int* pContentsOut) = 0; + virtual bool PointOutsideWorld(const Vector& ptTest) = 0; + virtual int GetLeafContainingPoint(const Vector& ptTest) = 0; +}; + +MAKE_INTERFACE_VERSION(IEngineTrace, EngineTrace, "engine.dll", "EngineTraceClient003"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IEngineVGui.h b/Amalgam/src/SDK/Definitions/Interfaces/IEngineVGui.h new file mode 100644 index 0000000..cb8c251 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IEngineVGui.h @@ -0,0 +1,31 @@ +#pragma once +#include "Interface.h" +#include "../Misc/VGUI.h" + +enum VGuiPanel_t +{ + PANEL_ROOT = 0, + PANEL_GAMEUIDLL, + PANEL_CLIENTDLL, + PANEL_TOOLS, + PANEL_INGAMESCREENS, + PANEL_GAMEDLL, + PANEL_CLIENTDLL_TOOLS +}; + +enum PaintMode_t +{ + PAINT_UIPANELS = (1 << 0), + PAINT_INGAMEPANELS = (1 << 1), + PAINT_CURSOR = (1 << 2) +}; + +class IEngineVGui +{ +public: + virtual ~IEngineVGui(void) {} + virtual VPANEL GetPanel(VGuiPanel_t type) = 0; + virtual bool IsGameUIVisible() = 0; +}; + +MAKE_INTERFACE_VERSION(IEngineVGui, EngineVGui, "engine.dll", "VEngineVGui002"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IGameEvents.h b/Amalgam/src/SDK/Definitions/Interfaces/IGameEvents.h new file mode 100644 index 0000000..0e63824 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IGameEvents.h @@ -0,0 +1,80 @@ +#pragma once +#include "Interface.h" +#include "../Misc/bitbuf.h" + +#define MAX_EVENT_NAME_LENGTH 32 +#define MAX_EVENT_BITS 9 +#define MAX_EVENT_NUMBER (1<(std::uintptr_t(this) + 264); + } + + CVerifiedUserCmd* GetVerifiedCommands() + { + return *reinterpret_cast(std::uintptr_t(this) + 272); + } +}; + +MAKE_INTERFACE_SIGNATURE(IInput, Input, "client.dll", "48 8B 0D ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 85 C0 0F 84 ? ? ? ? F3 0F 10 05", 0, 1); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IInputSystem.h b/Amalgam/src/SDK/Definitions/Interfaces/IInputSystem.h new file mode 100644 index 0000000..50b8b21 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IInputSystem.h @@ -0,0 +1,63 @@ +#pragma once +#include "../Misc/AnalogCode.h" +#include "../Misc/ButtonCode.h" +#include "../Misc/IAppSystem.h" +#include "../Misc/InputEnums.h" +#include "../Steam/ISteamController.h" + +class IInputSystem : public IAppSystem +{ +public: + virtual void AttachToWindow(void* hWnd) = 0; + virtual void DetachFromWindow() = 0; + virtual void EnableInput(bool bEnable) = 0; + virtual void EnableMessagePump(bool bEnable) = 0; + virtual void PollInputState() = 0; + virtual int GetPollTick() const = 0; + virtual bool IsButtonDown(ButtonCode_t code) const = 0; + virtual int GetButtonPressedTick(ButtonCode_t code) const = 0; + virtual int GetButtonReleasedTick(ButtonCode_t code) const = 0; + virtual int GetAnalogValue(AnalogCode_t code) const = 0; + virtual int GetAnalogDelta(AnalogCode_t code) const = 0; + virtual int GetEventCount() const = 0; + virtual const InputEvent_t* GetEventData() const = 0; + virtual void PostUserEvent(const InputEvent_t& event) = 0; + virtual int GetJoystickCount() const = 0; + virtual void EnableJoystickInput(int nJoystick, bool bEnable) = 0; + virtual void EnableJoystickDiagonalPOV(int nJoystick, bool bEnable) = 0; + virtual void SampleDevices(void) = 0; + virtual void SetRumble(float fLeftMotor, float fRightMotor, int userId) = 0; + virtual void StopRumble(void) = 0; + virtual void ResetInputState() = 0; + virtual void SetPrimaryUserId(int userId) = 0; + 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; + virtual void SleepUntilInput(int nMaxSleepTimeMS = -1) = 0; + virtual ButtonCode_t VirtualKeyToButtonCode(int nVirtualKey) const = 0; + virtual int ButtonCodeToVirtualKey(ButtonCode_t code) const = 0; + virtual ButtonCode_t ScanCodeToButtonCode(int lParam) const = 0; + virtual int GetPollCount() const = 0; + virtual void SetCursorPosition(int x, int y) = 0; + virtual void* GetHapticsInterfaceAddress() const = 0; + virtual void SetNovintPure(bool bPure) = 0; + virtual bool GetRawMouseAccumulators(int& accumX, int& accumY) = 0; + virtual void SetConsoleTextMode(bool bConsoleTextMode) = 0; + virtual ISteamController* SteamControllerInterface() = 0; + virtual uint32 GetNumSteamControllersConnected() = 0; + virtual bool IsSteamControllerActive() = 0; + virtual bool IsSteamControllerConnected() = 0; + virtual int GetSteamControllerIndexForSlot(int nSlot) = 0; + virtual bool GetRadialMenuStickValues(int nSlot, float& fX, float& fY) = 0; + virtual void ActivateSteamControllerActionSetForSlot(uint64 nSlot, GameActionSet_t eActionSet) = 0; + virtual ControllerActionSetHandle_t GetActionSetHandle(GameActionSet_t eActionSet) = 0; + virtual ControllerActionSetHandle_t GetActionSetHandle(const char* szActionSet) = 0; + virtual EControllerActionOrigin GetSteamControllerActionOrigin(const char* action, GameActionSet_t action_set) = 0; + virtual EControllerActionOrigin GetSteamControllerActionOrigin(const char* action, ControllerActionSetHandle_t action_set_handle) = 0; + virtual const wchar_t* GetSteamControllerFontCharacterForActionOrigin(EControllerActionOrigin origin) = 0; + virtual const wchar_t* GetSteamControllerDescriptionForActionOrigin(EControllerActionOrigin origin) = 0; + virtual void SetSkipControllerInitialization(bool bSkip) = 0; +}; + +MAKE_INTERFACE_VERSION(IInputSystem, InputSystem, "inputsystem.dll", "InputSystemVersion001"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IMatSystemSurface.h b/Amalgam/src/SDK/Definitions/Interfaces/IMatSystemSurface.h new file mode 100644 index 0000000..0f37ce6 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IMatSystemSurface.h @@ -0,0 +1,57 @@ +#pragma once +#include "../Misc/ISurface.h" + +MAKE_SIGNATURE(CMatSystemSurface_StartDrawing, "vguimatsurface.dll", "40 53 56 57 48 83 EC ? 48 8B F9 80 3D", 0x0); +MAKE_SIGNATURE(CMatSystemSurface_FinishDrawing, "vguimatsurface.dll", "40 53 48 83 EC ? 33 C9", 0x0); + +class VMatrix; +class IMaterial; +class ITexture; +struct InputEvent_t; + +typedef void (*GetMouseCallback_t)(int& x, int& y); +typedef void (*SetMouseCallback_t)(int x, int y); +typedef void (*PlaySoundFunc_t)(const char* pFileName); + +class IMatSystemSurface : public ISurface +{ +public: + virtual void AttachToWindow(void* hwnd, bool bLetAppDriveInput = false) = 0; + virtual void EnableWindowsMessages(bool bEnable) = 0; + virtual void Begin3DPaint(int iLeft, int iTop, int iRight, int iBottom, bool bRenderToTexture = true) = 0; + virtual void End3DPaint() = 0; + virtual void DisableClipping(bool bDisable) = 0; + virtual void GetClippingRect(int& left, int& top, int& right, int& bottom, bool& bClippingDisabled) = 0; + virtual void SetClippingRect(int left, int top, int right, int bottom) = 0; + virtual bool IsCursorLocked() const = 0; + virtual void SetMouseCallbacks(GetMouseCallback_t getFunc, SetMouseCallback_t setFunc) = 0; + virtual void InstallPlaySoundFunc(PlaySoundFunc_t soundFunc) = 0; + virtual void DrawColoredCircle(int centerx, int centery, float radius, int r, int g, int b, int a) = 0; + virtual int DrawColoredText(HFont font, int x, int y, int r, int g, int b, int a, const char* fmt, ...) = 0; + virtual void DrawColoredTextRect(HFont font, int x, int y, int w, int h, int r, int g, int b, int a, const char* fmt, ...) = 0; + virtual void DrawTextHeight(HFont font, int w, int& h, const char* fmt, ...) = 0; + virtual int DrawTextLen(HFont font, const char* fmt, ...) = 0; + virtual void DrawPanelIn3DSpace(VPANEL pRootPanel, const VMatrix& panelCenterToWorld, int nPixelWidth, int nPixelHeight, float flWorldWidth, float flWorldHeight) = 0; + virtual void DrawSetTextureMaterial(int id, IMaterial* pMaterial) = 0; + virtual bool HandleInputEvent(const InputEvent_t& event) = 0; + virtual void Set3DPaintTempRenderTarget(const char* pRenderTargetName) = 0; + virtual void Reset3DPaintTempRenderTarget(void) = 0; + 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; + virtual int DrawGetTextureId(ITexture* pTexture) = 0; + virtual void BeginSkinCompositionPainting() = 0; + virtual void EndSkinCompositionPainting() = 0; + + void StartDrawing() + { + S::CMatSystemSurface_StartDrawing.As()(this); + } + + void FinishDrawing() + { + S::CMatSystemSurface_FinishDrawing.As()(this); + } +}; + +MAKE_INTERFACE_VERSION(IMatSystemSurface, MatSystemSurface, "vguimatsurface.dll", "VGUI_Surface030"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IMaterialSystem.h b/Amalgam/src/SDK/Definitions/Interfaces/IMaterialSystem.h new file mode 100644 index 0000000..a7f438c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IMaterialSystem.h @@ -0,0 +1,694 @@ +#pragma once +#include "Interface.h" +#include "../Misc/Deformations.h" +#include "../Misc/IAppSystem.h" +#include "../Misc/IColorCorrectionSystem.h" +#include "../Misc/ImageFormat.h" +#include "../Misc/IMaterialSystemHardwareConfig.h" +#include "../Misc/IRefCounted.h" +#include "../Misc/LightDesc.h" +#include "../Misc/TextureGroupNames.h" +#include "../Misc/VTF.h" +#include "../Types.h" + +#define OVERBRIGHT 2.0f +#define OO_OVERBRIGHT ( 1.0f / 2.0f ) +#define GAMMA 2.2f +#define TEXGAMMA 2.2f + +class IMaterial; +class IMesh; +class IVertexBuffer; +class IIndexBuffer; +struct MaterialSystem_Config_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; + +typedef uint64 VertexFormat_t; + +#define ABSOLUTE_MINIMUM_DXLEVEL 80 + +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, + 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, + MATERIAL_TEXTURE0, + MATERIAL_TEXTURE1, + MATERIAL_TEXTURE2, + MATERIAL_TEXTURE3, + MATERIAL_TEXTURE4, + MATERIAL_TEXTURE5, + MATERIAL_TEXTURE6, + MATERIAL_TEXTURE7, + MATERIAL_MODEL, + NUM_MATRIX_MODES = MATERIAL_MODEL + 1, + NUM_TEXTURE_TRANSFORMS = MATERIAL_TEXTURE7 - MATERIAL_TEXTURE0 + 1 +}; + +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, + MATERIAL_POLYGON, + MATERIAL_QUADS, + MATERIAL_INSTANCED_QUADS, + MATERIAL_HETEROGENOUS +}; + +enum MaterialPropertyTypes_t +{ + MATERIAL_PROPERTY_NEEDS_LIGHTMAP = 0, + MATERIAL_PROPERTY_OPACITY, + MATERIAL_PROPERTY_REFLECTIVITY, + MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS +}; + +enum MaterialPropertyOpacityTypes_t +{ + MATERIAL_ALPHATEST = 0, + MATERIAL_OPAQUE, + MATERIAL_TRANSLUCENT +}; + +enum MaterialBufferTypes_t +{ + MATERIAL_FRONT = 0, + MATERIAL_BACK +}; + +enum MaterialCullMode_t +{ + MATERIAL_CULLMODE_CCW, + MATERIAL_CULLMODE_CW +}; + +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 +}; + +#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 +}; + +#define CREATERENDERTARGETFLAGS_HDR 0x00000001 +#define CREATERENDERTARGETFLAGS_AUTOMIPMAP 0x00000002 +#define CREATERENDERTARGETFLAGS_UNFILTERABLE_OK 0x00000004 +#define CREATERENDERTARGETFLAGS_NOEDRAM 0x00000008 +#define CREATERENDERTARGETFLAGS_TEMP 0x00000010 + +enum StencilOperation_t +{ + STENCILOPERATION_KEEP = 1, + STENCILOPERATION_ZERO = 2, + STENCILOPERATION_REPLACE = 3, + STENCILOPERATION_INCRSAT = 4, + STENCILOPERATION_DECRSAT = 5, + STENCILOPERATION_INVERT = 6, + STENCILOPERATION_INCR = 7, + STENCILOPERATION_DECR = 8, + STENCILOPERATION_FORCE_DWORD = 0x7fffffff +}; + +enum StencilComparisonFunction_t +{ + STENCILCOMPARISONFUNCTION_NEVER = 1, + STENCILCOMPARISONFUNCTION_LESS = 2, + STENCILCOMPARISONFUNCTION_EQUAL = 3, + STENCILCOMPARISONFUNCTION_LESSEQUAL = 4, + STENCILCOMPARISONFUNCTION_GREATER = 5, + STENCILCOMPARISONFUNCTION_NOTEQUAL = 6, + STENCILCOMPARISONFUNCTION_GREATEREQUAL = 7, + STENCILCOMPARISONFUNCTION_ALWAYS = 8, + STENCILCOMPARISONFUNCTION_FORCE_DWORD = 0x7fffffff +}; + +enum MorphFormatFlags_t +{ + MORPH_POSITION = 0x0001, + MORPH_NORMAL = 0x0002, + MORPH_WRINKLE = 0x0004, + MORPH_SPEED = 0x0008, + MORPH_SIDE = 0x0010 +}; + +typedef unsigned int MorphFormat_t; + +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 + +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; + int m_nMaxDXSupportLevel; + unsigned int m_nDriverVersionHigh; + unsigned int m_nDriverVersionLow; +}; + +struct MaterialVideoMode_t +{ + int m_Width; + int m_Height; + ImageFormat m_Format; + int m_RefreshRate; +}; + +struct FlashlightState_t +{ + 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; + 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; + bool m_bScissor; + int m_nLeft; + int m_nTop; + int m_nRight; + int m_nBottom; +}; + +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; +}; + +enum MaterialInitFlags_t +{ + MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE = 0x2, + MATERIAL_INIT_REFERENCE_RASTERIZER = 0x4 +}; + +enum MaterialRenderTargetDepth_t +{ + MATERIAL_RT_DEPTH_SHARED = 0x0, + MATERIAL_RT_DEPTH_SEPARATE = 0x1, + MATERIAL_RT_DEPTH_NONE = 0x2, + MATERIAL_RT_DEPTH_ONLY = 0x3 +}; + +enum RestoreChangeFlags_t +{ + MATERIAL_RESTORE_VERTEX_FORMAT_CHANGED = 0x1 +}; + +enum RenderTargetSizeMode_t +{ + RT_SIZE_NO_CHANGE = 0, + RT_SIZE_DEFAULT = 1, + RT_SIZE_PICMIP = 2, + RT_SIZE_HDR = 3, + RT_SIZE_FULL_FRAME_BUFFER = 4, + RT_SIZE_OFFSCREEN = 5, + RT_SIZE_FULL_FRAME_BUFFER_ROUNDED_UP = 6, + RT_SIZE_REPLAY_SCREENSHOT = 7, + RT_SIZE_LITERAL = 8, + RT_SIZE_LITERAL_PICMIP = 9 +}; + +typedef void (*MaterialBufferReleaseFunc_t)(); +typedef void (*MaterialBufferRestoreFunc_t)(int nChangeFlags); +typedef void (*ModeChangeCallbackFunc_t)(void); + +typedef int VertexBufferHandle_t; +typedef unsigned short MaterialHandle_t; + +using OcclusionQueryObjectHandle_t = void*; +#define INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ( (OcclusionQueryObjectHandle_t)0 ) + +class IMaterialProxyFactory; +class ITexture; +class IMaterialSystemHardwareConfig; +class CShadowMgr; + +using MaterialLock_t = void*; + +class IMaterialSystem : public IAppSystem +{ +public: + 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 CreateInterfaceFn Init(char const* pShaderAPIDLL, IMaterialProxyFactory* pMaterialProxyFactory, CreateInterfaceFn fileSystemFactory, CreateInterfaceFn cvarFactory = NULL) = 0; + virtual void SetShaderAPI(char const* pShaderAPIDLL) = 0; + virtual void SetAdapter(int nAdapter, int nFlags) = 0; + 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; + virtual IMaterialSystemHardwareConfig* GetHardwareConfig(const char* pVersion, int* returnCode) = 0; + virtual bool UpdateConfig(bool bForceUpdate) = 0; + virtual bool OverrideConfig(const MaterialSystem_Config_t& config, bool bForceUpdate) = 0; + virtual const MaterialSystem_Config_t& GetCurrentConfigForVideoCard() const = 0; + virtual bool GetRecommendedConfigurationInfo(int nDXLevel, KeyValues* pKeyValues) = 0; + virtual int GetDisplayAdapterCount() const = 0; + virtual int GetCurrentAdapter() const = 0; + virtual void GetDisplayAdapterInfo(int adapter, MaterialAdapterInfo_t& info) const = 0; + virtual int GetModeCount(int adapter) const = 0; + virtual void GetModeInfo(int adapter, int mode, MaterialVideoMode_t& info) const = 0; + virtual void AddModeChangeCallBack(ModeChangeCallbackFunc_t func) = 0; + virtual void GetDisplayMode(MaterialVideoMode_t& mode) const = 0; + virtual bool SetMode(void* hwnd, const MaterialSystem_Config_t& config) = 0; + virtual bool SupportsMSAAMode(int nMSAAMode) = 0; + virtual const MaterialSystemHardwareIdentifier_t& GetVideoCardIdentifier(void) const = 0; + virtual void SpewDriverInfo() const = 0; + virtual void GetDXLevelDefaults(uint& max_dxlevel, uint& recommended_dxlevel) = 0; + virtual void GetBackBufferDimensions(int& width, int& height) const = 0; + virtual ImageFormat GetBackBufferFormat() const = 0; + virtual bool SupportsHDRMode(HDRType_t nHDRModede) = 0; + virtual bool AddView(void* hwnd) = 0; + virtual void RemoveView(void* hwnd) = 0; + virtual void SetView(void* hwnd) = 0; + virtual void BeginFrame(float frameTime) = 0; + virtual void EndFrame() = 0; + virtual void Flush(bool flushHardware = false) = 0; + virtual void SwapBuffers() = 0; + virtual void EvictManagedResources() = 0; + virtual void ReleaseResources(void) = 0; + virtual void ReacquireResources(void) = 0; + virtual void AddReleaseFunc(MaterialBufferReleaseFunc_t func) = 0; + virtual void RemoveReleaseFunc(MaterialBufferReleaseFunc_t func) = 0; + virtual void AddRestoreFunc(MaterialBufferRestoreFunc_t func) = 0; + virtual void RemoveRestoreFunc(MaterialBufferRestoreFunc_t func) = 0; + virtual void ResetTempHWMemory(bool bExitingLevel = false) = 0; + virtual void HandleDeviceLost() = 0; + virtual int ShaderCount() const = 0; + virtual int GetShaders(int nFirstShader, int nMaxCount, IShader** ppShaderList) const = 0; + virtual int ShaderFlagCount() const = 0; + virtual const char* ShaderFlagName(int nIndex) const = 0; + virtual void GetShaderFallback(const char* pShaderName, char* pFallbackShader, int nFallbackLength) = 0; + virtual IMaterialProxyFactory* GetMaterialProxyFactory() = 0; + virtual void SetMaterialProxyFactory(IMaterialProxyFactory* pFactory) = 0; + virtual void EnableEditorMaterials() = 0; + virtual void SetInStubMode(bool bInStubMode) = 0; + 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; + virtual bool UsingFastClipping(void) = 0; + virtual int StencilBufferBits(void) = 0; + virtual void SuspendTextureStreaming() = 0; + virtual void ResumeTextureStreaming() = 0; + virtual void UncacheAllMaterials() = 0; + virtual void UncacheUnusedMaterials(bool bRecomputeStateSnapshots = false) = 0; + virtual void CacheUsedMaterials() = 0; + virtual void ReloadTextures() = 0; + virtual void ReloadMaterials(const char* pSubString = NULL) = 0; + virtual IMaterial* CreateMaterial(const char* pMaterialName, KeyValues* pVMTKeyValues) = 0; + virtual IMaterial* FindMaterial(char const* pMaterialName, const char* pTextureGroupName, bool complain = true, const char* pComplainPrefix = NULL) = 0; + virtual bool IsMaterialLoaded(char const* pMaterialName) = 0; + virtual MaterialHandle_t FirstMaterial() const = 0; + virtual MaterialHandle_t NextMaterial(MaterialHandle_t h) const = 0; + virtual MaterialHandle_t InvalidMaterial() const = 0; + virtual IMaterial* GetMaterial(MaterialHandle_t h) const = 0; + 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; + virtual bool IsTextureLoaded(char const* pTextureName) const = 0; + virtual ITexture* CreateProceduralTexture(const char* pTextureName, const char* pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags) = 0; + virtual void BeginRenderTargetAllocation() = 0; + virtual void EndRenderTargetAllocation() = 0; + virtual ITexture* CreateRenderTargetTexture(int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat format, MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED) = 0; + virtual ITexture* CreateNamedRenderTargetTextureEx(const char* pRTName, int w, int h, RenderTargetSizeMode_t sizeMode, 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, ImageFormat format, MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, bool bClampTexCoords = true, bool bAutoMipMap = false) = 0; + virtual ITexture* CreateNamedRenderTargetTextureEx2(const char* pRTName, int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat format, MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, unsigned int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, unsigned int renderTargetFlags = 0) = 0; + virtual void BeginLightmapAllocation() = 0; + virtual void EndLightmapAllocation() = 0; + virtual int AllocateLightmap(int width, int height, int offsetIntoLightmapPage[2], IMaterial* pMaterial) = 0; + virtual int AllocateWhiteLightmap(IMaterial* pMaterial) = 0; + virtual void UpdateLightmap(int lightmapPageID, int lightmapSize[2], int offsetIntoLightmapPage[2], float* pFloatImage, float* pFloatImageBump1, float* pFloatImageBump2, float* pFloatImageBump3) = 0; + virtual int GetNumSortIDs() = 0; + virtual void GetSortInfo(MaterialSystem_SortInfo_t* sortInfoArray) = 0; + 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; + virtual IMatRenderContext* GetRenderContext() = 0; + virtual bool SupportsShadowDepthTextures(void) = 0; + virtual void BeginUpdateLightmaps(void) = 0; + virtual void EndUpdateLightmaps(void) = 0; + virtual MaterialLock_t Lock() = 0; + virtual void Unlock(MaterialLock_t) = 0; + virtual ImageFormat GetShadowDepthTextureFormat() = 0; + virtual bool SupportsFetch4(void) = 0; + virtual IMatRenderContext* CreateRenderContext(MaterialContextType_t type) = 0; + virtual IMatRenderContext* SetRenderContext(IMatRenderContext*) = 0; + virtual bool SupportsCSAAMode(int nNumSamples, int nQualityLevel) = 0; + virtual void RemoveModeChangeCallBack(ModeChangeCallbackFunc_t func) = 0; + 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; + 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; + virtual void ReloadFilesInList(IFileList* pFilesToReload) = 0; + virtual bool AllowThreading(bool bAllow, int nServiceThread) = 0; + virtual IMaterial* FindMaterialEx(char const* pMaterialName, const char* pTextureGroupName, int nContext, bool complain = true, const char* pComplainPrefix = NULL) = 0; + virtual void SetRenderTargetFrameBufferSizeOverrides(int nWidth, int nHeight) = 0; + virtual void GetRenderTargetFrameBufferDimensions(int& nWidth, int& nHeight) = 0; + virtual char* GetDisplayDeviceName() const = 0; + virtual ITexture* CreateTextureFromBits(int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits) = 0; + virtual void OverrideRenderTargetAllocation(bool rtAlloc) = 0; + virtual ITextureCompositor* NewTextureCompositor(int w, int h, const char* pCompositeName, int nTeamNum, uint64 randomSeed, KeyValues* stageDesc, uint32 texCompositeCreateFlags = 0) = 0; + virtual void AsyncFindTexture(const char* pFilename, const char* pTextureGroupName, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs, bool bComplain = true, int nAdditionalCreationFlags = 0) = 0; + virtual ITexture* CreateNamedTextureFromBitsEx(const char* pName, const char* pTextureGroupName, int w, int h, int mips, ImageFormat fmt, int srcBufferSize, byte* srcBits, int nFlags) = 0; + virtual bool AddTextureCompositorTemplate(const char* pName, KeyValues* pTmplDesc, int nTexCompositeTemplateFlags = 0) = 0; + virtual bool VerifyTextureCompositorTemplates() = 0; +}; + +MAKE_INTERFACE_VERSION(IMaterialSystem, MaterialSystem, "materialsystem.dll", "VMaterialSystem081"); + +class IMatRenderContext : public IRefCounted +{ +public: + virtual void BeginRender() = 0; + virtual void EndRender() = 0; + virtual void Flush(bool flushHardware = false) = 0; + virtual void BindLocalCubemap(ITexture* pTexture) = 0; + virtual void SetRenderTarget(ITexture* pTexture) = 0; + virtual ITexture* GetRenderTarget(void) = 0; + virtual void GetRenderTargetDimensions(int& width, int& height) const = 0; + virtual void Bind(IMaterial* material, void* proxyData = 0) = 0; + virtual void BindLightmapPage(int lightmapPageID) = 0; + virtual void DepthRange(float zNear, float zFar) = 0; + virtual void ClearBuffers(bool bClearColor, bool bClearDepth, bool bClearStencil = false) = 0; + virtual void ReadPixels(int x, int y, int width, int height, unsigned char* data, ImageFormat dstFormat) = 0; + virtual void SetAmbientLight(float r, float g, float b) = 0; + virtual void SetLight(int lightNum, const LightDesc_t& desc) = 0; + virtual void SetAmbientLightCube(Vector4D cube[6]) = 0; + virtual void CopyRenderTargetToTexture(ITexture* pTexture) = 0; + virtual void SetFrameBufferCopyTexture(ITexture* pTexture, int textureIndex = 0) = 0; + virtual ITexture* GetFrameBufferCopyTexture(int textureIndex) = 0; + 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 const& matrix) = 0; + virtual void MultMatrix(VMatrix const& matrix) = 0; + virtual void MultMatrix(matrix3x4 const& matrix) = 0; + virtual void MultMatrixLocal(VMatrix const& matrix) = 0; + virtual void MultMatrixLocal(matrix3x4 const& matrix) = 0; + virtual void GetMatrix(MaterialMatrixMode_t matrixMode, VMatrix* matrix) = 0; + virtual void GetMatrix(MaterialMatrixMode_t matrixMode, matrix3x4* 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; + 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; + virtual void CullMode(MaterialCullMode_t cullMode) = 0; + virtual void SetHeightClipMode(MaterialHeightClipMode_t nHeightClipMode) = 0; + virtual void SetHeightClipZ(float z) = 0; + 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; + virtual void SetNumBoneWeights(int numBones) = 0; + virtual IMesh* CreateStaticMesh(VertexFormat_t fmt, const char* pTextureBudgetGroup, IMaterial* pMaterial = NULL) = 0; + virtual void DestroyStaticMesh(IMesh* mesh) = 0; + virtual IMesh* GetDynamicMesh(bool buffered = true, IMesh* pVertexOverride = 0, IMesh* pIndexOverride = 0, IMaterial* pAutoBind = 0) = 0; + 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; + 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; + 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; + 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; + virtual void OverrideDepthEnable(bool bEnable, bool bDepthEnable) = 0; + virtual void DrawScreenSpaceQuad(IMaterial* pMaterial) = 0; + virtual void SyncToken(const char* pToken) = 0; + virtual float ComputePixelWidthOfSphere(const Vector& origin, float flRadius) = 0; + virtual OcclusionQueryObjectHandle_t CreateOcclusionQueryObject(void) = 0; + virtual void DestroyOcclusionQueryObject(OcclusionQueryObjectHandle_t) = 0; + virtual void BeginOcclusionQueryDrawing(OcclusionQueryObjectHandle_t) = 0; + virtual void EndOcclusionQueryDrawing(OcclusionQueryObjectHandle_t) = 0; + virtual int OcclusionQuery_GetNumPixelsRendered(OcclusionQueryObjectHandle_t) = 0; + virtual void SetFlashlightMode(bool bEnable) = 0; + virtual void SetFlashlightState(const FlashlightState_t& state, const VMatrix& worldToTexture) = 0; + virtual MaterialHeightClipMode_t GetHeightClipMode() = 0; + virtual float ComputePixelDiameterOfSphere(const Vector& vecAbsOrigin, float flRadius) = 0; + virtual void EnableUserClipTransformOverride(bool bEnable) = 0; + virtual void UserClipTransform(const VMatrix& worldToView) = 0; + virtual bool GetFlashlightMode() const = 0; + virtual void ResetOcclusionQueryObject(OcclusionQueryObjectHandle_t) = 0; + virtual void Unused3() {} + virtual IMorph* CreateMorph(MorphFormat_t format, const char* pDebugName) = 0; + virtual void DestroyMorph(IMorph* pMorph) = 0; + virtual void BindMorph(IMorph* pMorph) = 0; + virtual void SetFlexWeights(int nFirstWeight, int nCount, const MorphWeight_t* pWeights) = 0; + virtual void Unused4() {}; + virtual void Unused5() {}; + virtual void Unused6() {}; + virtual void Unused7() {}; + virtual void Unused8() {}; + virtual void ReadPixelsAndStretch(Rect_t* pSrcRect, Rect_t* pDstRect, unsigned char* pBuffer, ImageFormat dstFormat, int nDstStride) = 0; + virtual void GetWindowSize(int& width, int& height) const = 0; + + virtual void DrawScreenSpaceRectangle( + IMaterial* pMaterial, + int destx, int desty, + int width, int height, + float src_texture_x0, float src_texture_y0, + float src_texture_x1, float src_texture_y1, + int src_texture_width, int src_texture_height, + void* pClientRenderable = NULL, + int nXDice = 1, + int nYDice = 1) = 0; + + virtual void LoadBoneMatrix(int boneIndex, const matrix3x4& matrix) = 0; + virtual void PushRenderTargetAndViewport() = 0; + virtual void PushRenderTargetAndViewport(ITexture* pTexture) = 0; + virtual void PushRenderTargetAndViewport(ITexture* pTexture, int nViewX, int nViewY, int nViewW, int nViewH) = 0; + virtual void PushRenderTargetAndViewport(ITexture* pTexture, ITexture* pDepthTexture, int nViewX, int nViewY, int nViewW, int nViewH) = 0; + virtual void PopRenderTargetAndViewport(void) = 0; + virtual void BindLightmapTexture(ITexture* pLightmapTexture) = 0; + 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; + 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 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; + virtual void PushCustomClipPlane(const float* pPlane) = 0; + virtual void PopCustomClipPlane(void) = 0; + virtual void GetMaxToRender(IMesh* pMesh, bool bMaxUntilFlush, int* pMaxVerts, int* pMaxIndices) = 0; + 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; + virtual ITexture* GetLocalCubemap() = 0; + virtual void ClearBuffersObeyStencil(bool bClearColor, bool bClearDepth) = 0; + virtual bool EnableClipping(bool bEnable) = 0; + virtual void GetFogDistances(float* fStart, float* fEnd, float* fFogZ) = 0; + virtual void BeginPIXEvent(unsigned long color, const char* szName) = 0; + virtual void EndPIXEvent() = 0; + virtual void SetPIXMarker(unsigned long color, const char* szName) = 0; + 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; + virtual ICallQueue* GetCallQueue() = 0; + virtual void GetWorldSpaceCameraPosition(Vector* pCameraPos) = 0; + virtual void GetWorldSpaceCameraVectors(Vector* pVecForward, Vector* pVecRight, Vector* pVecUp) = 0; + virtual void ResetToneMappingScale(float monoscale) = 0; + virtual void SetGoalToneMappingScale(float monoscale) = 0; + virtual void TurnOnToneMapping() = 0; + virtual void SetToneMappingScaleLinear(const Vector& scale) = 0; + virtual Vector GetToneMappingScaleLinear(void) = 0; + virtual void SetShadowDepthBiasFactors(float fSlopeScaleDepthBias, float fDepthBias) = 0; + virtual void PerformFullScreenStencilOperation(void) = 0; + virtual void SetLightingOrigin(Vector vLightingOrigin) = 0; + virtual void SetScissorRect(const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor) = 0; + virtual void BeginMorphAccumulation() = 0; + virtual void EndMorphAccumulation() = 0; + virtual void AccumulateMorph(IMorph* pMorph, int nMorphCount, const MorphWeight_t* pWeights) = 0; + virtual void PushDeformation(DeformationBase_t const* Deformation) = 0; + virtual void PopDeformation() = 0; + virtual int GetNumActiveDeformations() const = 0; + virtual bool GetMorphAccumulatorTexCoord(Vector2D* pTexCoord, IMorph* pMorph, int nVertex) = 0; + virtual IMesh* GetDynamicMeshEx(VertexFormat_t vertexFormat, bool bBuffered = true, IMesh* pVertexOverride = 0, IMesh* pIndexOverride = 0, IMaterial* pAutoBind = 0) = 0; + virtual void FogMaxDensity(float flMaxDensity) = 0; + virtual IMaterial* GetCurrentMaterial() = 0; + virtual int GetCurrentNumBones() const = 0; + virtual void* GetCurrentProxy() = 0; + virtual void EnableColorCorrection(bool bEnable) = 0; + virtual ColorCorrectionHandle_t AddLookup(const char* pName) = 0; + virtual bool RemoveLookup(ColorCorrectionHandle_t handle) = 0; + virtual void LockLookup(ColorCorrectionHandle_t handle) = 0; + virtual void LoadLookup(ColorCorrectionHandle_t handle, const char* pLookupName) = 0; + virtual void UnlockLookup(ColorCorrectionHandle_t handle) = 0; + virtual void SetLookupWeight(ColorCorrectionHandle_t handle, float flWeight) = 0; + virtual void ResetLookupWeights() = 0; + virtual void SetResetable(ColorCorrectionHandle_t handle, bool bResetable) = 0; + virtual void SetFullScreenDepthTextureValidityFlag(bool bIsValid) = 0; + virtual void SetNonInteractivePacifierTexture(ITexture* pTexture, float flNormalizedX, float flNormalizedY, float flNormalizedSize) = 0; + virtual void SetNonInteractiveTempFullscreenBuffer(ITexture* pTexture, MaterialNonInteractiveMode_t mode) = 0; + virtual void EnableNonInteractiveMode(MaterialNonInteractiveMode_t mode) = 0; + virtual void RefreshFrontBufferNonInteractive() = 0; + virtual void* LockRenderData(int nSizeInBytes) = 0; + virtual void UnlockRenderData(void* pData) = 0; + virtual void AddRefRenderData() = 0; + virtual void ReleaseRenderData() = 0; + virtual bool IsRenderData(const void* pData) const = 0; + virtual void PrintfVA(char* fmt, va_list vargs) = 0; + virtual void Printf(const char* fmt, ...) = 0; + virtual float Knob(char* knobname, float* setvalue = NULL) = 0; + 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; + virtual void AsyncCreateTextureFromRenderTarget(ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs) = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IMoveHelper.h b/Amalgam/src/SDK/Definitions/Interfaces/IMoveHelper.h new file mode 100644 index 0000000..1638647 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IMoveHelper.h @@ -0,0 +1,35 @@ +#pragma once +#include "Interface.h" +#include "../Main/CBaseHandle.h" +#include "../Definitions.h" +#include "../Types.h" + +class CGameTrace; +class IPhysicsSurfaceProps; +enum PLAYER_ANIM; + +typedef CBaseHandle EntityHandle_t; + +#define INVALID_ENTITY_HANDLE INVALID_EHANDLE_INDEX + +class IMoveHelper +{ +public: + virtual char const* GetName(EntityHandle_t handle) const = 0; + virtual void ResetTouchList(void) = 0; + virtual bool AddToTouched(const CGameTrace& tr, const Vector& impactvelocity) = 0; + virtual void ProcessImpacts(void) = 0; + virtual void Con_NPrintf(int idx, char const* fmt, ...) = 0; + 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; + virtual bool PlayerFallingDamage(void) = 0; + virtual void PlayerSetAnimation(PLAYER_ANIM playerAnim) = 0; + virtual IPhysicsSurfaceProps* GetSurfaceProps(void) = 0; + virtual bool IsWorldEntity(const CBaseHandle& handle) = 0; + +protected: + virtual ~IMoveHelper() {} +}; + +MAKE_INTERFACE_SIGNATURE(IMoveHelper, MoveHelper, "client.dll", "48 8B 0D ? ? ? ? 48 8B 01 FF 50 ? 0F B7 D7", 0x0, 2); // this might be wrong \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IStudioRender.h b/Amalgam/src/SDK/Definitions/Interfaces/IStudioRender.h new file mode 100644 index 0000000..d56e5c9 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IStudioRender.h @@ -0,0 +1,252 @@ +#pragma once +#include "Interface.h" +#include "IMaterialSystem.h" +#include "../Misc/IAppSystem.h" +#include "../Main/IMaterial.h" +#include "../Misc/IMDLCache.h" +#include "../Misc/Studio.h" +#include "../Main/UtlVector.h" +#include "../Types.h" + +struct studiohdr_t; +struct studiomeshdata_t; +struct LightDesc_t; +class IMaterial; +struct studiohwdata_t; +struct Ray_t; +class IMaterialSystem; +class IMesh; +struct vertexFileHeader_t; +struct FlashlightState_t; +struct FileHeader_t; +class IPooledVBAllocator; + +typedef void (*StudioRender_Printf_t)(const char* fmt, ...); + +struct StudioRenderConfig_t +{ + float fEyeShiftX; + float fEyeShiftY; + float fEyeShiftZ; + float fEyeSize; + float fEyeGlintPixelWidthLODThreshold; + int maxDecalsPerModel; + int drawEntities; + int skin; + int fullbright; + bool bEyeMove : 1; + 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; + int m_nReserved[4]; +}; + +using StudioDecalHandle_t = void*; +#define STUDIORENDER_DECAL_INVALID ( (StudioDecalHandle_t)0 ) + +enum +{ + ADDDECAL_TO_ALL_LODS = -1 +}; + +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, + 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 +}; + +#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 +}; + +enum OverrideType_t +{ + OVERRIDE_NORMAL = 0, + OVERRIDE_BUILD_SHADOWS, + OVERRIDE_DEPTH_WRITE, + OVERRIDE_SSAO_DEPTH_WRITE +}; + +enum +{ + USESHADOWLOD = -2 +}; + +#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; + //CUtlVector 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 +{ + 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]; + 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 m_PoseToWorld[MAXSTUDIOBONES]; +}; + +struct model_array_instance_t +{ + matrix3x4 modelToWorld; +}; + +class IStudioDataCache : public IAppSystem +{ +public: + virtual bool VerifyHeaders(studiohdr_t* pStudioHdr) = 0; + virtual vertexFileHeader_t* CacheVertexData(studiohdr_t* pStudioHdr) = 0; +}; + +class IStudioRender : public IAppSystem +{ +public: + virtual void BeginFrame(void) = 0; + virtual void EndFrame(void) = 0; + virtual void Mat_Stub(IMaterialSystem* pMatSys) = 0; + virtual void UpdateConfig(const StudioRenderConfig_t& config) = 0; + virtual void GetCurrentConfig(StudioRenderConfig_t& config) = 0; + virtual bool LoadModel(studiohdr_t* pStudioHdr, void* pVtxData, studiohwdata_t* pHardwareData) = 0; + virtual void UnloadModel(studiohwdata_t* pHardwareData) = 0; + virtual void RefreshStudioHdr(studiohdr_t* pStudioHdr, studiohwdata_t* pHardwareData) = 0; + virtual void SetEyeViewTarget(const studiohdr_t* pStudioHdr, int nBodyIndex, const Vector& worldPosition) = 0; + 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; + virtual void SetViewState(const Vector& viewOrigin, const Vector& viewRight, const Vector& viewUp, const Vector& viewPlaneNormal) = 0; + virtual void LockFlexWeights(int nWeightCount, float** ppFlexWeights, float** ppFlexDelayedWeights = NULL) = 0; + virtual void UnlockFlexWeights() = 0; + virtual matrix3x4* LockBoneMatrices(int nBoneCount) = 0; + virtual void UnlockBoneMatrices() = 0; + 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; + virtual void SetColorModulation(float const* pColor) = 0; + virtual void SetAlphaModulation(float flAlpha) = 0; + virtual void DrawModel(DrawModelResults_t* pResults, const DrawModelInfo_t& info, matrix3x4* pBoneToWorld, float* pFlexWeights, float* pFlexDelayedWeights, const Vector& modelOrigin, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL) = 0; + virtual void DrawModelStaticProp(const DrawModelInfo_t& drawInfo, const matrix3x4& modelToWorld, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL) = 0; + virtual void DrawStaticPropDecals(const DrawModelInfo_t& drawInfo, const matrix3x4& modelToWorld) = 0; + virtual void DrawStaticPropShadows(const DrawModelInfo_t& drawInfo, const matrix3x4& modelToWorld, int flags) = 0; + virtual void ForcedMaterialOverride(IMaterial* newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL) = 0; + virtual StudioDecalHandle_t CreateDecalList(studiohwdata_t* pHardwareData) = 0; + virtual void DestroyDecalList(StudioDecalHandle_t handle) = 0; + virtual void AddDecal(StudioDecalHandle_t handle, studiohdr_t* pStudioHdr, matrix3x4* pBoneToWorld, const Ray_t& ray, const Vector& decalUp, IMaterial* pDecalMaterial, float radius, int body, bool noPokethru = false, int maxLODToDecal = ADDDECAL_TO_ALL_LODS) = 0; + virtual void ComputeLighting(const Vector* pAmbient, int lightCount, LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting) = 0; + virtual void ComputeLightingConstDirectional(const Vector* pAmbient, int lightCount, LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting, float flDirectionalAmount) = 0; + virtual void AddShadow(IMaterial* pMaterial, void* pProxyData, FlashlightState_t* m_pFlashlightState = NULL, VMatrix* pWorldToTexture = NULL, ITexture* pFlashlightDepthTexture = NULL) = 0; + virtual void ClearAllShadows() = 0; + virtual int ComputeModelLod(studiohwdata_t* pHardwareData, float unitSphereSize, float* pMetric = NULL) = 0; + virtual void GetPerfStats(DrawModelResults_t* pResults, const DrawModelInfo_t& info, CUtlBuffer* pSpewBuf = NULL) const = 0; + virtual void GetTriangles(const DrawModelInfo_t& info, matrix3x4* pBoneToWorld, GetTriangles_Output_t& out) = 0; + 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; + virtual void DrawModelArray(const DrawModelInfo_t& drawInfo, int arrayCount, model_array_instance_t* pInstanceData, int instanceStride, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL) = 0; + virtual void GetMaterialOverride(IMaterial** ppOutForcedMaterial, OverrideType_t* pOutOverrideType) = 0; + + void SetColorModulation(float r, float g, float b) + { + const float clr[3] = { r, g, b }; + SetColorModulation(clr); + } + + void SetColorModulation(Color_t clr) + { + float _clr[3] = { float(clr.r) / 255, float(clr.g) / 255, float(clr.b) / 255 }; + SetColorModulation(_clr); + } +}; + +MAKE_INTERFACE_VERSION(IStudioRender, StudioRender, "studiorender.dll", "VStudioRender025"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IUniformRandomStream.h b/Amalgam/src/SDK/Definitions/Interfaces/IUniformRandomStream.h new file mode 100644 index 0000000..83fcf13 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IUniformRandomStream.h @@ -0,0 +1,13 @@ +#pragma once +#include "Interface.h" + +class IUniformRandomStream +{ +public: + virtual void SetSeed(int iSeed) = 0; + virtual float RandomFloat(float flMinVal = 0.f, float flMaxVal = 1.f) = 0; + virtual int RandomInt(int iMinVal, int iMaxVal) = 0; + virtual float RandomFloatExp(float flMinVal = 0.f, float flMaxVal = 1.f, float flExponent = 1.f) = 0; +}; + +MAKE_INTERFACE_SIGNATURE(IUniformRandomStream, UniformRandomStream, "client.dll", "48 8B 0D ? ? ? ? 33 D2 F3 0F 59 CE", 0x0, 1); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IVEngineClient.h b/Amalgam/src/SDK/Definitions/Interfaces/IVEngineClient.h new file mode 100644 index 0000000..859f269 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IVEngineClient.h @@ -0,0 +1,359 @@ +#pragma once +#include "Interface.h" +#include "../Main/UtlVector.h" +#include "../Misc/BaseTypes.h" +#include "../Misc/bitbuf.h" +#include "../Misc/ButtonCode.h" +#include "../Misc/ChecksumCRC.h" +#include "../Misc/ClientClass.h" +#include "../Misc/CViewSetup.h" +#include "../Misc/Datamap.h" +#include "../Misc/Modes.h" +#include "../Definitions.h" +#include + +struct model_t; +class CSentence; +struct vrect_t; +struct cmodel_t; +class IMaterial; +class CAudioSource; +class CMeasureSection; +class SurfInfo; +class ISpatialQuery; +struct cache_user_t; +class IMaterialSystem; +struct ScreenFade_t; +struct ScreenShake_t; +class CEngineSprite; +class CGlobalVarsBase; +class CPhysCollide; +class CSaveRestoreData; +class INetChannelInfo; +struct datamap_t; +struct typedescription_t; +class CStandardRecvProxies; +struct client_textmessage_t; +class IAchievementMgr; +class CGamestatsData; +class KeyValues; +class IFileList; +class CRenamedRecvTableInfo; +class CMouthInfo; +class IConVar; + +//from xboxstubs.h +typedef struct _XUSER_DATA +{ + BYTE type; + + union + { + int nData; + int64 i64Data; + double dblData; + struct + { + uint cbData; + char* pwszData; + } string; + float fData; + struct + { + 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 player_info_s +{ + char name[MAX_PLAYER_NAME_LENGTH]; + int userID; + char guid[SIGNED_GUID_LEN + 1]; + uint32 friendsID; + char friendsName[MAX_PLAYER_NAME_LENGTH]; + bool fakeplayer; + bool ishltv; + bool isreplay; + CRC32_t customFiles[MAX_CUSTOM_FILES]; + unsigned char filesDownloaded; +} PlayerInfo_t; + +struct AudioState_t +{ + Vector m_Origin; + QAngle m_Angles; + bool m_bIsUnderwater; +}; + +enum SkyboxVisibility_t +{ + SKYBOX_NOT_VISIBLE = 0, + SKYBOX_3DSKYBOX_VISIBLE, + SKYBOX_2DSKYBOX_VISIBLE, +}; + +struct SkyBoxMaterials_t +{ + IMaterial* material[6]; +}; + +enum ClientFrameStage_t +{ + FRAME_UNDEFINED = -1, + FRAME_START, + FRAME_NET_UPDATE_START, + FRAME_NET_UPDATE_POSTDATAUPDATE_START, + FRAME_NET_UPDATE_POSTDATAUPDATE_END, + FRAME_NET_UPDATE_END, + FRAME_RENDER_START, + FRAME_RENDER_END +}; + +struct OcclusionParams_t +{ + float m_flMaxOccludeeArea; + float m_flMinOccluderArea; +}; + +class IVEngineClient +{ +public: + virtual int GetIntersectingSurfaces(const model_t* model, const Vector& vCenter, const float radius, const bool bOnlyVisibleSurfaces, SurfInfo* pInfos, const int nMaxInfos) = 0; + virtual Vector GetLightForPoint(const Vector& pos, bool bClamp) = 0; + virtual IMaterial* TraceLineMaterialAndLighting(const Vector& start, const Vector& end, Vector& diffuseLightColor, Vector& baseColor) = 0; + virtual const char* ParseFile(const char* data, char* token, int maxlen) = 0; + virtual bool CopyLocalFile(const char* source, const char* destination) = 0; + virtual void GetScreenSize(int& width, int& height) = 0; + virtual void ServerCmd(const char* szCmdString, bool bReliable = true) = 0; + virtual void ClientCmd(const char* szCmdString) = 0; + virtual bool GetPlayerInfo(int ent_num, PlayerInfo_t* pinfo) = 0; + virtual int GetPlayerForUserID(int userID) = 0; + virtual client_textmessage_t* TextMessageGet(const char* pName) = 0; + virtual bool Con_IsVisible(void) = 0; + virtual int GetLocalPlayer(void) = 0; + virtual const model_t* LoadModel(const char* pName, bool bProp = false) = 0; + virtual float Time(void) = 0; + virtual float GetLastTimeStamp(void) = 0; + virtual CSentence* GetSentence(CAudioSource* pAudioSource) = 0; + virtual float GetSentenceLength(CAudioSource* pAudioSource) = 0; + virtual bool IsStreaming(CAudioSource* pAudioSource) const = 0; + virtual void GetViewAngles(QAngle& va) = 0; + inline Vec3 GetViewAngles() { QAngle out = {}; GetViewAngles(out); return out; } + virtual void SetViewAngles(QAngle& va) = 0; + virtual int GetMaxClients(void) = 0; + virtual const char* Key_LookupBinding(const char* pBinding) = 0; + virtual const char* Key_BindingForKey(ButtonCode_t code) = 0; + virtual void StartKeyTrapMode(void) = 0; + virtual bool CheckDoneKeyTrapping(ButtonCode_t& code) = 0; + virtual bool IsInGame(void) = 0; + virtual bool IsConnected(void) = 0; + virtual bool IsDrawingLoadingImage(void) = 0; + virtual void Con_NPrintf(int pos, const char* fmt, ...) = 0; + virtual void Con_NXPrintf(const struct con_nprint_s* info, const char* fmt, ...) = 0; + virtual int IsBoxVisible(const Vector& mins, const Vector& maxs) = 0; + virtual int IsBoxInViewCluster(const Vector& mins, const Vector& maxs) = 0; + virtual bool CullBox(const Vector& mins, const Vector& maxs) = 0; + virtual void Sound_ExtraUpdate(void) = 0; + virtual const char* GetGameDirectory(void) = 0; + virtual const VMatrix& WorldToScreenMatrix() = 0; + virtual const VMatrix& WorldToViewMatrix() = 0; + virtual int GameLumpVersion(int lumpId) const = 0; + virtual int GameLumpSize(int lumpId) const = 0; + virtual bool LoadGameLump(int lumpId, void* pBuffer, int size) = 0; + virtual int LevelLeafCount() const = 0; + virtual ISpatialQuery* GetBSPTreeQuery() = 0; + virtual void LinearToGamma(float* linear, float* gamma) = 0; + virtual float LightStyleValue(int style) = 0; + virtual void ComputeDynamicLighting(const Vector& pt, const Vector* pNormal, Vector& color) = 0; + virtual void GetAmbientLightColor(Vector& color) = 0; + virtual int GetDXSupportLevel() = 0; + virtual bool SupportsHDR() = 0; + virtual void Mat_Stub(IMaterialSystem* pMatSys) = 0; + virtual void GetChapterName(char* pchBuff, int iMaxLength) = 0; + virtual char const* GetLevelName(void) = 0; + virtual int GetLevelVersion(void) = 0; + virtual struct IVoiceTweak_s* GetVoiceTweakAPI(void) = 0; + virtual void EngineStats_BeginFrame(void) = 0; + virtual void EngineStats_EndFrame(void) = 0; + virtual void FireEvents() = 0; + virtual int GetLeavesArea(int* pLeaves, int nLeaves) = 0; + virtual bool DoesBoxTouchAreaFrustum(const Vector& mins, const Vector& maxs, int iArea) = 0; + virtual void SetAudioState(const AudioState_t& state) = 0; + 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; + virtual void ComputeLighting(const Vector& pt, const Vector* pNormal, bool bClamp, Vector& color, Vector* pBoxColors = NULL) = 0; + virtual void ActivateOccluder(int nOccluderIndex, bool bActive) = 0; + virtual bool IsOccluded(const Vector& vecAbsMins, const Vector& vecAbsMaxs) = 0; + virtual void* SaveAllocMemory(size_t num, size_t size) = 0; + virtual void SaveFreeMemory(void* pSaveMem) = 0; + virtual INetChannelInfo* GetNetChannelInfo(void) = 0; + virtual void DebugDrawPhysCollide(const CPhysCollide* pCollide, IMaterial* pMaterial, matrix3x4& transform, const color32& color) = 0; + virtual void CheckPoint(const char* pName) = 0; + virtual void DrawPortals() = 0; + virtual bool IsPlayingDemo(void) = 0; + virtual bool IsRecordingDemo(void) = 0; + virtual bool IsPlayingTimeDemo(void) = 0; + virtual int GetDemoRecordingTick(void) = 0; + virtual int GetDemoPlaybackTick(void) = 0; + virtual int GetDemoPlaybackStartTick(void) = 0; + virtual float GetDemoPlaybackTimeScale(void) = 0; + virtual int GetDemoPlaybackTotalTicks(void) = 0; + virtual bool IsPaused(void) = 0; + virtual bool IsTakingScreenshot(void) = 0; + virtual bool IsHLTV(void) = 0; + virtual bool IsLevelMainMenuBackground(void) = 0; + virtual void GetMainMenuBackgroundName(char* dest, int destlen) = 0; + virtual void GetVideoModes(int& nCount, vmode_s*& pModes) = 0; + virtual void SetOcclusionParameters(const OcclusionParams_t& params) = 0; + virtual void GetUILanguage(char* dest, int destlen) = 0; + virtual SkyboxVisibility_t IsSkyboxVisibleFromPoint(const Vector& vecPoint) = 0; + virtual const char* GetMapEntitiesString() = 0; + virtual bool IsInEditMode(void) = 0; + virtual float GetScreenAspectRatio() = 0; + virtual bool REMOVED_SteamRefreshLogin(const char* password, bool isSecure) = 0; + virtual bool REMOVED_SteamProcessCall(bool& finished) = 0; + virtual unsigned int GetEngineBuildNumber() = 0; + virtual const char* GetProductVersionString() = 0; + virtual void GrabPreColorCorrectedFrame(int x, int y, int width, int height) = 0; + virtual bool IsHammerRunning() const = 0; + virtual void ExecuteClientCmd(const char* szCmdString) = 0; + virtual bool MapHasHDRLighting(void) = 0; + virtual int GetAppID() = 0; + virtual Vector GetLightForPointFast(const Vector& pos, bool bClamp) = 0; + virtual void ClientCmd_Unrestricted(const char* szCmdString) = 0; + virtual void SetRestrictServerCommands(bool bRestrict) = 0; + virtual void SetRestrictClientCommands(bool bRestrict) = 0; + virtual void SetOverlayBindProxy(int iOverlayID, void* pBindProxy) = 0; + virtual bool CopyFrameBufferToMaterial(const char* pMaterialName) = 0; + virtual void ChangeTeam(const char* pTeamName) = 0; + virtual void ReadConfiguration(const bool readDefault = false) = 0; + virtual void SetAchievementMgr(IAchievementMgr* pAchievementMgr) = 0; + virtual IAchievementMgr* GetAchievementMgr() = 0; + virtual bool MapLoadFailed(void) = 0; + virtual void SetMapLoadFailed(bool bState) = 0; + virtual bool IsLowViolence() = 0; + virtual const char* GetMostRecentSaveGame(void) = 0; + virtual void SetMostRecentSaveGame(const char* lpszFilename) = 0; + virtual void StartXboxExitingProcess() = 0; + virtual bool IsSaveInProgress() = 0; + virtual uint OnStorageDeviceAttached(void) = 0; + virtual void OnStorageDeviceDetached(void) = 0; + virtual void ResetDemoInterpolation(void) = 0; + virtual void SetGamestatsData(CGamestatsData* pGamestatsData) = 0; + virtual CGamestatsData* GetGamestatsData() = 0; + virtual void ServerCmdKeyValues(KeyValues* pKeyValues) = 0; + virtual bool IsSkippingPlayback(void) = 0; + virtual bool IsLoadingDemo(void) = 0; + virtual bool IsPlayingDemoALocallyRecordedDemo() = 0; + virtual const char* Key_LookupBindingExact(const char* pBinding) = 0; + virtual void AddPhonemeFile(const char* pszPhonemeFile) = 0; + virtual float GetPausedExpireTime(void) = 0; + virtual bool StartDemoRecording(const char* pszFilename, const char* pszFolder = NULL) = 0; + virtual void StopDemoRecording(void) = 0; + virtual void TakeScreenshot(const char* pszFilename, const char* pszFolder = NULL) = 0; +}; + +MAKE_INTERFACE_VERSION(IVEngineClient, EngineClient, "engine.dll", "VEngineClient014"); + +class IBaseClientDLL +{ +public: + virtual int Init(CreateInterfaceFn appSystemFactory, CreateInterfaceFn physicsFactory, CGlobalVarsBase* pGlobals) = 0; + virtual void PostInit() = 0; + virtual void Shutdown(void) = 0; + virtual bool ReplayInit(CreateInterfaceFn replayFactory) = 0; + virtual bool ReplayPostInit() = 0; + virtual void LevelInitPreEntity(char const* pMapName) = 0; + virtual void LevelInitPostEntity() = 0; + virtual void LevelShutdown(void) = 0; + virtual ClientClass* GetAllClasses(void) = 0; + virtual int HudVidInit(void) = 0; + virtual void HudProcessInput(bool bActive) = 0; + virtual void HudUpdate(bool bActive) = 0; + virtual void HudReset(void) = 0; + virtual void HudText(const char* message) = 0; + virtual void IN_ActivateMouse(void) = 0; + virtual void IN_DeactivateMouse(void) = 0; + virtual void IN_Accumulate(void) = 0; + virtual void IN_ClearStates(void) = 0; + virtual bool IN_IsKeyDown(const char* name, bool& isdown) = 0; + virtual void IN_OnMouseWheeled(int nDelta) = 0; + virtual int IN_KeyEvent(int eventcode, ButtonCode_t keynum, const char* pszCurrentBinding) = 0; + 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 void View_Render(vrect_t* rect) = 0; + virtual void RenderView(const CViewSetup& view, int nClearFlags, int whatToDraw) = 0; + virtual void View_Fade(ScreenFade_t* pSF) = 0; + virtual void SetCrosshairAngle(const QAngle& angle) = 0; + virtual void InitSprite(CEngineSprite* pSprite, const char* loadname) = 0; + virtual void ShutdownSprite(CEngineSprite* pSprite) = 0; + virtual int GetSpriteSize(void) const = 0; + virtual void VoiceStatus(int entindex, qboolean bTalking) = 0; + virtual void InstallStringTableCallback(char const* tableName) = 0; + virtual void FrameStageNotify(ClientFrameStage_t curStage) = 0; + virtual bool DispatchUserMessage(int msg_type, bf_read& msg_data) = 0; + 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; + virtual CStandardRecvProxies* GetStandardRecvProxies() = 0; + virtual void WriteSaveGameScreenshot(const char* pFilename) = 0; + virtual void EmitSentenceCloseCaption(char const* tokenstream) = 0; + virtual void EmitCloseCaption(char const* captionname, float duration) = 0; + virtual bool CanRecordDemo(char* errorMsg, int length) const = 0; + virtual void OnDemoRecordStart(char const* pDemoBaseName) = 0; + virtual void OnDemoRecordStop() = 0; + virtual void OnDemoPlaybackStart(char const* pDemoBaseName) = 0; + virtual void OnDemoPlaybackStop() = 0; + virtual bool ShouldDrawDropdownConsole() = 0; + virtual int GetScreenWidth() = 0; + virtual int GetScreenHeight() = 0; + virtual void WriteSaveGameScreenshotOfSize(const char* pFilename, int width, int height, bool bCreatePowerOf2Padded = false, bool bWriteVTF = false) = 0; + virtual bool GetPlayerView(CViewSetup& playerView) = 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; + virtual void StartStatsReporting(HANDLE handle, bool bArbitrated) = 0; + virtual void InvalidateMdlCache() = 0; + virtual void IN_SetSampleTime(float frametime) = 0; + virtual void ReloadFilesInList(IFileList* pFilesToReload) = 0; + virtual bool HandleUiToggle() = 0; + virtual bool ShouldAllowConsole() = 0; + virtual CRenamedRecvTableInfo* GetRenamedRecvTableInfos() = 0; + virtual CMouthInfo* GetClientUIMouthInfo() = 0; + virtual void FileReceived(const char* fileName, unsigned int transferID) = 0; + virtual const char* TranslateEffectForVisionFilter(const char* pchEffectType, const char* pchEffectName) = 0; + virtual void ClientAdjustStartSoundParams(struct StartSoundParams_t& params) = 0; + virtual bool DisconnectAttempt(void) = 0; + virtual bool IsConnectedUserInfoChangeAllowed(IConVar* pCvar) = 0; +}; + +MAKE_INTERFACE_VERSION(IBaseClientDLL, BaseClientDLL, "client.dll", "VClient017"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IVModelInfo.h b/Amalgam/src/SDK/Definitions/Interfaces/IVModelInfo.h new file mode 100644 index 0000000..3de3cba --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IVModelInfo.h @@ -0,0 +1,118 @@ +#pragma once +#include "Interface.h" +#include "../Types.h" + +class IMaterial; +class KeyValues; +struct vcollide_t; +struct model_t; +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; + +class IModelLoadCallback +{ +public: + virtual void OnModelLoadComplete(const model_t* pModel) = 0; +}; + +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; } +}; + +class IVModelInfo +{ +public: + virtual ~IVModelInfo(void) {} + virtual const model_t* GetModel(int modelindex) = 0; + virtual int GetModelIndex(const char* name) const = 0; + 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* 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; + 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; + 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; + virtual void SetLevelScreenFadeRange(float flMinSize, float flMaxSize) = 0; + virtual void GetLevelScreenFadeRange(float* pMinArea, float* pMaxArea) const = 0; + virtual void SetViewScreenFadeRange(float flMinSize, float flMaxSize) = 0; + 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; + virtual int GetAutoplayList(const studiohdr_t* pStudioHdr, unsigned short** pAutoplayList) const = 0; + virtual CPhysCollide* GetCollideForVirtualTerrain(int index) = 0; + virtual bool IsUsingFBTexture(const model_t* model, int nSkin, int nBody, void /*IClientRenderable*/* pClientRenderable) const = 0; + 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; + 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; + virtual void OnLevelChange() = 0; + virtual int GetModelClientSideIndex(const char* name) const = 0; + 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; + virtual bool RegisterModelLoadCallback(int modelindex, IModelLoadCallback* pCallback, bool bCallImmediatelyIfLoaded = true) = 0; + virtual void UnregisterModelLoadCallback(int modelindex, IModelLoadCallback* pCallback) = 0; +}; + +class IVModelInfoClient : public IVModelInfo +{ +public: + virtual void OnDynamicModelsStringTableChange(int nStringIndex, const char* pString, const void* pData) = 0; + virtual const model_t* FindOrLoadModel(const char* name) = 0; +}; + +MAKE_INTERFACE_VERSION(IVModelInfoClient, ModelInfoClient, "engine.dll", "VModelInfoClient006"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IVModelRender.h b/Amalgam/src/SDK/Definitions/Interfaces/IVModelRender.h new file mode 100644 index 0000000..f9c9244 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IVModelRender.h @@ -0,0 +1,98 @@ +#pragma once +#include "Interface.h" +#include "IStudioRender.h" +#include "../Types.h" + +class IClientRenderable; +struct model_t; +using LightCacheHandle_t = void*; + +struct DrawModelState_t +{ + studiohdr_t* m_pStudioHdr; + studiohwdata_t* m_pStudioHWData; + IClientRenderable* m_pRenderable; + const matrix3x4* m_pModelToWorld; + StudioDecalHandle_t m_decals; + int m_drawFlags; + int m_lod; +}; + +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* pModelToWorld; + const matrix3x4* pLightingOffset; + const Vector* pLightingOrigin; + int flags; + int entity_index; + int skin; + int body; + int hitboxset; + ModelInstanceHandle_t instance; +}; + +struct StaticPropRenderInfo_t +{ + const matrix3x4* pModelToWorld; + const model_t* pModel; + IClientRenderable* pRenderable; + Vector* pLightingOrigin; + short skin; + ModelInstanceHandle_t instance; +}; + +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* modelToWorld = NULL, + const matrix3x4* pLightingOffset = NULL) = 0; + + virtual void ForcedMaterialOverride(IMaterial* newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL) = 0; + virtual void SetViewTarget(const CStudioHdr* pStudioHdr, int nBodyIndex, const Vector& target) = 0; + virtual ModelInstanceHandle_t CreateInstance(IClientRenderable* pRenderable, LightCacheHandle_t* pCache = NULL) = 0; + virtual void DestroyInstance(ModelInstanceHandle_t handle) = 0; + virtual void SetStaticLighting(ModelInstanceHandle_t handle, LightCacheHandle_t* pHandle) = 0; + virtual LightCacheHandle_t GetStaticLighting(ModelInstanceHandle_t handle) = 0; + virtual bool ChangeInstance(ModelInstanceHandle_t handle, IClientRenderable* pRenderable) = 0; + 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; + virtual void RemoveAllDecals(ModelInstanceHandle_t handle) = 0; + virtual void RemoveAllDecalsFromAllModels() = 0; + virtual matrix3x4* DrawModelShadowSetup(IClientRenderable* pRenderable, int body, int skin, DrawModelInfo_t* pInfo, matrix3x4* pCustomBoneToWorld = NULL) = 0; + virtual void DrawModelShadow(IClientRenderable* pRenderable, const DrawModelInfo_t& info, matrix3x4* pCustomBoneToWorld = NULL) = 0; + virtual bool RecomputeStaticLighting(ModelInstanceHandle_t handle) = 0; + virtual void ReleaseAllStaticPropColorData(void) = 0; + virtual void RestoreAllStaticPropColorData(void) = 0; + virtual int DrawModelEx(ModelRenderInfo_t& pInfo) = 0; + virtual int DrawModelExStaticProp(ModelRenderInfo_t& pInfo) = 0; + virtual bool DrawModelSetup(ModelRenderInfo_t& pInfo, DrawModelState_t* pState, matrix3x4* pCustomBoneToWorld, matrix3x4** ppBoneToWorldOut) = 0; + virtual void DrawModelExecute(const DrawModelState_t& state, const ModelRenderInfo_t& pInfo, matrix3x4* pCustomBoneToWorld = NULL) = 0; + virtual void SetupLighting(const Vector& vecCenter) = 0; + virtual int DrawStaticPropArrayFast(StaticPropRenderInfo_t* pProps, int count, bool bShadowDepth) = 0; + 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_t cColor, bool noPokeThru = false, int maxLODToDecal = ADDDECAL_TO_ALL_LODS) = 0; + virtual void GetMaterialOverride(IMaterial** ppOutForcedMaterial, OverrideType_t* pOutOverrideType) = 0; +}; + +MAKE_INTERFACE_VERSION(IVModelRender, ModelRender, "engine.dll", "VEngineModel016"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IVRenderView.h b/Amalgam/src/SDK/Definitions/Interfaces/IVRenderView.h new file mode 100644 index 0000000..bcf7f3b --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IVRenderView.h @@ -0,0 +1,204 @@ +#pragma once +#include "IMaterialSystem.h" +#include "Interface.h" +#include "../Misc/BaseTypes.h" +#include "../Misc/IRefCounted.h" +#include "../Misc/VPlane.h" +#include "../Definitions.h" + +class IClientRenderable; +class IClientEntity; +class CViewSetup; +struct model_t; + +enum +{ + FRUSTUM_RIGHT = 0, + FRUSTUM_LEFT = 1, + FRUSTUM_TOP = 2, + FRUSTUM_BOTTOM = 3, + FRUSTUM_NEARZ = 4, + FRUSTUM_FARZ = 5, + FRUSTUM_NUMPLANES = 6 +}; + +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]; + +typedef unsigned short LeafIndex_t; +typedef short LeafFogVolume_t; + +enum +{ + INVALID_LEAF_INDEX = (LeafIndex_t)~0 +}; + +struct WorldListInfo_t +{ + int m_ViewFogVolume; + int m_LeafCount; + LeafIndex_t* m_pLeafList; + LeafFogVolume_t* m_pLeafFogVolume; +}; + +class IWorldRenderList : public IRefCounted +{ +}; + +struct VisibleFogVolumeInfo_t +{ + int m_nVisibleFogVolume; + int m_nVisibleFogVolumeLeaf; + bool m_bEyeInFogVolume; + float m_flDistanceToWater; + float m_flWaterHeight; + IMaterial* m_pFogVolumeMaterial; +}; + +struct BrushVertex_t +{ + Vector m_Pos; + Vector m_Normal; + Vector m_TangentS; + Vector m_TangentT; + Vector2D m_TexCoord; + Vector2D m_LightmapCoord; +}; + +struct VisOverrideData_t +{ + Vector m_vecVisOrigin; + float m_fDistToAreaPortalTolerance; +}; + +class IBrushSurface +{ +public: + virtual void ComputeTextureCoordinate(Vector const& worldPos, Vector2D& texCoord) = 0; + virtual void ComputeLightmapCoordinate(Vector const& worldPos, Vector2D& lightmapCoord) = 0; + virtual int GetVertexCount() const = 0; + virtual void GetVertexData(BrushVertex_t* pVerts) = 0; + virtual IMaterial* GetMaterial() = 0; +}; + +class IBrushRenderer +{ +public: + virtual bool RenderBrushModelSurface(IClientEntity* pBaseEntity, IBrushSurface* pBrushSurface) = 0; +}; + +#define MAX_VIS_LEAVES 32 + +enum DrawBrushModelMode_t +{ + DBM_DRAW_ALL = 0, + DBM_DRAW_OPAQUE_ONLY, + DBM_DRAW_TRANSLUCENT_ONLY +}; + +enum +{ + VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS = 0x00000001 +}; + +class IVRenderView +{ +public: + virtual void DrawBrushModel(IClientEntity* baseentity, model_t* model, const Vector& origin, const QAngle& angles, bool bUnused) = 0; + virtual void DrawIdentityBrushModel(IWorldRenderList* pList, model_t* model) = 0; + virtual void TouchLight(struct dlight_t* light) = 0; + virtual void Draw3DDebugOverlays(void) = 0; + virtual void SetBlend(float blend) = 0; + virtual float GetBlend(void) = 0; + virtual void SetColorModulation(float const* blend) = 0; + virtual void GetColorModulation(float* blend) = 0; + virtual void SceneBegin(void) = 0; + virtual void SceneEnd(void) = 0; + virtual void GetVisibleFogVolume(const Vector& eyePoint, VisibleFogVolumeInfo_t* pInfo) = 0; + 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; + virtual void DrawTopView(bool enable) = 0; + virtual void TopViewBounds(Vector2D const& mins, Vector2D const& maxs) = 0; + virtual void DrawLights(void) = 0; + virtual void DrawMaskEntities(void) = 0; + virtual void DrawTranslucentSurfaces(IWorldRenderList* pList, int sortIndex, unsigned long flags, bool bShadowDepth) = 0; + virtual void DrawLineFile(void) = 0; + virtual void DrawLightmaps(IWorldRenderList* pList, int pageId) = 0; + virtual void ViewSetupVis(bool novis, int numorigins, const Vector origin[]) = 0; + virtual bool AreAnyLeavesVisible(int* leafList, int nLeaves) = 0; + virtual void VguiPaint(void) = 0; + virtual void ViewDrawFade(byte* color, IMaterial* pMaterial) = 0; + virtual void OLD_SetProjectionMatrix(float fov, float zNear, float zFar) = 0; + virtual colorVec GetLightAtPoint(Vector& pos) = 0; + virtual int GetViewEntity(void) = 0; + virtual float GetFieldOfView(void) = 0; + virtual unsigned char** GetAreaBits(void) = 0; + virtual void SetFogVolumeState(int nVisibleFogVolume, bool bUseHeightFog) = 0; + virtual void InstallBrushSurfaceRenderer(IBrushRenderer* pBrushRenderer) = 0; + virtual void DrawBrushModelShadow(IClientRenderable* pRenderable) = 0; + 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; + virtual void VGui_Paint(int mode) = 0; + 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; + virtual void SetMainView(const Vector& vecOrigin, const QAngle& angles) = 0; + virtual void ViewSetupVisEx(bool novis, int numorigins, const Vector origin[], unsigned int& returnFlags) = 0; + 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; + + void SetColorModulation(float r, float g, float b) + { + float blend[3] = { r, g, b }; + SetColorModulation(blend); + } + + void SetColorModulation(Color_t clr) + { + float blend[3] = { clr.r / 255.f, clr.g / 255.f, clr.b / 255.f }; + SetColorModulation(blend); + } +}; + +MAKE_INTERFACE_VERSION(IVRenderView, RenderView, "engine.dll", "VEngineRenderView014"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/IViewRender.h b/Amalgam/src/SDK/Definitions/Interfaces/IViewRender.h new file mode 100644 index 0000000..2ea389c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/IViewRender.h @@ -0,0 +1,144 @@ +#pragma once +#include "Interface.h" + +class CViewSetup; +class CBaseEntity; +struct vrect_t; +struct WriteReplayScreenshotParams_t; +class IReplayScreenshotSystem; +class ITexture; +class IMaterial; + +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 +}; + +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 RenderViewInfo_t +{ + RENDERVIEW_UNSPECIFIED = 0, + RENDERVIEW_DRAWVIEWMODEL = (1 << 0), + RENDERVIEW_DRAWHUD = (1 << 1), + RENDERVIEW_SUPPRESSMONITORRENDERING = (1 << 2), +}; + +//----------------------------------------------------------------------------- +// Purpose: View setup and rendering +//----------------------------------------------------------------------------- +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 void* 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& params) = 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 CBaseEntity* GetCurrentlyDrawingEntity() = 0; + virtual void SetCurrentlyDrawingEntity(CBaseEntity* pEnt) = 0; + + virtual bool UpdateShadowDepthTexture(ITexture* pRenderTarget, ITexture* pDepthTexture, const CViewSetup& shadowView) = 0; + + virtual void FreezeFrame(float flFreezeTime) = 0; + + virtual IReplayScreenshotSystem* GetReplayScreenshotSystem() = 0; +}; + +MAKE_INTERFACE_SIGNATURE(IViewRender, ViewRender, "client.dll", "48 8B 0D ? ? ? ? 48 8B 01 FF 90 ? ? ? ? 48 8B 03 48 8D 54 24", 0x0, 1); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/Interface.h b/Amalgam/src/SDK/Definitions/Interfaces/Interface.h new file mode 100644 index 0000000..db4fada --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/Interface.h @@ -0,0 +1,21 @@ +#pragma once +#include "../../../Utils/Interfaces/Interfaces.h" +#include "../../../Utils/Signatures/Signatures.h" + +MAKE_SIGNATURE(AttribHookValue, "client.dll", "4C 8B DC 49 89 5B ? 49 89 6B ? 56 57 41 54 41 56 41 57 48 83 EC ? 48 8B 3D ? ? ? ? 4C 8D 35", 0x0); + +class IBaseInterface +{ +public: + virtual ~IBaseInterface() {} +}; + +typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); + +namespace SDK +{ + inline float AttribHookValue(float value, const char* name, void* econent, void* buffer = 0, bool isGlobalConstString = true) + { + return S::AttribHookValue.As()(value, name, econent, buffer, isGlobalConstString); + } +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h b/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h new file mode 100644 index 0000000..68f4393 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/Prediction.h @@ -0,0 +1,49 @@ +#pragma once +#include "IMoveHelper.h" +#include "../Misc/IPrediction.h" + +class CMoveData; +class CUserCmd; +class CBasePlayer; + +class CPrediction : public IPrediction +{ +public: + virtual ~CPrediction() {}; + virtual void Init() = 0; + virtual void Shutdown() = 0; + virtual void Update(int startframe, bool validframe, int incoming_acknowledged, int outgoing_command) = 0; + virtual void OnReceivedUncompressedPacket() = 0; + virtual void PreEntityPacketReceived(int commands_acknowledged, int current_world_update_packet) = 0; + virtual void PostEntityPacketReceived() = 0; + virtual void PostNetworkDataReceived(int commands_acknowledged) = 0; + virtual bool InPrediction() = 0; + virtual bool IsFirstTimePredicted() = 0; + virtual int GetIncomingPacketNumber() = 0; + virtual void GetViewOrigin(Vec3& org) = 0; + virtual void SetViewOrigin(Vec3& 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; + virtual void RunCommand(CBasePlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper) = 0; + virtual void SetupMove(CBasePlayer* player, CUserCmd* ucmd, IMoveHelper* pHelper, CMoveData* move) = 0; + virtual void FinishMove(CBasePlayer* player, CUserCmd* ucmd, CMoveData* move) = 0; + virtual void SetIdealPitch(CBasePlayer* player, const Vec3& origin, const Vec3& angles, const Vec3& viewheight) = 0; + virtual void _Update(bool received_new_world_update, bool validframe, int incoming_acknowledged, int outgoing_command) = 0; + + CHandle m_hLastGround; + bool m_bInPrediction; + bool m_bFirstTimePredicted; + bool m_bOldCLPredictValue; + bool m_bEnginePaused; + int m_nPreviousStartFrame; + int m_nCommandsPredicted; + int m_nServerCommandsAcknowledged; + int m_bPreviousAckHadErrors; + int m_nIncomingPacketNumber; + float m_flIdealPitch; +}; + + +MAKE_INTERFACE_VERSION(CPrediction, Prediction, "client.dll", "VClientPrediction001"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/SteamInterfaces.h b/Amalgam/src/SDK/Definitions/Interfaces/SteamInterfaces.h new file mode 100644 index 0000000..63aebae --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/SteamInterfaces.h @@ -0,0 +1,11 @@ +#pragma once +#include "Interface.h" +#include "../Steam/Steam_API.h" + +MAKE_INTERFACE_VERSION(ISteamClient, SteamClient, "steamclient64.dll", STEAMCLIENT_INTERFACE_VERSION); +MAKE_INTERFACE_NULL(ISteamFriends, SteamFriends); +MAKE_INTERFACE_NULL(ISteamUtils, SteamUtils); +MAKE_INTERFACE_NULL(ISteamApps, SteamApps); +MAKE_INTERFACE_NULL(ISteamUserStats, SteamUserStats); +MAKE_INTERFACE_NULL(ISteamUser, SteamUser); +MAKE_INTERFACE_NULL(ISteamNetworkingUtils, SteamNetworkingUtils); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/VGuiPanel.h b/Amalgam/src/SDK/Definitions/Interfaces/VGuiPanel.h new file mode 100644 index 0000000..624e231 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/VGuiPanel.h @@ -0,0 +1,25 @@ +#pragma once +#include "Interface.h" +#include "../Types.h" +#include "../../../Utils/Memory/Memory.h" + +class CPanel +{ +public: + const char* GetName(unsigned int vgui_panel) + { + return reinterpret_cast(U::Memory.GetVFunc(this, 36))(this, vgui_panel); + } + + void SetMouseInputEnabled(unsigned int panel, bool state) + { + reinterpret_cast(U::Memory.GetVFunc(this, 32))(this, panel, state); + } + + void SetTopmostPopup(unsigned int panel, bool state) + { + reinterpret_cast(U::Memory.GetVFunc(this, 59))(this, panel, state); + } +}; + +MAKE_INTERFACE_VERSION(CPanel, VGuiPanel, "vgui2.dll", "VGUI_Panel009"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h b/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h new file mode 100644 index 0000000..1c52a87 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h @@ -0,0 +1,920 @@ +#pragma once +#include "../Misc/IAppSystem.h" +#include "../Types.h" + +#define k_flMaxVelocity 2000.0f +#define k_flMaxAngularVelocity 360.0f * 10.0f +#define DEFAULT_MIN_FRICTION_MASS 10.0f +#define DEFAULT_MAX_FRICTION_MASS 2500.0f + +struct vcollide_t; + +enum +{ + COLLIDE_POLY = 0, + COLLIDE_MOPP = 1, + COLLIDE_BALL = 2, + COLLIDE_VIRTUAL = 3, +}; + +class IPhysCollide +{ +public: + virtual ~IPhysCollide() {} + //virtual void AddReference() = 0; + //virtual void ReleaseReference() = 0; + + // get a surface manager + virtual void* CreateSurfaceManager(short&) const = 0; + virtual void GetAllLedges(void* ledges) const = 0; + virtual unsigned int GetSerializationSize() const = 0; + virtual unsigned int SerializeToBuffer(char* pDest, bool bSwap = false) const = 0; + virtual int GetVCollideIndex() const = 0; + virtual Vec3 GetMassCenter() const = 0; + virtual void SetMassCenter(const Vec3& massCenter) = 0; + virtual Vec3 GetOrthographicAreas() const = 0; + virtual void SetOrthographicAreas(const Vec3& areas) = 0; + virtual float GetSphereRadius() const = 0; + virtual void OutputDebugInfo() const = 0; +}; + +#define LEAFMAP_HAS_CUBEMAP 0x0001 +#define LEAFMAP_HAS_SINGLE_VERTEX_SPAN 0x0002 +#define LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS 0x0004 +struct leafmap_t +{ + void* pLeaf; + unsigned short vertCount; + byte flags; + byte spanCount; + unsigned short startVert[8]; + + void SetHasCubemap() + { + flags = LEAFMAP_HAS_CUBEMAP; + } + + void SetSingleVertexSpan(int startVertIndex, int vertCountIn) + { + flags = 0; + flags |= LEAFMAP_HAS_SINGLE_VERTEX_SPAN; + startVert[0] = startVertIndex; + vertCount = vertCountIn; + } + + int MaxSpans() + { + return sizeof(startVert) - sizeof(startVert[0]); + } + const byte* GetSpans() const + { + return reinterpret_cast(&startVert[1]); + } + byte* GetSpans() + { + return reinterpret_cast(&startVert[1]); + } + + void SetRLESpans(int startVertIndex, int spanCountIn, byte* pSpans) + { + flags = 0; + if (spanCountIn > MaxSpans()) + return; + if (spanCountIn == 1) + { + SetSingleVertexSpan(startVertIndex, pSpans[0]); + return; + } + // write out a run length encoded list of verts to include in this model + flags |= LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS; + startVert[0] = startVertIndex; + vertCount = 0; + spanCount = spanCountIn; + byte* pSpanOut = GetSpans(); + for (int i = 0; i < spanCountIn; i++) + { + pSpanOut[i] = pSpans[i]; + if (!(i & 1)) + { + vertCount += pSpans[i]; + } + } + } + + inline bool HasSpans() const { return (flags & (LEAFMAP_HAS_SINGLE_VERTEX_SPAN | LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS)) ? true : false; } + inline bool HasCubemap() const { return (flags & LEAFMAP_HAS_CUBEMAP) ? true : false; } + inline bool HasSingleVertexSpan() const { return (flags & LEAFMAP_HAS_SINGLE_VERTEX_SPAN) ? true : false; } + inline bool HasRLESpans() const { return (flags & LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS) ? true : false; } +}; + + +struct collidemap_t +{ + int leafCount; + leafmap_t leafmap[1]; +}; + +class CPhysCollide : public IPhysCollide +{ +public: + static CPhysCollide* UnserializeFromBuffer(const char* pBuffer, unsigned int size, int index, bool swap = false); + virtual const void* GetCompactSurface() const { return NULL; } + virtual Vec3 GetOrthographicAreas() const { return Vec3(1, 1, 1); } + virtual float GetSphereRadius() const { return 0; } + virtual void ComputeOrthographicAreas(float epsilon) {} + virtual void SetOrthographicAreas(const Vec3& areas) {} + virtual const collidemap_t* GetCollideMap() const { return NULL; } +}; + +// ------------------------------------------------------------------------------------ +// 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 IPhysicsShadowController; +class IPhysicsObject +{ +public: + virtual ~IPhysicsObject(void) {} + virtual bool IsStatic() const = 0; + virtual bool IsAsleep() const = 0; + virtual bool IsTrigger() const = 0; + virtual bool IsFluid() const = 0; + 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; + virtual bool IsAttachedToConstraint(bool bExternalOnly) const = 0; + virtual void EnableCollisions(bool enable) = 0; + virtual void EnableGravity(bool enable) = 0; + virtual void EnableDrag(bool enable) = 0; + virtual void EnableMotion(bool enable) = 0; + virtual void SetGameData(void* pGameData) = 0; + virtual void* GetGameData(void) const = 0; + 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; + virtual void SetCallbackFlags(unsigned short callbackflags) = 0; + virtual unsigned short GetCallbackFlags(void) const = 0; + virtual void Wake(void) = 0; + virtual void Sleep(void) = 0; + virtual void RecheckCollisionFilter() = 0; + virtual void RecheckContactPoints() = 0; + virtual void SetMass(float mass) = 0; + virtual float GetMass(void) const = 0; + virtual float GetInvMass(void) const = 0; + virtual Vec3 GetInertia(void) const = 0; + virtual Vec3 GetInvInertia(void) const = 0; + virtual void SetInertia(const Vec3& inertia) = 0; + virtual void SetDamping(const float* speed, const float* rot) = 0; + virtual void GetDamping(float* speed, float* rot) const = 0; + virtual void SetDragCoefficient(float* pDrag, float* pAngularDrag) = 0; + virtual void SetBuoyancyRatio(float ratio) = 0; + virtual int GetMaterialIndex() const = 0; + virtual void SetMaterialIndex(int materialIndex) = 0; + virtual unsigned int GetContents() const = 0; + virtual void SetContents(unsigned int contents) = 0; + virtual float GetSphereRadius() const = 0; + virtual float GetEnergy() const = 0; + virtual Vec3 GetMassCenterLocalSpace() const = 0; + virtual void SetPosition(const Vec3& worldPosition, const QAngle& angles, bool isTeleport) = 0; + virtual void SetPositionMatrix(const matrix3x4& matrix, bool isTeleport) = 0; + virtual void GetPosition(Vec3* worldPosition, QAngle* angles) const = 0; + virtual void GetPositionMatrix(matrix3x4* positionMatrix) const = 0; + virtual void SetVelocity(const Vec3* velocity, const Vec3* angularVelocity) = 0; + virtual void SetVelocityInstantaneous(const Vec3* velocity, const Vec3* angularVelocity) = 0; + virtual void GetVelocity(Vec3* velocity, Vec3* angularVelocity) const = 0; + virtual void AddVelocity(const Vec3* velocity, const Vec3* angularVelocity) = 0; + virtual void GetVelocityAtPoint(const Vec3& worldPosition, Vec3* pVelocity) const = 0; + virtual void GetImplicitVelocity(Vec3* velocity, Vec3* angularVelocity) const = 0; + virtual void LocalToWorld(Vec3* worldPosition, const Vec3& localPosition) const = 0; + virtual void WorldToLocal(Vec3* localPosition, const Vec3& worldPosition) const = 0; + virtual void LocalToWorldVector(Vec3* worldVector, const Vec3& localVector) const = 0; + virtual void WorldToLocalVector(Vec3* localVector, const Vec3& worldVector) const = 0; + virtual void ApplyForceCenter(const Vec3& forceVector) = 0; + virtual void ApplyForceOffset(const Vec3& forceVector, const Vec3& worldPosition) = 0; + virtual void ApplyTorqueCenter(const Vec3& torque) = 0; + virtual void CalculateForceOffset(const Vec3& forceVector, const Vec3& worldPosition, Vec3* centerForce, Vec3* centerTorque) const = 0; + virtual void CalculateVelocityOffset(const Vec3& forceVector, const Vec3& worldPosition, Vec3* centerVelocity, Vec3* centerAngularVelocity) const = 0; + virtual float CalculateLinearDrag(const Vec3& unitDirection) const = 0; + virtual float CalculateAngularDrag(const Vec3& objectSpaceRotationAxis) const = 0; + virtual bool GetContactPoint(Vec3* contactPoint, IPhysicsObject** contactObject) const = 0; + virtual void SetShadow(float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation) = 0; + virtual void UpdateShadow(const Vec3& targetPosition, const QAngle& targetAngles, bool tempDisableGravity, float timeOffset) = 0; + virtual int GetShadowPosition(Vec3* position, QAngle* angles) const = 0; + virtual /*IPhysicsShadowController*/void* GetShadowController(void) const = 0; + virtual void RemoveShadowController() = 0; + virtual float ComputeShadowControl(/*const hlshadowcontrol_params_t &*/void* params, 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; + virtual void BecomeHinged(int localAxis) = 0; + virtual void RemoveHinged() = 0; + virtual /*IPhysicsFrictionSnapshot*/void* CreateFrictionSnapshot() = 0; + virtual void DestroyFrictionSnapshot(/*IPhysicsFrictionSnapshot*/void* pSnapshot) = 0; + virtual void OutputDebugInfo() const = 0; + + void* m_pGameData; + void* m_pObject; + const CPhysCollide* m_pCollide; + IPhysicsShadowController* m_pShadow; + + Vec3 m_dragBasis; + Vec3 m_angDragBasis; + + // these 5 should pack into a short + // pack new bools here + bool m_shadowTempGravityDisable : 5; + bool m_hasTouchedDynamic : 1; + bool m_asleepSinceCreation : 1; + bool m_forceSilentDelete : 1; + unsigned char m_sleepState : 2; + unsigned char m_hingedAxis : 3; + unsigned char m_collideType : 3; + unsigned short m_gameIndex; + +private: + unsigned short m_materialIndex; + unsigned short m_activeIndex; + + unsigned short m_callbacks; + unsigned short m_gameFlags; + unsigned int m_contentsMask; + + float m_volume; + float m_buoyancyRatio; + float m_dragCoefficient; + float m_angDragCoefficient; +}; +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 fluidparams_t; +struct springparams_t; +struct objectparams_t +{ + Vec3* 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 debugcollide_t; +class CGameTrace; +typedef CGameTrace trace_t; +struct physics_stats_t; +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; + } +}; +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" + +class IVPhysicsDebugOverlay +{ +public: + virtual void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, const char* format, ...) = 0; + virtual void AddBoxOverlay(const Vec3& origin, const Vec3& mins, const Vec3& max, QAngle const& orientation, int r, int g, int b, int a, float duration) = 0; + virtual void AddTriangleOverlay(const Vec3& p1, const Vec3& p2, const Vec3& p3, int r, int g, int b, int a, bool noDepthTest, float duration) = 0; + virtual void AddLineOverlay(const Vec3& origin, const Vec3& dest, int r, int g, int b, bool noDepthTest, float duration) = 0; + virtual void AddTextOverlay(const Vec3& origin, float duration, const char* format, ...) = 0; + virtual void AddTextOverlay(const Vec3& origin, int line_offset, float duration, 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 Vec3& start, const Vec3& end, const Vec3& mins, const Vec3& max, const QAngle& angles, int r, int g, int b, int a, float flDuration) = 0; + virtual void AddTextOverlayRGB(const Vec3& origin, int line_offset, float duration, float r, float g, float b, float alpha, const char* format, ...) = 0; +}; + +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 +{ + Vec3 origin; + Vec3 normal; + float h; // height of the cone (hl units) + float theta; // cone angle (degrees) +}; + + +#define VPHYSICS_COLLISION_INTERFACE_VERSION "VPhysicsCollision007" + +class IPhysicsCollision +{ +public: + virtual ~IPhysicsCollision(void) {} + + // produce a convex element from verts (convex hull around verts) + virtual CPhysConvex* ConvexFromVerts(Vec3** 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 Vec3& mins, const Vec3& 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 Vec3& vPolyNormal, const Vec3* 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 Vec3& a, const Vec3& b, const Vec3& 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 Vec3 CollideGetExtent(const CPhysCollide* pCollide, const Vec3& collideOrigin, const QAngle& collideAngles, const Vec3& direction) = 0; + + // Get an AABB for an oriented collision model + virtual void CollideGetAABB(Vec3* pMins, Vec3* pMaxs, const CPhysCollide* pCollide, const Vec3& collideOrigin, const QAngle& collideAngles) = 0; + + virtual void CollideGetMassCenter(CPhysCollide* pCollide, Vec3* pOutMassCenter) = 0; + virtual void CollideSetMassCenter(CPhysCollide* pCollide, const Vec3& 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 Vec3 CollideGetOrthographicAreas(const CPhysCollide* pCollide) = 0; + virtual void CollideSetOrthographicAreas(CPhysCollide* pCollide, const Vec3& 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 Vec3& mins, const Vec3& maxs) = 0; + virtual int GetConvexesUsedInCollideable(const CPhysCollide* pCollideable, CPhysConvex** pOutputArray, int iOutputArrayLimit) = 0; + + + // Trace an AABB against a collide + virtual void TraceBox(const Vec3& start, const Vec3& end, const Vec3& mins, const Vec3& maxs, const CPhysCollide* pCollide, const Vec3& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + virtual void TraceBox(const Ray_t& ray, const CPhysCollide* pCollide, const Vec3& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + virtual void TraceBox(const Ray_t& ray, unsigned int contentsMask, IConvexInfo* pConvexInfo, const CPhysCollide* pCollide, const Vec3& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + + // Trace one collide against another + virtual void TraceCollide(const Vec3& start, const Vec3& end, const CPhysCollide* pSweepCollide, const QAngle& sweepAngles, const CPhysCollide* pCollide, const Vec3& collideOrigin, const QAngle& collideAngles, trace_t* ptr) = 0; + + // relatively slow test for box vs. truncated cone + virtual bool IsBoxIntersectingCone(const Vec3& boxAbsMins, const Vec3& 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, Vec3** outVerts) = 0; + // destroy the list of verts created by CreateDebugMesh + virtual void DestroyDebugMesh(int vertCount, Vec3* 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& params) = 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; +}; + +MAKE_INTERFACE_VERSION(IPhysicsCollision, PhysicsCollision, "vphysics.dll", "VPhysicsCollision007"); + +// this can be used to post-process a collision model +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, Vec3* verts) = 0; + + // UNDONE: This doesn't work!!! + virtual void SetTriangleVerts(int convexIndex, int triangleIndex, const Vec3* 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. +//----------------------------------------------------------------------------- +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 Vec3& vecPoint) = 0; +}; + +// The caller should implement this to return contents masks per convex on a collide +class IConvexInfo +{ +public: + virtual unsigned int GetContents(int convexGameData) = 0; +}; + +class CPhysicsEventHandler; +class IPhysicsCollisionData +{ +public: + virtual void GetSurfaceNormal(Vec3& out) = 0; // normal points toward second object (object index 1) + virtual void GetContactPoint(Vec3& out) = 0; // contact point of collision (in world space) + virtual void GetContactSpeed(Vec3& 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 +}; + +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) {} +}; + + +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 +{ + Vec3 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. + +class IPhysicsShadowController +{ +public: + virtual ~IPhysicsShadowController(void) {} + + virtual void Update(const Vec3& 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(Vec3* 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(Vec3* 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, Vec3& linear, Vec3& angular) = 0; +}; + +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() +// ------------------- +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, +}; + +class IPhysicsTraceFilter +{ +public: + virtual bool ShouldHitObject(IPhysicsObject* pObject, int contentsMask) = 0; + virtual PhysicsTraceType_t GetTraceType() const = 0; +}; + +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 Vec3& gravityVector) = 0; + virtual void GetGravity(Vec3* 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 Vec3& 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 Vec3& position, const QAngle& angles, objectparams_t* pParams) = 0; + // Create a perfectly spherical object + virtual IPhysicsObject* CreateSphereObject(float radius, int materialIndex, const Vec3& 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& params, 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& params) = 0; + virtual void PreRestore(const physprerestoreparams_t& params) = 0; + virtual bool Restore(const physrestoreparams_t& params) = 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 Vec3& vecAbsStart, const Vec3& 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; +}; + +MAKE_INTERFACE_VERSION(IPhysics, Physics, "vphysics.dll", "VPhysics031"); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Interfaces/ViewRenderBeams.h b/Amalgam/src/SDK/Definitions/Interfaces/ViewRenderBeams.h new file mode 100644 index 0000000..72c5177 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Interfaces/ViewRenderBeams.h @@ -0,0 +1,186 @@ +#pragma once +#include "Interface.h" +#include "../Types.h" + +class CBaseEntity; +class CTraceFilter; + +struct BeamTrail_t +{ + BeamTrail_t* next; + float die; + Vector org; + Vector vel; +}; + +struct Beam_t +{ + unsigned char CDefaultClientRenderable[8]; + unsigned __int16 m_hRenderHandle; + Vector m_Mins; + Vector m_Maxs; + int* m_queryHandleHalo; + float m_haloProxySize; + Beam_t* next; + int type; + int flags; + int numAttachments; + Vector attachment[10]; + Vector delta; + float t; + float freq; + float die; + float width; + float endWidth; + float fadeLength; + float amplitude; + float life; + float r; + float g; + float b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + unsigned int entity[10]; + int attachmentIndex[10]; + int modelIndex; + int haloIndex; + float haloScale; + int frameCount; + float rgbNoise[129]; + BeamTrail_t* trail; + float start_radius; + float end_radius; + bool m_bCalculatedNoise; + float m_flHDRColorScale; +}; + +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! +}; + +struct BeamInfo_t +{ + int m_nType; + CBaseEntity* m_pStartEnt; + int m_nStartAttachment; + CBaseEntity* m_pEndEnt; + int m_nEndAttachment; + 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; + Vector m_vecCenter; + float m_flStartRadius; + float m_flEndRadius; + + BeamInfo_t() + { + m_nType = 0; + m_nSegments = -1; + m_pszModelName = NULL; + m_pszHaloName = NULL; + m_nModelIndex = -1; + m_nHaloIndex = -1; + m_bRenderable = true; + m_nFlags = 0; + } +}; + +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(CBaseEntity* pbeam, CTraceFilter* 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; +}; + +MAKE_INTERFACE_SIGNATURE(IViewRenderBeams, ViewRenderBeams, "client.dll", "48 8B 0D ? ? ? ? 48 8B D3 48 8B 01 FF 50 ? 0F B7 93", 0x0, 1); \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseAnimating.h b/Amalgam/src/SDK/Definitions/Main/CBaseAnimating.h new file mode 100644 index 0000000..ba91278 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseAnimating.h @@ -0,0 +1,148 @@ +#pragma once +#include "CBaseEntity.h" +#include "../Misc/Studio.h" +#include "../../../Utils/Math/Math.h" + +MAKE_SIGNATURE(CBaseAnimating_FrameAdvance, "client.dll", "48 89 5C 24 ? 48 89 6C 24 ? 57 48 81 EC ? ? ? ? 44 0F 29 54 24", 0x0); +MAKE_SIGNATURE(CBaseAnimating_GetBonePosition, "client.dll", "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 8B DA 49 8B F1", 0x0); + +class CBaseAnimating : public CBaseEntity +{ +public: + NETVAR(m_nSequence, int, "CBaseAnimating", "m_nSequence"); + NETVAR(m_nForceBone, int, "CBaseAnimating", "m_nForceBone"); + NETVAR(m_vecForce, Vec3, "CBaseAnimating", "m_vecForce"); + NETVAR(m_nSkin, int, "CBaseAnimating", "m_nSkin"); + NETVAR(m_nBody, int, "CBaseAnimating", "m_nBody"); + NETVAR(m_nHitboxSet, int, "CBaseAnimating", "m_nHitboxSet"); + NETVAR(m_flModelScale, float, "CBaseAnimating", "m_flModelScale"); + NETVAR(m_flModelWidthScale, float, "CBaseAnimating", "m_flModelWidthScale"); + NETVAR(m_flPlaybackRate, float, "CBaseAnimating", "m_flPlaybackRate"); + NETVAR(m_flEncodedController, void*, "CBaseAnimating", "m_flEncodedController"); + NETVAR(m_bClientSideAnimation, bool, "CBaseAnimating", "m_bClientSideAnimation"); + NETVAR(m_bClientSideFrameReset, bool, "CBaseAnimating", "m_bClientSideFrameReset"); + NETVAR(m_nNewSequenceParity, int, "CBaseAnimating", "m_nNewSequenceParity"); + NETVAR(m_nResetEventsParity, int, "CBaseAnimating", "m_nResetEventsParity"); + NETVAR(m_nMuzzleFlashParity, int, "CBaseAnimating", "m_nMuzzleFlashParity"); + NETVAR(m_hLightingOrigin, EHANDLE, "CBaseAnimating", "m_hLightingOrigin"); + NETVAR(m_hLightingOriginRelative, EHANDLE, "CBaseAnimating", "m_hLightingOriginRelative"); + NETVAR(m_flCycle, float, "CBaseAnimating", "m_flCycle"); + NETVAR(m_fadeMinDist, float, "CBaseAnimating", "m_fadeMinDist"); + NETVAR(m_fadeMaxDist, float, "CBaseAnimating", "m_fadeMaxDist"); + NETVAR(m_flFadeScale, float, "CBaseAnimating", "m_flFadeScale"); + + NETVAR_OFF(GetModelPtr, CStudioHdr*, "CBaseAnimating", "m_nMuzzleFlashParity", 12); + + int GetHitboxGroup(int nHitbox) + { + auto pModel = GetModel(); + if (!pModel) return -1; + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) return -1; + auto pSet = pHDR->pHitboxSet(m_nHitboxSet()); + if (!pSet) return -1; + auto pBox = pSet->pHitbox(nHitbox); + if (!pBox) return -1; + + return pBox->group; + } + + int GetNumOfHitboxes() + { + auto pModel = GetModel(); + if (!pModel) return 0; + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) return 0; + auto pSet = pHDR->pHitboxSet(m_nHitboxSet()); + if (!pSet) return 0; + + return pSet->numhitboxes; + } + + Vec3 GetHitboxPos(int nHitbox, Vec3 vOffset = {}) + { + auto pModel = GetModel(); + if (!pModel) return {}; + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) return {}; + auto pSet = pHDR->pHitboxSet(m_nHitboxSet()); + if (!pSet) return {}; + auto pBox = pSet->pHitbox(nHitbox); + if (!pBox) return {}; + + matrix3x4 BoneMatrix[128] = {}; + if (!SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, I::GlobalVars->curtime)) + return {}; + + Vec3 vOut = {}; + Math::VectorTransform(vOffset, BoneMatrix[pBox->bone], vOut); + return vOut; + } + + void GetHitboxInfo(int nHitbox, Vec3* pCenter = nullptr, Vec3* pMins = nullptr, Vec3* pMaxs = nullptr, matrix3x4* pMatrix = nullptr, Vec3 vOffset = {}) + { + auto pModel = GetModel(); + if (!pModel) return; + auto pHDR = I::ModelInfoClient->GetStudiomodel(pModel); + if (!pHDR) return; + auto pSet = pHDR->pHitboxSet(m_nHitboxSet()); + if (!pSet) return; + auto pBox = pSet->pHitbox(nHitbox); + if (!pBox) return; + + matrix3x4 BoneMatrix[128] = {}; + if (!SetupBones(BoneMatrix, 128, BONE_USED_BY_ANYTHING, I::GlobalVars->curtime)) + return; + + if (pMins) + *pMins = pBox->bbmin; + + if (pMaxs) + *pMaxs = pBox->bbmax; + + if (pCenter) + Math::VectorTransform(vOffset, BoneMatrix[pBox->bone], *pCenter); + + if (pMatrix) + memcpy(*pMatrix, BoneMatrix[pBox->bone], sizeof(matrix3x4)); + } + + std::array& m_flPoseParameter() + { + static int nOffset = U::NetVars.GetNetVar("CBaseAnimating", "m_flPoseParameter"); + return *reinterpret_cast*>(std::uintptr_t(this) + nOffset); + } + + CUtlVector* GetCachedBoneData() + { + static int nOffset = U::NetVars.GetNetVar("CBaseAnimating", "m_hLightingOrigin") - 88; + return reinterpret_cast*>(std::uintptr_t(this) + nOffset); + } + + float FrameAdvance(float flInterval) + { + return S::CBaseAnimating_FrameAdvance.As()(this, flInterval); + } + + void GetBonePosition(int iBone, Vector& origin, QAngle& angles) + { + S::CBaseAnimating_GetBonePosition.As()(this, iBone, origin, angles); + } + + __inline bool GetAttachment(int number, Vec3& origin) + { + return reinterpret_cast(U::Memory.GetVFunc(this, 71))(this, number, origin); + } +}; + +class CBaseAnimatingOverlay : public CBaseAnimating +{ +public: + +}; + +class CCurrencyPack : public CBaseAnimating +{ +public: + NETVAR(m_bDistributed, bool, "CCurrencyPack", "m_bDistributed"); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseCombatCharacter.h b/Amalgam/src/SDK/Definitions/Main/CBaseCombatCharacter.h new file mode 100644 index 0000000..a7f95af --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseCombatCharacter.h @@ -0,0 +1,17 @@ +#pragma once +#include "CBaseFlex.h" + +class CBaseCombatCharacter : public CBaseFlex +{ +public: + NETVAR(m_flNextAttack, float, "CBaseCombatCharacter", "m_flNextAttack"); + NETVAR(m_hActiveWeapon, EHANDLE, "CBaseCombatCharacter", "m_hActiveWeapon"); + NETVAR(m_hMyWeapons, EHANDLE, "CBaseCombatCharacter", "m_hMyWeapons"); + NETVAR(m_bGlowEnabled, bool, "CBaseCombatCharacter", "m_bGlowEnabled"); + + __inline size_t* GetMyWeapons() + { + static int nOffset = U::NetVars.GetNetVar("CBaseCombatCharacter", "m_hMyWeapons"); + return reinterpret_cast(std::uintptr_t(this) + nOffset); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseCombatWeapon.h b/Amalgam/src/SDK/Definitions/Main/CBaseCombatWeapon.h new file mode 100644 index 0000000..11e83e4 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseCombatWeapon.h @@ -0,0 +1,29 @@ +#pragma once +#include "CBaseProjectile.h" +#include "../../../Utils/Signatures/Signatures.h" + +MAKE_SIGNATURE(CBaseCombatWeapon_HasAmmo, "client.dll", "40 53 48 83 EC ? 83 B9 ? ? ? ? ? 48 8B D9 75 ? 83 B9 ? ? ? ? ? 74 ? 48 8B 01", 0x0); + +class CBaseCombatWeapon : public CBaseAnimating +{ +public: + NETVAR(m_iClip1, int, "CBaseCombatWeapon", "m_iClip1"); + NETVAR(m_iClip2, int, "CBaseCombatWeapon", "m_iClip2"); + NETVAR(m_iPrimaryAmmoType, int, "CBaseCombatWeapon", "m_iPrimaryAmmoType"); + NETVAR(m_iSecondaryAmmoType, int, "CBaseCombatWeapon", "m_iSecondaryAmmoType"); + NETVAR(m_nViewModelIndex, int, "CBaseCombatWeapon", "m_nViewModelIndex"); + NETVAR(m_bFlipViewModel, bool, "CBaseCombatWeapon", "m_bFlipViewModel"); + NETVAR(m_flNextPrimaryAttack, float, "CBaseCombatWeapon", "m_flNextPrimaryAttack"); + NETVAR(m_flNextSecondaryAttack, float, "CBaseCombatWeapon", "m_flNextSecondaryAttack"); + NETVAR(m_nNextThinkTick, int, "CBaseCombatWeapon", "m_nNextThinkTick"); + NETVAR(m_flTimeWeaponIdle, float, "CBaseCombatWeapon", "m_flTimeWeaponIdle"); + NETVAR(m_iViewModelIndex, int, "CBaseCombatWeapon", "m_iViewModelIndex"); + NETVAR(m_iWorldModelIndex, int, "CBaseCombatWeapon", "m_iWorldModelIndex"); + NETVAR(m_iState, int, "CBaseCombatWeapon", "m_iState"); + NETVAR(m_hOwner, EHANDLE, "CBaseCombatWeapon", "m_hOwner"); + + bool HasAmmo() + { + return S::CBaseCombatWeapon_HasAmmo.As()(this); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h b/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h new file mode 100644 index 0000000..7cfea52 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseEntity.h @@ -0,0 +1,195 @@ +#pragma once +#include "CBaseHandle.h" +#include "IClientEntity.h" +#include "CCollisionProperty.h" +#include "../Main/UtlVector.h" +#include "../Definitions.h" +#include "../../../Utils/NetVars/NetVars.h" +#include "../../../Utils/Signatures/Signatures.h" +#include "../../../Utils/Memory/Memory.h" + +MAKE_SIGNATURE(CBaseEntity_SetAbsOrigin, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B FA 48 8B D9 E8 ? ? ? ? F3 0F 10 83", 0x0); +MAKE_SIGNATURE(CBaseEntity_SetAbsAngles, "client.dll", "48 89 5C 24 ? 57 48 81 EC ? ? ? ? 48 8B FA 48 8B D9 E8 ? ? ? ? F3 0F 10 83", 0x0); +MAKE_SIGNATURE(CBaseEntity_SetAbsVelocity, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? F3 0F 10 81 ? ? ? ? 48 8B DA 0F 2E 02", 0x0); +MAKE_SIGNATURE(CBaseEntity_EstimateAbsVelocity, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B FA 48 8B D9 E8 ? ? ? ? 48 3B D8", 0x0); +MAKE_SIGNATURE(CBaseEntity_CreateShadow, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B 41 ? 48 8B F9 48 83 C1 ? FF 90", 0x0); +MAKE_SIGNATURE(CBaseEntity_InvalidateBoneCache, "client.dll", "8B 05 ? ? ? ? FF C8 C7 81", 0x0); + +enum CollideType_t +{ + ENTITY_SHOULD_NOT_COLLIDE = 0, + ENTITY_SHOULD_COLLIDE, + ENTITY_SHOULD_RESPOND +}; + +typedef CHandle EHANDLE; + +#define MULTIPLAYER_BACKUP 90 + +class IInterpolatedVar; + +class VarMapEntry_t +{ +public: + unsigned short type; + unsigned short m_bNeedsToInterpolate; + void* data; + IInterpolatedVar* watcher; +}; + +struct VarMapping_t +{ + CUtlVector m_Entries; + int m_nInterpolatedEntries; + float m_lastInterpolationTime; +}; + +class CBaseEntity : public IClientEntity +{ +public: + NETVAR(m_flAnimTime, float, "CBaseEntity", "m_flAnimTime"); + NETVAR(m_flSimulationTime, float, "CBaseEntity", "m_flSimulationTime"); + NETVAR(m_ubInterpolationFrame, int, "CBaseEntity", "m_ubInterpolationFrame"); + NETVAR(m_vecOrigin, Vec3, "CBaseEntity", "m_vecOrigin"); + NETVAR(m_angRotation, Vec3, "CBaseEntity", "m_angRotation"); + NETVAR(m_nModelIndex, int, "CBaseEntity", "m_nModelIndex"); + NETVAR(m_fEffects, int, "CBaseEntity", "m_fEffects"); + NETVAR(m_nRenderMode, int, "CBaseEntity", "m_nRenderMode"); + NETVAR(m_nRenderFX, int, "CBaseEntity", "m_nRenderFX"); + NETVAR(m_clrRender, Color_t, "CBaseEntity", "m_clrRender"); + NETVAR(m_iTeamNum, int, "CBaseEntity", "m_iTeamNum"); + NETVAR(m_CollisionGroup, int, "CBaseEntity", "m_CollisionGroup"); + NETVAR(m_flElasticity, float, "CBaseEntity", "m_flElasticity"); + NETVAR(m_flShadowCastDistance, float, "CBaseEntity", "m_flShadowCastDistance"); + NETVAR(m_hOwnerEntity, EHANDLE, "CBaseEntity", "m_hOwnerEntity"); + NETVAR(m_hEffectEntity, EHANDLE, "CBaseEntity", "m_hEffectEntity"); + NETVAR(moveparent, int, "CBaseEntity", "moveparent"); + NETVAR(m_iParentAttachment, int, "CBaseEntity", "m_iParentAttachment"); + NETVAR(m_Collision, CCollisionProperty*, "CBaseEntity", "m_Collision"); + NETVAR(m_vecMinsPreScaled, Vec3, "CBaseEntity", "m_vecMinsPreScaled"); + NETVAR(m_vecMaxsPreScaled, Vec3, "CBaseEntity", "m_vecMaxsPreScaled"); + NETVAR(m_vecMins, Vec3, "CBaseEntity", "m_vecMins"); + NETVAR(m_vecMaxs, Vec3, "CBaseEntity", "m_vecMaxs"); + NETVAR(m_nSolidType, int, "CBaseEntity", "m_nSolidType"); + NETVAR(m_usSolidFlags, int, "CBaseEntity", "m_usSolidFlags"); + NETVAR(m_nSurroundType, int, "CBaseEntity", "m_nSurroundType"); + NETVAR(m_triggerBloat, int, "CBaseEntity", "m_triggerBloat"); + NETVAR(m_bUniformTriggerBloat, bool, "CBaseEntity", "m_bUniformTriggerBloat"); + NETVAR(m_vecSpecifiedSurroundingMinsPreScaled, Vec3, "CBaseEntity", "m_vecSpecifiedSurroundingMinsPreScaled"); + NETVAR(m_vecSpecifiedSurroundingMaxsPreScaled, Vec3, "CBaseEntity", "m_vecSpecifiedSurroundingMaxsPreScaled"); + NETVAR(m_vecSpecifiedSurroundingMins, Vec3, "CBaseEntity", "m_vecSpecifiedSurroundingMins"); + NETVAR(m_vecSpecifiedSurroundingMaxs, Vec3, "CBaseEntity", "m_vecSpecifiedSurroundingMaxs"); + NETVAR(m_iTextureFrameIndex, int, "CBaseEntity", "m_iTextureFrameIndex"); + NETVAR(m_PredictableID, int, "CBaseEntity", "m_PredictableID"); + NETVAR(m_bIsPlayerSimulated, bool, "CBaseEntity", "m_bIsPlayerSimulated"); + NETVAR(m_bSimulatedEveryTick, bool, "CBaseEntity", "m_bSimulatedEveryTick"); + NETVAR(m_bAnimatedEveryTick, bool, "CBaseEntity", "m_bAnimatedEveryTick"); + NETVAR(m_bAlternateSorting, bool, "CBaseEntity", "m_bAlternateSorting"); + NETVAR(m_nModelIndexOverrides, void*, "CBaseEntity", "m_nModelIndexOverrides"); + NETVAR(movetype, int, "CBaseEntity", "movetype"); + + NETVAR_OFF(m_flOldSimulationTime, float, "CBaseEntity", "m_flSimulationTime", 4); + + VIRTUAL(UpdateVisibility, void, void(__thiscall*)(CBaseEntity*), this, 91); + + Vec3 GetCenter() + { + return m_vecOrigin() + Vec3(0, 0, (m_vecMins().z + m_vecMaxs().z) / 2); + } + + Vec3 GetRenderCenter() + { + Vec3 vMin = {}, vMax = {}; + GetRenderBounds(vMin, vMax); + return GetRenderOrigin() + Vec3(0.f, 0.f, (vMin.z + vMax.z) / 2); + } + + bool IsInValidTeam(int* pTeamNumOut = nullptr) + { + int nTeamNum = m_iTeamNum(); + + switch (nTeamNum) + { + case TF_TEAM_RED: + case TF_TEAM_BLUE: + { + if (pTeamNumOut) + *pTeamNumOut = nTeamNum; + + return true; + } + + default: return false; + } + } + + CBaseEntity* GetMoveParent() + { + static int nOffset = U::NetVars.GetNetVar("CBaseEntity", "moveparent") - 8; + auto m_pMoveParent = reinterpret_cast(std::uintptr_t(this) + nOffset); + + if (!m_pMoveParent) + return nullptr; + + return m_pMoveParent->Get(); + } + + CBaseEntity* NextMovePeer() + { + static int nOffset = U::NetVars.GetNetVar("CBaseEntity", "moveparent") - 16; + auto m_pMovePeer = reinterpret_cast(std::uintptr_t(this) + nOffset); + + if (!m_pMovePeer) + return nullptr; + + return m_pMovePeer->Get(); + } + + CBaseEntity* FirstMoveChild() + { + static int nOffset = U::NetVars.GetNetVar("CBaseEntity", "moveparent") - 24; + auto m_pMoveChild = reinterpret_cast(std::uintptr_t(this) + nOffset); + + if (!m_pMoveChild) + return nullptr; + + return m_pMoveChild->Get(); + } + + void SetAbsOrigin(const Vec3& absOrigin) + { + S::CBaseEntity_SetAbsOrigin.As()(this, absOrigin); + } + + void SetAbsAngles(const Vec3& absAngles) + { + S::CBaseEntity_SetAbsAngles.As()(this, absAngles); + } + + void SetAbsVelocity(const Vec3& vecAbsVelocity) + { + S::CBaseEntity_SetAbsVelocity.As()(this, vecAbsVelocity); + } + + void EstimateAbsVelocity(Vec3& vel) + { + S::CBaseEntity_EstimateAbsVelocity.As()(this, vel); + } + + Vec3 GetAbsVelocity() + { + Vec3 vOut; + EstimateAbsVelocity(vOut); + return vOut; + } + + void CreateShadow() + { + S::CBaseEntity_CreateShadow.As()(this); + } + + void InvalidateBoneCache() + { + S::CBaseEntity_InvalidateBoneCache.As()(this); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseFlex.h b/Amalgam/src/SDK/Definitions/Main/CBaseFlex.h new file mode 100644 index 0000000..9ec8832 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseFlex.h @@ -0,0 +1,16 @@ +#pragma once +#include "CBaseAnimating.h" + +class IHasLocalToGlobalFlexSettings +{ +public: + virtual void EnsureTranslations(const /*flexsettinghdr_t*/ void* pSettinghdr) = 0; +}; + +class CBaseFlex : public CBaseAnimatingOverlay, public IHasLocalToGlobalFlexSettings +{ +public: + NETVAR(m_flexWeight, void*, "CBaseFlex", "m_flexWeight"); + NETVAR(m_blinktoggle, int, "CBaseFlex", "m_blinktoggle"); + NETVAR(m_viewtarget, Vec3, "CBaseFlex", "m_viewtarget"); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseHandle.h b/Amalgam/src/SDK/Definitions/Main/CBaseHandle.h new file mode 100644 index 0000000..bd73a78 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseHandle.h @@ -0,0 +1,244 @@ +#pragma once +#include "../Definitions.h" + +class IHandleEntity; + +class CBaseHandle +{ +public: + CBaseHandle(); + CBaseHandle(const CBaseHandle& other); + CBaseHandle(unsigned long value); + CBaseHandle(int iEntry, int iSerialNumber); + void Init(int iEntry, int iSerialNumber); + void Term(); + 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; + const CBaseHandle& operator=(const IHandleEntity* pEntity); + const CBaseHandle& Set(const IHandleEntity* pEntity); + IHandleEntity* Get() const; + +protected: + 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) +{ + 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; +} + +template +class CHandle : public CBaseHandle +{ +public: + CHandle(); + CHandle(int iEntry, int iSerialNumber); + CHandle(const CBaseHandle& handle); + CHandle(T* pVal); + + 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; +}; + +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 +CHandle CHandle::FromIndex(int index) +{ + CHandle ret; + ret.m_Index = index; + return ret; +} + +template +T* CHandle::Get() const +{ + return reinterpret_cast(CBaseHandle::Get()); +} + +template +CHandle::operator T* () +{ + return Get(); +} + +template +CHandle::operator T* () const +{ + return Get(); +} + +template +bool CHandle::operator !() const +{ + return !Get(); +} + +template +bool CHandle::operator==(T* val) const +{ + return Get() == val; +} + +template +bool CHandle::operator!=(T* val) const +{ + return Get() != val; +} + +template +void CHandle::Set(const T* pVal) +{ + CBaseHandle::Set(reinterpret_cast(pVal)); +} + +template +const CBaseHandle& CHandle::operator=(const T* val) +{ + Set(val); + return *this; +} + +template +T* CHandle::operator ->() const +{ + return Get(); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseObject.h b/Amalgam/src/SDK/Definitions/Main/CBaseObject.h new file mode 100644 index 0000000..a3e6d01 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseObject.h @@ -0,0 +1,110 @@ +#pragma once +#include "CBaseCombatCharacter.h" + +class CBaseObject : public CBaseCombatCharacter +{ +public: + NETVAR(m_iHealth, int, "CBaseObject", "m_iHealth"); + NETVAR(m_iMaxHealth, int, "CBaseObject", "m_iMaxHealth"); + NETVAR(m_bHasSapper, bool, "CBaseObject", "m_bHasSapper"); + NETVAR(m_iObjectType, int, "CBaseObject", "m_iObjectType"); + NETVAR(m_bBuilding, bool, "CBaseObject", "m_bBuilding"); + NETVAR(m_bPlacing, bool, "CBaseObject", "m_bPlacing"); + NETVAR(m_bCarried, bool, "CBaseObject", "m_bCarried"); + NETVAR(m_bCarryDeploy, bool, "CBaseObject", "m_bCarryDeploy"); + NETVAR(m_bMiniBuilding, bool, "CBaseObject", "m_bMiniBuilding"); + NETVAR(m_flPercentageConstructed, float, "CBaseObject", "m_flPercentageConstructed"); + NETVAR(m_fObjectFlags, int, "CBaseObject", "m_fObjectFlags"); + NETVAR(m_hBuiltOnEntity, EHANDLE, "CBaseObject", "m_hBuiltOnEntity"); + NETVAR(m_bDisabled, bool, "CBaseObject", "m_bDisabled"); + NETVAR(m_hBuilder, EHANDLE, "CBaseObject", "m_hBuilder"); + NETVAR(m_vecBuildMaxs, Vec3, "CBaseObject", "m_vecBuildMaxs"); + NETVAR(m_vecBuildMins, Vec3, "CBaseObject", "m_vecBuildMins"); + NETVAR(m_iDesiredBuildRotations, int, "CBaseObject", "m_iDesiredBuildRotations"); + NETVAR(m_bServerOverridePlacement, bool, "CBaseObject", "m_bServerOverridePlacement"); + NETVAR(m_iUpgradeLevel, int, "CBaseObject", "m_iUpgradeLevel"); + NETVAR(m_iUpgradeMetal, int, "CBaseObject", "m_iUpgradeMetal"); + NETVAR(m_iUpgradeMetalRequired, int, "CBaseObject", "m_iUpgradeMetalRequired"); + NETVAR(m_iHighestUpgradeLevel, int, "CBaseObject", "m_iHighestUpgradeLevel"); + NETVAR(m_iObjectMode, int, "CBaseObject", "m_iObjectMode"); + NETVAR(m_bDisposableBuilding, bool, "CBaseObject", "m_bDisposableBuilding"); + NETVAR(m_bWasMapPlaced, bool, "CBaseObject", "m_bWasMapPlaced"); + NETVAR(m_bPlasmaDisable, bool, "CBaseObject", "m_bPlasmaDisable"); + + VIRTUAL(GetNumBuildPoints, int, int(__fastcall*)(void*), IHasBuildPoints(), 0); + + void* IHasBuildPoints() + { + static int nOffset = U::NetVars.GetNetVar("CBaseObject", "m_iUpgradeLevel") - 340; + return reinterpret_cast(std::uintptr_t(this) + nOffset); + }; + + bool GetBuildPoint(int iPoint, Vec3& vecOrigin, Vec3& vecAngles) + { + void* pPoints = IHasBuildPoints(); + return reinterpret_cast(U::Memory.GetVFunc(pPoints, 1))(pPoints, iPoint, vecOrigin, vecAngles); + } + + __inline int GetBuildPointAttachmentIndex(int iPoint) + { + void* pPoints = IHasBuildPoints(); + return reinterpret_cast(U::Memory.GetVFunc(pPoints, 2))(pPoints, iPoint); + } + + bool IsDisabled() + { + return m_bDisabled() || m_bHasSapper(); + } +}; + +class CObjectSentrygun : public CBaseObject +{ +public: + NETVAR(m_iAmmoShells, int, "CObjectSentrygun", "m_iAmmoShells"); + NETVAR(m_iAmmoRockets, int, "CObjectSentrygun", "m_iAmmoRockets"); + NETVAR(m_iState, int, "CObjectSentrygun", "m_iState"); + NETVAR(m_bPlayerControlled, bool, "CObjectSentrygun", "m_bPlayerControlled"); + NETVAR(m_nShieldLevel, int, "CObjectSentrygun", "m_nShieldLevel"); + NETVAR(m_bShielded, bool, "CObjectSentrygun", "m_bShielded"); + NETVAR(m_hEnemy, EHANDLE, "CObjectSentrygun", "m_hEnemy"); + NETVAR(m_hAutoAimTarget, EHANDLE, "CObjectSentrygun", "m_hAutoAimTarget"); + NETVAR(m_iKills, int, "CObjectSentrygun", "m_iKills"); + NETVAR(m_iAssists, int, "CObjectSentrygun", "m_iAssists"); + + __inline int MaxAmmoShells() + { + if (m_iUpgradeLevel() == 1 || m_bMiniBuilding()) + return 150; + else + return 200; + } + + __inline void GetAmmoCount(int& iShells, int& iMaxShells, int& iRockets, int& iMaxRockets) + { + const bool bIsMini = m_bMiniBuilding(); + + iShells = m_iAmmoShells(); + iMaxShells = MaxAmmoShells(); + iRockets = bIsMini ? 0 : m_iAmmoRockets(); + iMaxRockets = (bIsMini || m_iUpgradeLevel() < 3) ? 0 : 20; + } +}; + +class CObjectDispenser : public CBaseObject +{ +public: + NETVAR(m_iState, int, "CObjectDispenser", "m_iState"); + NETVAR(m_iAmmoMetal, int, "CObjectDispenser", "m_iAmmoMetal"); + NETVAR(m_iMiniBombCounter, int, "CObjectDispenser", "m_iMiniBombCounter"); +}; + +class CObjectTeleporter : public CBaseObject +{ +public: + NETVAR(m_iState, int, "CObjectTeleporter", "m_iState"); + NETVAR(m_flRechargeTime, float, "CObjectTeleporter", "m_flRechargeTime"); + NETVAR(m_flCurrentRechargeDuration, float, "CObjectTeleporter", "m_flCurrentRechargeDuration"); + NETVAR(m_iTimesUsed, int, "CObjectTeleporter", "m_iTimesUsed"); + NETVAR(m_flYawToExit, float, "CObjectTeleporter", "m_flYawToExit"); + NETVAR(m_bMatchBuilding, bool, "CObjectTeleporter", "m_bMatchBuilding"); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBasePlayer.h b/Amalgam/src/SDK/Definitions/Main/CBasePlayer.h new file mode 100644 index 0000000..201e6f0 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBasePlayer.h @@ -0,0 +1,119 @@ +#pragma once +#include "CBaseCombatCharacter.h" +#include "CUserCmd.h" +#include "../../../Utils/Signatures/Signatures.h" + +MAKE_SIGNATURE(CBasePlayer_GetAmmoCount, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 63 DA 48 8B F9 83 FB", 0x0); + +class CBasePlayer : public CBaseCombatCharacter +{ +public: + NETVAR(m_Local, void*, "CBasePlayer", "m_Local"); + NETVAR(m_chAreaBits, void*, "CBasePlayer", "m_chAreaBits"); + NETVAR(m_chAreaPortalBits, void*, "CBasePlayer", "m_chAreaPortalBits"); + NETVAR(m_iHideHUD, int, "CBasePlayer", "m_iHideHUD"); + NETVAR(m_flFOVRate, float, "CBasePlayer", "m_flFOVRate"); + NETVAR(m_bDucked, bool, "CBasePlayer", "m_bDucked"); + NETVAR(m_bDucking, bool, "CBasePlayer", "m_bDucking"); + NETVAR(m_bInDuckJump, bool, "CBasePlayer", "m_bInDuckJump"); + NETVAR(m_flDucktime, float, "CBasePlayer", "m_flDucktime"); + NETVAR(m_flDuckJumpTime, float, "CBasePlayer", "m_flDuckJumpTime"); + NETVAR(m_flJumpTime, float, "CBasePlayer", "m_flJumpTime"); + NETVAR(m_flFallVelocity, float, "CBasePlayer", "m_flFallVelocity"); + NETVAR(m_vecPunchAngle, Vec3, "CBasePlayer", "m_vecPunchAngle"); + NETVAR(m_vecPunchAngleVel, Vec3, "CBasePlayer", "m_vecPunchAngleVel"); + NETVAR(m_bDrawViewmodel, bool, "CBasePlayer", "m_bDrawViewmodel"); + NETVAR(m_bWearingSuit, bool, "CBasePlayer", "m_bWearingSuit"); + NETVAR(m_bPoisoned, bool, "CBasePlayer", "m_bPoisoned"); + NETVAR(m_flStepSize, float, "CBasePlayer", "m_flStepSize"); + NETVAR(m_bAllowAutoMovement, bool, "CBasePlayer", "m_bAllowAutoMovement"); + NETVAR(m_vecViewOffset, Vec3, "CBasePlayer", "m_vecViewOffset[0]"); + NETVAR(m_flFriction, float, "CBasePlayer", "m_flFriction"); + NETVAR(m_iAmmo, void*, "CBasePlayer", "m_iAmmo"); + NETVAR(m_fOnTarget, int, "CBasePlayer", "m_fOnTarget"); + NETVAR(m_nTickBase, int, "CBasePlayer", "m_nTickBase"); + NETVAR(m_nNextThinkTick, int, "CBasePlayer", "m_nNextThinkTick"); + NETVAR(m_hLastWeapon, EHANDLE, "CBasePlayer", "m_hLastWeapon"); + NETVAR(m_hGroundEntity, EHANDLE, "CBasePlayer", "m_hGroundEntity"); + NETVAR(m_vecVelocity, Vec3, "CBasePlayer", "m_vecVelocity[0]"); + NETVAR(m_vecBaseVelocity, Vec3, "CBasePlayer", "m_vecBaseVelocity"); + NETVAR(m_hConstraintEntity, EHANDLE, "CBasePlayer", "m_hConstraintEntity"); + NETVAR(m_vecConstraintCenter, Vec3, "CBasePlayer", "m_vecConstraintCenter"); + NETVAR(m_flConstraintRadius, float, "CBasePlayer", "m_flConstraintRadius"); + NETVAR(m_flConstraintWidth, float, "CBasePlayer", "m_flConstraintWidth"); + NETVAR(m_flConstraintSpeedFactor, float, "CBasePlayer", "m_flConstraintSpeedFactor"); + NETVAR(m_flDeathTime, float, "CBasePlayer", "m_flDeathTime"); + NETVAR(m_nWaterLevel, byte, "CBasePlayer", "m_nWaterLevel"); + NETVAR(m_flLaggedMovementValue, float, "CBasePlayer", "m_flLaggedMovementValue"); + NETVAR(m_AttributeList, void*, "CBasePlayer", "m_AttributeList"); + NETVAR(pl, void*, "CBasePlayer", "pl"); + NETVAR(deadflag, int, "CBasePlayer", "deadflag"); + NETVAR(m_iFOV, int, "CBasePlayer", "m_iFOV"); + NETVAR(m_iFOVStart, int, "CBasePlayer", "m_iFOVStart"); + NETVAR(m_flFOVTime, float, "CBasePlayer", "m_flFOVTime"); + NETVAR(m_iDefaultFOV, int, "CBasePlayer", "m_iDefaultFOV"); + NETVAR(m_hZoomOwner, EHANDLE, "CBasePlayer", "m_hZoomOwner"); + NETVAR(m_hVehicle, EHANDLE, "CBasePlayer", "m_hVehicle"); + NETVAR(m_hUseEntity, EHANDLE, "CBasePlayer", "m_hUseEntity"); + NETVAR(m_iHealth, int, "CBasePlayer", "m_iHealth"); + NETVAR(m_lifeState, byte, "CBasePlayer", "m_lifeState"); + NETVAR(m_iBonusProgress, int, "CBasePlayer", "m_iBonusProgress"); + NETVAR(m_iBonusChallenge, int, "CBasePlayer", "m_iBonusChallenge"); + NETVAR(m_flMaxspeed, float, "CBasePlayer", "m_flMaxspeed"); + NETVAR(m_fFlags, int, "CBasePlayer", "m_fFlags"); + NETVAR(m_iObserverMode, int, "CBasePlayer", "m_iObserverMode"); + NETVAR(m_hObserverTarget, EHANDLE, "CBasePlayer", "m_hObserverTarget"); + NETVAR(m_hViewModel, EHANDLE, "CBasePlayer", "m_hViewModel[0]"); + NETVAR(m_szLastPlaceName, const char*, "CBasePlayer", "m_szLastPlaceName"); + + NETVAR_OFF(m_nButtons, int, "CBasePlayer", "m_hConstraintEntity", -12); + NETVAR_OFF(m_pCurrentCommand, CUserCmd*, "CBasePlayer", "m_hConstraintEntity", -8); + NETVAR_OFF(m_afButtonLast, int, "CBasePlayer", "m_hConstraintEntity", -24); + NETVAR_OFF(m_flWaterJumpTime, float, "CBasePlayer", "m_fOnTarget", -60); + NETVAR_OFF(m_flSwimSoundTime, float, "CBasePlayer", "m_fOnTarget", -44); + NETVAR_OFF(m_vecLadderNormal, Vec3, "CBasePlayer", "m_fOnTarget", -36); + NETVAR_OFF(m_surfaceProps, int, "CBasePlayer", "m_hLastWeapon", 72); + NETVAR_OFF(m_pSurfaceData, void*, "CBasePlayer", "m_hLastWeapon", 76); + NETVAR_OFF(m_surfaceFriction, float, "CBasePlayer", "m_hLastWeapon", 80); + NETVAR_OFF(m_chTextureType, char, "CBasePlayer", "m_hLastWeapon", 84); + + CONDGET(IsOnGround, m_fFlags(), FL_ONGROUND); + CONDGET(IsInWater, m_fFlags(), FL_INWATER); + CONDGET(IsDucking, m_fFlags(), FL_DUCKING); + + bool IsAlive() + { + return m_lifeState() == LIFE_ALIVE; + } + + Vec3 GetShootPos() + { + return m_vecOrigin() + m_vecViewOffset(); + } + + Vec3 GetEyePosition() + { + return GetAbsOrigin() + m_vecViewOffset(); + } + + bool OnSolid() + { + return m_hGroundEntity() || IsOnGround(); + } + + bool IsSwimming() + { + return m_nWaterLevel() > 1; + } + + __inline void SetCurrentCmd(CUserCmd* pCmd) + { + static int nOffset = U::NetVars.GetNetVar("CBasePlayer", "m_hConstraintEntity") - 8; + *reinterpret_cast(std::uintptr_t(this) + nOffset) = pCmd; + } + + int GetAmmoCount(int iAmmoType) + { + return S::CBasePlayer_GetAmmoCount.As()(this, iAmmoType); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseProjectile.h b/Amalgam/src/SDK/Definitions/Main/CBaseProjectile.h new file mode 100644 index 0000000..4f87d08 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseProjectile.h @@ -0,0 +1,91 @@ +#pragma once +#include "CBaseAnimating.h" + +enum +{ + TF_GL_MODE_REGULAR = 0, + TF_GL_MODE_REMOTE_DETONATE, + TF_GL_MODE_REMOTE_DETONATE_PRACTICE, + TF_GL_MODE_CANNONBALL +}; + +class CBaseProjectile : public CBaseAnimating +{ +public: + NETVAR(m_hOriginalLauncher, EHANDLE, "CBaseProjectile", "m_hOriginalLauncher"); +}; + +class CBaseGrenade : public CBaseProjectile +{ +public: + NETVAR(m_flDamage, float, "CBaseGrenade", "m_flDamage"); + NETVAR(m_DmgRadius, float, "CBaseGrenade", "m_DmgRadius"); + NETVAR(m_bIsLive, bool, "CBaseGrenade", "m_bIsLive"); + NETVAR(m_hThrower, EHANDLE, "CBaseGrenade", "m_hThrower"); + NETVAR(m_vecVelocity, Vec3, "CBaseGrenade", "m_vecVelocity"); + NETVAR(m_fFlags, int, "CBaseGrenade", "m_fFlags"); +}; + +class CTFBaseRocket : public CBaseProjectile +{ +public: + NETVAR(m_vInitialVelocity, Vec3, "CTFBaseRocket", "m_vInitialVelocity"); + NETVAR(m_vecOrigin, Vec3, "CTFBaseRocket", "m_vecOrigin"); + NETVAR(m_angRotation, Vec3, "CTFBaseRocket", "m_angRotation"); + NETVAR(m_iDeflected, int, "CTFBaseRocket", "m_iDeflected"); + NETVAR(m_hLauncher, EHANDLE, "CTFBaseRocket", "m_hLauncher"); +}; + +class CTFBaseProjectile : public CBaseProjectile +{ +public: + NETVAR(m_hLauncher, EHANDLE, "CTFBaseProjectile", "m_hLauncher"); +}; + +class CTFWeaponBaseGrenadeProj : public CBaseGrenade +{ +public: + NETVAR(m_vInitialVelocity, Vec3, "CTFWeaponBaseGrenadeProj", "m_vInitialVelocity"); + NETVAR(m_bCritical, bool, "CTFWeaponBaseGrenadeProj", "m_bCritical"); + NETVAR(m_iDeflected, int, "CTFWeaponBaseGrenadeProj", "m_iDeflected"); + NETVAR(m_vecOrigin, Vec3, "CTFWeaponBaseGrenadeProj", "m_vecOrigin"); + NETVAR(m_angRotation, Vec3, "CTFWeaponBaseGrenadeProj", "m_angRotation"); + NETVAR(m_hDeflectOwner, EHANDLE, "CTFWeaponBaseGrenadeProj", "m_hDeflectOwner"); +}; + +class CTFProjectile_Rocket : public CTFBaseRocket +{ +public: + NETVAR(m_bCritical, bool, "CTFProjectile_Rocket", "m_bCritical"); +}; + +class CTFProjectile_Flare : public CTFBaseRocket +{ +public: + NETVAR(m_bCritical, bool, "CTFProjectile_Flare", "m_bCritical"); +}; + +class CTFProjectile_Arrow : public CTFBaseRocket +{ +public: + NETVAR(m_bArrowAlight, bool, "CTFProjectile_Arrow", "m_bArrowAlight"); + NETVAR(m_bCritical, bool, "CTFProjectile_Arrow", "m_bCritical"); + NETVAR(m_iProjectileType, int, "CTFProjectile_Arrow", "m_iProjectileType"); +}; + +class CTFGrenadePipebombProjectile : public CTFWeaponBaseGrenadeProj +{ +public: + NETVAR(m_bTouched, bool, "CTFGrenadePipebombProjectile", "m_bTouched"); + NETVAR(m_iType, int, "CTFGrenadePipebombProjectile", "m_iType"); + NETVAR(m_hLauncher, EHANDLE, "CTFGrenadePipebombProjectile", "m_hLauncher"); + NETVAR(m_bDefensiveBomb, int, "CTFGrenadePipebombProjectile", "m_bDefensiveBomb"); + + NETVAR_OFF(m_flCreationTime, float, "CTFGrenadePipebombProjectile", "m_iType", 4); + NETVAR_OFF(m_bPulsed, bool, "CTFGrenadePipebombProjectile", "m_iType", 12); + + bool HasStickyEffects() + { + return m_iType() == TF_GL_MODE_REMOTE_DETONATE || m_iType() == TF_GL_MODE_REMOTE_DETONATE_PRACTICE; + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CBaseTrace.h b/Amalgam/src/SDK/Definitions/Main/CBaseTrace.h new file mode 100644 index 0000000..a60c3c0 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CBaseTrace.h @@ -0,0 +1,53 @@ +#pragma once +#include "../Types.h" + +#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) + +struct cplane_t +{ + Vector normal{}; + float dist{}; + byte type{}; + byte signbits{}; + byte pad[2]{}; +}; + +#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 + +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +class CBaseTrace +{ +public: + 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: + Vector startpos{}; + Vector endpos{}; + cplane_t plane{}; + float fraction{}; + int contents{}; + unsigned short dispFlags{}; + bool allsolid{}; + bool startsolid{}; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CCollisionProperty.h b/Amalgam/src/SDK/Definitions/Main/CCollisionProperty.h new file mode 100644 index 0000000..5b01334 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CCollisionProperty.h @@ -0,0 +1,50 @@ +#pragma once +#include "CGameTrace.h" +#include "../Types.h" +#include "../../../Utils/Signatures/Signatures.h" + +MAKE_SIGNATURE(CCollisionPropert_SetCollisionBounds, "client.dll", "48 8B C4 48 89 58 ? 48 89 70 ? 48 89 78 ? 41 56 48 81 EC ? ? ? ? F2 0F 10 02", 0x0); +MAKE_SIGNATURE(CCollisionProperty_CalcNearestPoint, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 49 8B D8 48 8B F9 4C 8D 44 24", 0x0); + +struct model_t; + +class ICollideable +{ +public: + virtual void* GetEntityHandle() = 0; + virtual const Vec3& OBBMinsPreScaled() const = 0; + virtual const Vec3& OBBMaxsPreScaled() const = 0; + virtual const Vec3& OBBMins() const = 0; + virtual const Vec3& OBBMaxs() const = 0; + virtual void WorldSpaceTriggerBounds(Vec3* pVecWorldMins, Vec3* pVecWorldMaxs) const = 0; + virtual bool TestCollision(const Ray_t& ray, unsigned int fContentsMask, CGameTrace& tr) = 0; + virtual bool TestHitboxes(const Ray_t& ray, unsigned int fContentsMask, CGameTrace& tr) = 0; + virtual int GetCollisionModelIndex() = 0; + virtual const model_t* GetCollisionModel() = 0; + virtual const Vec3& GetCollisionOrigin() const = 0; + virtual const Vec3& GetCollisionAngles() const = 0; + virtual const matrix3x4& CollisionToWorldTransform() const = 0; + virtual SolidType_t GetSolid() const = 0; + virtual int GetSolidFlags() const = 0; + virtual void* GetIClientUnknown() = 0; + virtual int GetCollisionGroup() const = 0; + virtual void WorldSpaceSurroundingBounds(Vec3* pVecMins, Vec3* pVecMaxs) = 0; + virtual bool ShouldTouchTrigger(int triggerSolidFlags) const = 0; + virtual const matrix3x4* GetRootParentToWorldTransform() const = 0; +}; + +class CCollisionProperty : public ICollideable +{ +public: + void SetCollisionBounds(const Vec3& mins, const Vec3& maxs) + { + static auto func = S::CCollisionPropert_SetCollisionBounds.As(); + func(this, mins, maxs); + } + + void CalcNearestPoint(const Vec3& vecWorldPt, Vec3* pVecNearestWorldPt) + { + static auto func = S::CCollisionProperty_CalcNearestPoint.As(); + func(this, vecWorldPt, pVecNearestWorldPt); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CEconDefinition.h b/Amalgam/src/SDK/Definitions/Main/CEconDefinition.h new file mode 100644 index 0000000..f3f7f4c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CEconDefinition.h @@ -0,0 +1,50 @@ +#pragma once +#include "KeyValues.h" +#include "../Steam/SteamClientPublic.h" + +class CEconNotification +{ +public: + virtual ~CEconNotification() = 0; + virtual void SetLifetime(float flSeconds) = 0; + virtual float GetExpireTime() const = 0; + virtual float GetInGameLifeTime() const = 0; + virtual bool BShowInGameElements() const = 0; + virtual void MarkForDeletion() = 0; + + enum EType + { + // Can only be deleted + eType_Basic, + // Can be accept or declined + eType_AcceptDecline, + // Can be triggered or deleted + eType_Trigger, + // Can only be triggered + eType_MustTrigger, + }; + + virtual EType NotificationType() = 0; + virtual bool BHighPriority() = 0; + virtual void Trigger() = 0; + virtual void Accept() = 0; + virtual void Decline() = 0; + virtual void Deleted() = 0; + virtual void Expired() = 0; + virtual void UpdateTick() = 0; + virtual const char* GetUnlocalizedHelpText() = 0; + virtual void* CreateUIElement(bool bMainMenu) const = 0; + +protected: + const char* m_pText; + const char* m_pSoundFilename; + float m_flExpireTime; + KeyValues* m_pKeyValues; + wchar_t m_wszBuffer[1024]; + CSteamID m_steamID; + +private: + friend class CEconNotificationQueue; + int m_iID; + bool m_bInUse; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CEntitySphereQuery.h b/Amalgam/src/SDK/Definitions/Main/CEntitySphereQuery.h new file mode 100644 index 0000000..c907c8f --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CEntitySphereQuery.h @@ -0,0 +1,35 @@ +#pragma once +#include "../../../Utils/Signatures/Signatures.h" +#include "../Definitions.h" +#include "CBaseEntity.h" + +#define MAX_SPHERE_QUERY 512 + +#pragma warning (disable : 26495) + +MAKE_SIGNATURE(CEntitySphereQuery, "client.dll", "40 53 48 83 EC ? 48 8B D9 C7 44 24 ? ? ? ? ? 33 C9", 0x0); + +//credits to KGB +class CEntitySphereQuery +{ +public: + CEntitySphereQuery(const Vec3& center, const float radius, const int flagMask = 0, const int partitionMask = PARTITION_CLIENT_NON_STATIC_EDICTS) + { + static auto dwAddress = S::CEntitySphereQuery(); + reinterpret_cast(dwAddress)(this, center, radius, flagMask, partitionMask); + } + + CBaseEntity* GetCurrentEntity() + { + return (m_nListIndex < m_nListCount) ? m_pList[m_nListIndex] : nullptr; + } + + void NextEntity() + { + m_nListIndex++; + } + +private: + int m_nListIndex, m_nListCount; + CBaseEntity* m_pList[MAX_SPHERE_QUERY]; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CGameTrace.h b/Amalgam/src/SDK/Definitions/Main/CGameTrace.h new file mode 100644 index 0000000..620a848 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CGameTrace.h @@ -0,0 +1,27 @@ +#pragma once +#include "CModel.h" +#include "UtlVector.h" +#include "IHandleEntity.h" +#include "../Misc/ISpatialPartition.h" + +class CBaseEntity; + +class CGameTrace : public CBaseTrace +{ +public: + bool DidHit() const; + + float fractionleftsolid{}; + csurface_t surface{}; + int hitgroup{}; + short physicsbone{}; + CBaseEntity* m_pEnt{}; + int hitbox{}; +}; + +inline bool CGameTrace::DidHit() const +{ + return fraction < 1.f || allsolid || startsolid; +} + +typedef CGameTrace trace_t; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CHalloweenPickup.h b/Amalgam/src/SDK/Definitions/Main/CHalloweenPickup.h new file mode 100644 index 0000000..6e5319a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CHalloweenPickup.h @@ -0,0 +1,13 @@ +#pragma once +#include "CBaseAnimating.h" + +class CHalloweenPickup : public CBaseAnimating +{ +public: +}; + +class CHalloweenGiftPickup : public CHalloweenPickup +{ +public: + NETVAR(m_hTargetPlayer, EHANDLE, "CHalloweenGiftPickup", "m_hTargetPlayer"); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CModel.h b/Amalgam/src/SDK/Definitions/Main/CModel.h new file mode 100644 index 0000000..edf3dc4 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CModel.h @@ -0,0 +1,97 @@ +#pragma once +#include "CBaseTrace.h" +#include "CBaseHandle.h" +#include "../Misc/BSPFlags.h" +#include "../Misc/VCollide.h" + +struct edict_t; +struct model_t; + +#define AREA_SOLID 1 +#define AREA_TRIGGERS 2 + +struct cmodel_t +{ + Vector mins, maxs; + Vector origin; + int headnode; + vcollide_t vcollisionData; +}; + +struct csurface_t +{ + const char* name; + short surfaceProps; + unsigned short flags; +}; + +class __declspec(align(16))VectorAligned : public Vec3 +{ +public: + inline VectorAligned(void) { }; + + inline VectorAligned(float x, float y, float z) { + Set(x, y, z); + } + + explicit VectorAligned(const Vec3& othr) { + Set(othr.x, othr.y, othr.z); + } + + VectorAligned& operator=(const Vec3& othr) { + Set(othr.x, othr.y, othr.z); + return *this; + } + + float w = 0.0f; +}; + +struct Ray_t +{ + VectorAligned m_Start{}; + VectorAligned m_Delta{}; + VectorAligned m_StartOffset{}; + VectorAligned m_Extents{}; + bool m_IsRay{}; + bool m_IsSwept{}; + + void Init(Vector const& start, Vector const& end) + { + m_Delta = end - start; + m_IsSwept = (m_Delta.LengthSqr() != 0); + m_Extents.Set(); + m_IsRay = true; + m_StartOffset.Set(); + m_Start = start; + } + + void Init(Vector const& start, Vector const& end, Vector const& mins, Vector const& maxs) + { + m_Delta = end - start; + m_IsSwept = (m_Delta.LengthSqr() != 0); + m_Extents = maxs - mins; + m_Extents *= 0.5f; + m_IsRay = (m_Extents.LengthSqr() < 1e-6); + m_StartOffset = mins + maxs; + m_StartOffset *= 0.5f; + m_Start = start + m_StartOffset; + m_StartOffset *= -1.0f; + } + + 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] = 3.402823e+38f; + } + } + return vecInvDelta; + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CMultiPlayerAnimState.h b/Amalgam/src/SDK/Definitions/Main/CMultiPlayerAnimState.h new file mode 100644 index 0000000..1b5d8ba --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CMultiPlayerAnimState.h @@ -0,0 +1,335 @@ +#pragma once +#include "CBasePlayer.h" +#include "../Misc/Activity.h" + +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; + } + + 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; +}; + +class CAnimationLayer +{ +public: + CRangeCheckedVar m_nSequence; + CRangeCheckedVar m_flPrevCycle; + CRangeCheckedVar m_flWeight; + int m_nOrder; + CRangeCheckedVar m_flPlaybackRate; + CRangeCheckedVar m_flCycle; + float m_flLayerAnimtime; + float m_flLayerFadeOuttime; + float m_flBlendIn; + float m_flBlendOut; + bool m_bClientBlend; +}; + +typedef enum +{ + LEGANIM_9WAY, + LEGANIM_8WAY, + LEGANIM_GOLDSRC +} LegAnimType_t; + +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, + PLAYERANIMEVENT_CANCEL, + PLAYERANIMEVENT_SPAWN, + PLAYERANIMEVENT_SNAP_YAW, + PLAYERANIMEVENT_CUSTOM, + PLAYERANIMEVENT_CUSTOM_GESTURE, + PLAYERANIMEVENT_CUSTOM_SEQUENCE, + PLAYERANIMEVENT_CUSTOM_GESTURE_SEQUENCE, + 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 +}; + +struct GestureSlot_t +{ + int m_iGestureSlot; + Activity m_iActivity; + bool m_bAutoKill; + bool m_bActive; + CAnimationLayer* m_pAnimLayer; +}; + +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; +}; + +struct MultiPlayerMovementData_t +{ + float m_flWalkSpeed; + float m_flRunSpeed; + float m_flSprintSpeed; + float m_flBodyYawRate; +}; + +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 +}; + +class IInterpolatedVar +{ +public: + virtual ~IInterpolatedVar() = 0; + virtual void Setup(void* pValue, int type) = 0; + virtual void SetInterpolationAmount(float seconds) = 0; + virtual void NoteLastNetworkedValue() = 0; + virtual bool NoteChanged(float changetime, bool bUpdateLastNetworkedValue) = 0; + virtual void Reset() = 0; + 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; +}; + +class CInterpolatedVar +{ +public: + IInterpolatedVar* vtable; + float* m_pValue; + float* m_pElements; + unsigned short m_maxElement; + unsigned short m_firstElement; + unsigned short m_count; + unsigned short m_growSize; + float* 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; +}; + +class CMultiPlayerAnimState +{ +public: + virtual ~CMultiPlayerAnimState() = 0; + virtual void ClearAnimationState() = 0; + virtual void DoAnimationEvent(PlayerAnimEvent_t event, int nData = 0) = 0; + virtual Activity CalcMainActivity() = 0; + virtual void Update(float eyeYaw, float eyePitch) = 0; + virtual void Release() = 0; + virtual Activity TranslateActivity(Activity actDesired) = 0; + virtual void SetRunSpeed(float flSpeed) = 0; + virtual void SetWalkSpeed(float flSpeed) = 0; + virtual void SetSprintSpeed(float flSpeed) = 0; + virtual void ShowDebugInfo() = 0; + virtual void DebugShowAnimState(int iStartLine) = 0; + virtual void Init(CBasePlayer* pPlayer, MultiPlayerMovementData_t& movementData) = 0; + virtual int SelectWeightedSequence(Activity activity) = 0; + virtual void RestartMainSequence() = 0; + virtual void GetOuterAbsVelocity(Vector& vel) = 0; + virtual bool HandleJumping(Activity& idealActivity) = 0; + virtual bool HandleDucking(Activity& idealActivity) = 0; + virtual bool HandleMoving(Activity& idealActivity) = 0; + virtual bool HandleSwimming(Activity& idealActivity) = 0; + virtual bool HandleDying(Activity& idealActivity) = 0; + virtual void RestartGesture(int iGestureSlot, Activity iGestureActivity, bool bAutoKill = true) = 0; + virtual float GetGesturePlaybackRate() = 0; + virtual void PlayFlinchGesture(Activity iActivity) = 0; + virtual float CalcMovementSpeed(bool* bIsMoving) = 0; + virtual float CalcMovementPlaybackRate(bool* bIsMoving) = 0; + virtual void ComputePoseParam_MoveYaw(CStudioHdr* pStudioHdr) = 0; + virtual void ComputePoseParam_AimPitch(CStudioHdr* pStudioHdr) = 0; + virtual void ComputePoseParam_AimYaw(CStudioHdr* pStudioHdr) = 0; + virtual void EstimateYaw() = 0; + virtual float GetCurrentMaxGroundSpeed() = 0; + virtual void ComputeSequences(CStudioHdr* pStudioHdr) = 0; + virtual bool ShouldUpdateAnimState() = 0; + +public: + bool m_bForceAimYaw; + CUtlVector m_aGestureSlots; + CBasePlayer* m_pEntity; + QAngle m_angRender; + 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; + bool m_bJumping; + float m_flJumpStartTime; + bool m_bFirstJumpFrame; + bool m_bInSwim; + bool m_bFirstSwimFrame; + bool m_bDying; + bool m_bFirstDyingFrame; + Activity m_eCurrentMainSequenceActivity; + int m_nSpecificMainSequence; + CHandle m_hActiveWeapon; + float m_flLastGroundSpeedUpdateTime; + CInterpolatedVar m_iv_flMaxGroundSpeed; + float m_flMaxGroundSpeed; + int m_nMovementSequence; + LegAnimType_t m_LegAnimType; +}; + +class CTFPlayerAnimState : public CMultiPlayerAnimState +{ +public: + CBaseEntity* GetTFPlayer() { return m_pTFPlayer; } + + virtual void ClearAnimationState() = 0; + virtual Activity TranslateActivity(Activity actDesired) = 0; + virtual void Update(float eyeYaw, float eyePitch) = 0; + virtual void CheckStunAnimation() = 0; + virtual Activity CalcMainActivity() = 0; + virtual void ComputePoseParam_AimYaw(CStudioHdr* pStudioHdr) = 0; + virtual float GetCurrentMaxGroundSpeed() = 0; + virtual float GetGesturePlaybackRate() = 0; + virtual bool ShouldUpdateAnimState() = 0; + virtual void GetOuterAbsVelocity(Vec3& vel) = 0; + virtual void RestartGesture(int iGestureSlot, Activity iGestureActivity, bool bAutoKill = true) = 0; + void SetRenderAngles(const Vec3& angles) { m_angRender = angles; } + + CBaseEntity* m_pTFPlayer; + bool m_bInAirWalk; + float m_flHoldDeployedPoseUntilTime; + float m_flTauntMoveX; + float m_flTauntMoveY; + float m_flVehicleLeanVel; + float m_flVehicleLeanPos; + Vec3 m_vecSmoothedUp; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CTFPlayer.h b/Amalgam/src/SDK/Definitions/Main/CTFPlayer.h new file mode 100644 index 0000000..86eecf3 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CTFPlayer.h @@ -0,0 +1,504 @@ +#pragma once +#include "CBasePlayer.h" +#include "CMultiPlayerAnimState.h" +#include "CTFWeaponBase.h" +#include "../../../Utils/Signatures/Signatures.h" + +MAKE_SIGNATURE(CTFPlayer_IsPlayerOnSteamFriendsList, "client.dll", "40 57 48 81 EC ? ? ? ? 48 8B FA E8", 0x0); +MAKE_SIGNATURE(TeamFortress_CalculateMaxSpeed, "client.dll", "88 54 24 ? 53 55", 0x0); +MAKE_SIGNATURE(CTFPlayer_UpdateClientSideAnimation, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B D9 E8 ? ? ? ? 48 8B F8 48 85 C0 74 ? 48 8B 00 48 8B CF FF 90 ? ? ? ? 84 C0 75 ? 33 FF 48 3B DF", 0x0); +MAKE_SIGNATURE(CTFPlayer_UpdateWearables, "client.dll", "40 53 48 83 EC ? 48 8B D9 E8 ? ? ? ? 48 8B 03 48 8B CB FF 90 ? ? ? ? 4C 8D 0D ? ? ? ? C7 44 24 ? ? ? ? ? 48 8B C8 4C 8D 05 ? ? ? ? 33 D2 E8 ? ? ? ? 48 85 C0", 0x0); +MAKE_SIGNATURE(CTFPlayer_ThirdPersonSwitch, "client.dll", "48 83 EC ? 48 8B 01 48 89 5C 24 ? 48 8B D9 48 89 7C 24", 0x0); + +class CTFPlayer : public CBasePlayer +{ +public: + NETVAR(m_bSaveMeParity, bool, "CTFPlayer", "m_bSaveMeParity"); + NETVAR(m_bIsMiniBoss, bool, "CTFPlayer", "m_bIsMiniBoss"); + NETVAR(m_bIsABot, bool, "CTFPlayer", "m_bIsABot"); + NETVAR(m_nBotSkill, int, "CTFPlayer", "m_nBotSkill"); + NETVAR(m_nWaterLevel, byte, "CTFPlayer", "m_nWaterLevel"); + NETVAR(m_hRagdoll, EHANDLE, "CTFPlayer", "m_hRagdoll"); + NETVAR(m_PlayerClass, void*, "CTFPlayer", "m_PlayerClass"); + NETVAR(m_iClass, int, "CTFPlayer", "m_iClass"); + NETVAR(m_iszClassIcon, const char*, "CTFPlayer", "m_iszClassIcon"); + NETVAR(m_iszCustomModel, const char*, "CTFPlayer", "m_iszCustomModel"); + NETVAR(m_vecCustomModelOffset, Vec3, "CTFPlayer", "m_vecCustomModelOffset"); + NETVAR(m_angCustomModelRotation, Vec3, "CTFPlayer", "m_angCustomModelRotation"); + NETVAR(m_bCustomModelRotates, bool, "CTFPlayer", "m_bCustomModelRotates"); + NETVAR(m_bCustomModelRotationSet, bool, "CTFPlayer", "m_bCustomModelRotationSet"); + NETVAR(m_bCustomModelVisibleToSelf, bool, "CTFPlayer", "m_bCustomModelVisibleToSelf"); + NETVAR(m_bUseClassAnimations, bool, "CTFPlayer", "m_bUseClassAnimations"); + NETVAR(m_iClassModelParity, int, "CTFPlayer", "m_iClassModelParity"); + NETVAR(m_Shared, void*, "CTFPlayer", "m_Shared"); + NETVAR(m_nPlayerCond, int, "CTFPlayer", "m_nPlayerCond"); + NETVAR(m_bJumping, bool, "CTFPlayer", "m_bJumping"); + NETVAR(m_nNumHealers, int, "CTFPlayer", "m_nNumHealers"); + NETVAR(m_iCritMult, int, "CTFPlayer", "m_iCritMult"); + NETVAR(m_iAirDash, int, "CTFPlayer", "m_iAirDash"); + NETVAR(m_nAirDucked, int, "CTFPlayer", "m_nAirDucked"); + NETVAR(m_flDuckTimer, float, "CTFPlayer", "m_flDuckTimer"); + NETVAR(m_nPlayerState, int, "CTFPlayer", "m_nPlayerState"); + NETVAR(m_iDesiredPlayerClass, int, "CTFPlayer", "m_iDesiredPlayerClass"); + NETVAR(m_flMovementStunTime, float, "CTFPlayer", "m_flMovementStunTime"); + NETVAR(m_iMovementStunAmount, int, "CTFPlayer", "m_iMovementStunAmount"); + NETVAR(m_iMovementStunParity, int, "CTFPlayer", "m_iMovementStunParity"); + NETVAR(m_hStunner, EHANDLE, "CTFPlayer", "m_hStunner"); + NETVAR(m_iStunFlags, int, "CTFPlayer", "m_iStunFlags"); + NETVAR(m_nArenaNumChanges, int, "CTFPlayer", "m_nArenaNumChanges"); + NETVAR(m_bArenaFirstBloodBoost, bool, "CTFPlayer", "m_bArenaFirstBloodBoost"); + NETVAR(m_iWeaponKnockbackID, int, "CTFPlayer", "m_iWeaponKnockbackID"); + NETVAR(m_bLoadoutUnavailable, bool, "CTFPlayer", "m_bLoadoutUnavailable"); + NETVAR(m_iItemFindBonus, int, "CTFPlayer", "m_iItemFindBonus"); + NETVAR(m_bShieldEquipped, bool, "CTFPlayer", "m_bShieldEquipped"); + NETVAR(m_bParachuteEquipped, bool, "CTFPlayer", "m_bParachuteEquipped"); + NETVAR(m_iNextMeleeCrit, int, "CTFPlayer", "m_iNextMeleeCrit"); + NETVAR(m_iDecapitations, int, "CTFPlayer", "m_iDecapitations"); + NETVAR(m_iRevengeCrits, int, "CTFPlayer", "m_iRevengeCrits"); + NETVAR(m_iDisguiseBody, int, "CTFPlayer", "m_iDisguiseBody"); + NETVAR(m_hCarriedObject, EHANDLE, "CTFPlayer", "m_hCarriedObject"); + NETVAR(m_bCarryingObject, bool, "CTFPlayer", "m_bCarryingObject"); + NETVAR(m_flNextNoiseMakerTime, float, "CTFPlayer", "m_flNextNoiseMakerTime"); + NETVAR(m_iSpawnRoomTouchCount, int, "CTFPlayer", "m_iSpawnRoomTouchCount"); + NETVAR(m_iKillCountSinceLastDeploy, int, "CTFPlayer", "m_iKillCountSinceLastDeploy"); + NETVAR(m_flFirstPrimaryAttack, float, "CTFPlayer", "m_flFirstPrimaryAttack"); + NETVAR(m_flEnergyDrinkMeter, float, "CTFPlayer", "m_flEnergyDrinkMeter"); + NETVAR(m_flHypeMeter, float, "CTFPlayer", "m_flHypeMeter"); + NETVAR(m_flChargeMeter, float, "CTFPlayer", "m_flChargeMeter"); + NETVAR(m_flInvisChangeCompleteTime, float, "CTFPlayer", "m_flInvisChangeCompleteTime"); + NETVAR(m_nDisguiseTeam, int, "CTFPlayer", "m_nDisguiseTeam"); + NETVAR(m_nDisguiseClass, int, "CTFPlayer", "m_nDisguiseClass"); + NETVAR(m_nDisguiseSkinOverride, int, "CTFPlayer", "m_nDisguiseSkinOverride"); + NETVAR(m_nMaskClass, int, "CTFPlayer", "m_nMaskClass"); + NETVAR(m_iDisguiseTargetIndex, int, "CTFPlayer", "m_iDisguiseTargetIndex"); + NETVAR(m_iDisguiseHealth, int, "CTFPlayer", "m_iDisguiseHealth"); + NETVAR(m_bFeignDeathReady, bool, "CTFPlayer", "m_bFeignDeathReady"); + NETVAR(m_hDisguiseWeapon, EHANDLE, "CTFPlayer", "m_hDisguiseWeapon"); + NETVAR(m_nTeamTeleporterUsed, int, "CTFPlayer", "m_nTeamTeleporterUsed"); + NETVAR(m_flCloakMeter, float, "CTFPlayer", "m_flCloakMeter"); + NETVAR(m_flSpyTranqBuffDuration, float, "CTFPlayer", "m_flSpyTranqBuffDuration"); + NETVAR(m_nDesiredDisguiseTeam, int, "CTFPlayer", "m_nDesiredDisguiseTeam"); + NETVAR(m_nDesiredDisguiseClass, int, "CTFPlayer", "m_nDesiredDisguiseClass"); + NETVAR(m_flStealthNoAttackExpire, float, "CTFPlayer", "m_flStealthNoAttackExpire"); + NETVAR(m_flStealthNextChangeTime, float, "CTFPlayer", "m_flStealthNextChangeTime"); + NETVAR(m_bLastDisguisedAsOwnTeam, bool, "CTFPlayer", "m_bLastDisguisedAsOwnTeam"); + NETVAR(m_flRageMeter, float, "CTFPlayer", "m_flRageMeter"); + NETVAR(m_bRageDraining, bool, "CTFPlayer", "m_bRageDraining"); + NETVAR(m_flNextRageEarnTime, float, "CTFPlayer", "m_flNextRageEarnTime"); + NETVAR(m_bInUpgradeZone, bool, "CTFPlayer", "m_bInUpgradeZone"); + NETVAR(m_flItemChargeMeter, void*, "CTFPlayer", "m_flItemChargeMeter"); + NETVAR(m_bPlayerDominated, void*, "CTFPlayer", "m_bPlayerDominated"); + NETVAR(m_bPlayerDominatingMe, void*, "CTFPlayer", "m_bPlayerDominatingMe"); + NETVAR(m_ScoreData, void*, "CTFPlayer", "m_ScoreData"); + NETVAR(m_iCaptures, int, "CTFPlayer", "m_iCaptures"); + NETVAR(m_iDefenses, int, "CTFPlayer", "m_iDefenses"); + NETVAR(m_iKills, int, "CTFPlayer", "m_iKills"); + NETVAR(m_iDeaths, int, "CTFPlayer", "m_iDeaths"); + NETVAR(m_iSuicides, int, "CTFPlayer", "m_iSuicides"); + NETVAR(m_iDominations, int, "CTFPlayer", "m_iDominations"); + NETVAR(m_iRevenge, int, "CTFPlayer", "m_iRevenge"); + NETVAR(m_iBuildingsBuilt, int, "CTFPlayer", "m_iBuildingsBuilt"); + NETVAR(m_iBuildingsDestroyed, int, "CTFPlayer", "m_iBuildingsDestroyed"); + NETVAR(m_iHeadshots, int, "CTFPlayer", "m_iHeadshots"); + NETVAR(m_iBackstabs, int, "CTFPlayer", "m_iBackstabs"); + NETVAR(m_iHealPoints, int, "CTFPlayer", "m_iHealPoints"); + NETVAR(m_iInvulns, int, "CTFPlayer", "m_iInvulns"); + NETVAR(m_iTeleports, int, "CTFPlayer", "m_iTeleports"); + NETVAR(m_iResupplyPoints, int, "CTFPlayer", "m_iResupplyPoints"); + NETVAR(m_iKillAssists, int, "CTFPlayer", "m_iKillAssists"); + NETVAR(m_iPoints, int, "CTFPlayer", "m_iPoints"); + NETVAR(m_iBonusPoints, int, "CTFPlayer", "m_iBonusPoints"); + NETVAR(m_iDamageDone, int, "CTFPlayer", "m_iDamageDone"); + NETVAR(m_iCrits, int, "CTFPlayer", "m_iCrits"); + NETVAR(m_RoundScoreData, void*, "CTFPlayer", "m_RoundScoreData"); + NETVAR(m_ConditionList, void*, "CTFPlayer", "m_ConditionList"); + NETVAR(_condition_bits, int, "CTFPlayer", "_condition_bits"); + NETVAR(m_iTauntIndex, int, "CTFPlayer", "m_iTauntIndex"); + NETVAR(m_iTauntConcept, int, "CTFPlayer", "m_iTauntConcept"); + NETVAR(m_nPlayerCondEx, int, "CTFPlayer", "m_nPlayerCondEx"); + NETVAR(m_iStunIndex, int, "CTFPlayer", "m_iStunIndex"); + NETVAR(m_nHalloweenBombHeadStage, int, "CTFPlayer", "m_nHalloweenBombHeadStage"); + NETVAR(m_nPlayerCondEx2, int, "CTFPlayer", "m_nPlayerCondEx2"); + NETVAR(m_nPlayerCondEx3, int, "CTFPlayer", "m_nPlayerCondEx3"); + NETVAR(m_nStreaks, void*, "CTFPlayer", "m_nStreaks"); + NETVAR(m_unTauntSourceItemID_Low, int, "CTFPlayer", "m_unTauntSourceItemID_Low"); + NETVAR(m_unTauntSourceItemID_High, int, "CTFPlayer", "m_unTauntSourceItemID_High"); + NETVAR(m_flRuneCharge, float, "CTFPlayer", "m_flRuneCharge"); + NETVAR(m_bHasPasstimeBall, bool, "CTFPlayer", "m_bHasPasstimeBall"); + NETVAR(m_bIsTargetedForPasstimePass, bool, "CTFPlayer", "m_bIsTargetedForPasstimePass"); + NETVAR(m_hPasstimePassTarget, EHANDLE, "CTFPlayer", "m_hPasstimePassTarget"); + NETVAR(m_askForBallTime, float, "CTFPlayer", "m_askForBallTime"); + NETVAR(m_bKingRuneBuffActive, bool, "CTFPlayer", "m_bKingRuneBuffActive"); + NETVAR(m_nPlayerCondEx4, int, "CTFPlayer", "m_nPlayerCondEx4"); + NETVAR(m_flHolsterAnimTime, float, "CTFPlayer", "m_flHolsterAnimTime"); + NETVAR(m_hSwitchTo, EHANDLE, "CTFPlayer", "m_hSwitchTo"); + NETVAR(m_hItem, EHANDLE, "CTFPlayer", "m_hItem"); + NETVAR(m_bIsCoaching, bool, "CTFPlayer", "m_bIsCoaching"); + NETVAR(m_hCoach, EHANDLE, "CTFPlayer", "m_hCoach"); + NETVAR(m_hStudent, EHANDLE, "CTFPlayer", "m_hStudent"); + NETVAR(m_nCurrency, int, "CTFPlayer", "m_nCurrency"); + NETVAR(m_nExperienceLevel, int, "CTFPlayer", "m_nExperienceLevel"); + NETVAR(m_nExperienceLevelProgress, int, "CTFPlayer", "m_nExperienceLevelProgress"); + NETVAR(m_bMatchSafeToLeave, bool, "CTFPlayer", "m_bMatchSafeToLeave"); + NETVAR(m_vecOrigin, Vec3, "CTFPlayer", "m_vecOrigin"); + NETVAR(m_angEyeAnglesX, float, "CTFPlayer", "m_angEyeAngles[0]"); + NETVAR(m_angEyeAnglesY, float, "CTFPlayer", "m_angEyeAngles[1]"); + NETVAR(m_bAllowMoveDuringTaunt, bool, "CTFPlayer", "m_bAllowMoveDuringTaunt"); + NETVAR(m_bIsReadyToHighFive, bool, "CTFPlayer", "m_bIsReadyToHighFive"); + NETVAR(m_hHighFivePartner, EHANDLE, "CTFPlayer", "m_hHighFivePartner"); + NETVAR(m_nForceTauntCam, int, "CTFPlayer", "m_nForceTauntCam"); + NETVAR(m_flTauntYaw, float, "CTFPlayer", "m_flTauntYaw"); + NETVAR(m_nActiveTauntSlot, int, "CTFPlayer", "m_nActiveTauntSlot"); + NETVAR(m_iTauntItemDefIndex, int, "CTFPlayer", "m_iTauntItemDefIndex"); + NETVAR(m_flCurrentTauntMoveSpeed, float, "CTFPlayer", "m_flCurrentTauntMoveSpeed"); + NETVAR(m_flVehicleReverseTime, float, "CTFPlayer", "m_flVehicleReverseTime"); + NETVAR(m_flMvMLastDamageTime, float, "CTFPlayer", "m_flMvMLastDamageTime"); + NETVAR(m_flLastDamageTime, float, "CTFPlayer", "m_flLastDamageTime"); + NETVAR(m_bInPowerPlay, bool, "CTFPlayer", "m_bInPowerPlay"); + NETVAR(m_iSpawnCounter, int, "CTFPlayer", "m_iSpawnCounter"); + NETVAR(m_bArenaSpectator, bool, "CTFPlayer", "m_bArenaSpectator"); + NETVAR(m_AttributeManager, void*, "CTFPlayer", "m_AttributeManager"); + NETVAR(m_hOuter, EHANDLE, "CTFPlayer", "m_hOuter"); + NETVAR(m_ProviderType, int, "CTFPlayer", "m_ProviderType"); + NETVAR(m_iReapplyProvisionParity, int, "CTFPlayer", "m_iReapplyProvisionParity"); + NETVAR(m_flHeadScale, float, "CTFPlayer", "m_flHeadScale"); + NETVAR(m_flTorsoScale, float, "CTFPlayer", "m_flTorsoScale"); + NETVAR(m_flHandScale, float, "CTFPlayer", "m_flHandScale"); + NETVAR(m_bUseBossHealthBar, bool, "CTFPlayer", "m_bUseBossHealthBar"); + NETVAR(m_bUsingVRHeadset, bool, "CTFPlayer", "m_bUsingVRHeadset"); + NETVAR(m_bForcedSkin, bool, "CTFPlayer", "m_bForcedSkin"); + NETVAR(m_nForcedSkin, int, "CTFPlayer", "m_nForcedSkin"); + NETVAR(m_bGlowEnabled, bool, "CTFPlayer", "m_bGlowEnabled"); + NETVAR(m_nActiveWpnClip, int, "CTFPlayer", "m_nActiveWpnClip"); + NETVAR(m_flKartNextAvailableBoost, float, "CTFPlayer", "m_flKartNextAvailableBoost"); + NETVAR(m_iKartHealth, int, "CTFPlayer", "m_iKartHealth"); + NETVAR(m_iKartState, int, "CTFPlayer", "m_iKartState"); + NETVAR(m_hGrapplingHookTarget, EHANDLE, "CTFPlayer", "m_hGrapplingHookTarget"); + NETVAR(m_hSecondaryLastWeapon, EHANDLE, "CTFPlayer", "m_hSecondaryLastWeapon"); + NETVAR(m_bUsingActionSlot, bool, "CTFPlayer", "m_bUsingActionSlot"); + NETVAR(m_flInspectTime, float, "CTFPlayer", "m_flInspectTime"); + NETVAR(m_flHelpmeButtonPressTime, float, "CTFPlayer", "m_flHelpmeButtonPressTime"); + NETVAR(m_iCampaignMedals, int, "CTFPlayer", "m_iCampaignMedals"); + NETVAR(m_iPlayerSkinOverride, int, "CTFPlayer", "m_iPlayerSkinOverride"); + NETVAR(m_bViewingCYOAPDA, bool, "CTFPlayer", "m_bViewingCYOAPDA"); + + NETVAR_OFF(m_flGravity, float, "CTFPlayer", "m_nWaterLevel", -24); + NETVAR_OFF(m_MoveType, byte, "CTFPlayer", "m_nWaterLevel", -4); + NETVAR_OFF(m_MoveCollide, byte, "CTFPlayer", "m_nWaterLevel", -3); + NETVAR_OFF(m_nWaterType, byte, "CTFPlayer", "m_nWaterLevel", 1); + NETVAR_OFF(m_flInvisibility, float, "CTFPlayer", "m_flInvisChangeCompleteTime", -8); + NETVAR_OFF(m_flTankPressure, float, "CTFPlayer", "m_Shared", 636); + NETVAR_OFF(GetAnimState, CMultiPlayerAnimState*, "CTFPlayer", "m_hItem", -88); + NETVAR_OFF(m_flPrevTauntYaw, float, "CTFPlayer", "m_flTauntYaw", 4); + + VIRTUAL(m_iMaxHealth, int, int(__thiscall*)(void*), this, 107); + + CONDGET(IsSlowed, m_nPlayerCond(), TFCond_Slowed); + CONDGET(IsScoped, m_nPlayerCond(), TFCond_Zoomed); + CONDGET(IsDisguised, m_nPlayerCond(), TFCond_Disguised); + CONDGET(IsCloaked, m_nPlayerCond(), TFCond_Stealthed); + CONDGET(IsUberedCond, m_nPlayerCond(), TFCond_Ubercharged); + CONDGET(IsTaunting, m_nPlayerCond(), TFCond_Taunting); + CONDGET(IsBonked, m_nPlayerCond(), TFCond_Bonked); + CONDGET(IsStunned, m_nPlayerCond(), TFCond_Stunned); + CONDGET(IsCharging, m_nPlayerCond(), TFCond_Charging); + CONDGET(IsOnFire, m_nPlayerCond(), TFCond_OnFire); + CONDGET(IsInJarate, m_nPlayerCond(), TFCond_Jarated); + CONDGET(IsBleeding, m_nPlayerCond(), TFCond_Bleeding); + CONDGET(IsInMilk, m_nPlayerCond(), TFCond_Milked); + CONDGET(IsMegaHealed, m_nPlayerCond(), TFCond_MegaHeal); + CONDGET(IsPhlogUbered, m_nPlayerCondEx(), TFCondEx_PyroCrits); + CONDGET(IsBulletResist, m_nPlayerCondEx(), TFCondEx_BulletCharge); + CONDGET(IsBlastResist, m_nPlayerCondEx(), TFCondEx_ExplosiveCharge); + CONDGET(IsFireResist, m_nPlayerCondEx(), TFCondEx_FireCharge); + CONDGET(IsBulletImmune, m_nPlayerCondEx2(), TFCondEx2_BulletImmune); + CONDGET(IsBlastImmune, m_nPlayerCondEx2(), TFCondEx2_BlastImmune); + CONDGET(IsFireImmune, m_nPlayerCondEx2(), TFCondEx2_FireImmune); + CONDGET(IsAGhost, m_nPlayerCondEx2(), TFCondEx2_HalloweenGhostMode); + CONDGET(IsInBumperKart, m_nPlayerCondEx2(), TFCondEx2_InKart); + CONDGET(IsStrengthRune, m_nPlayerCondEx2(), TFCondEx2_StrengthRune); + CONDGET(IsHasteRune, m_nPlayerCondEx2(), TFCondEx2_HasteRune); + CONDGET(IsRegenRune, m_nPlayerCondEx2(), TFCondEx2_RegenRune); + CONDGET(IsResistRune, m_nPlayerCondEx2(), TFCondEx2_ResistRune); + CONDGET(IsVampireRune, m_nPlayerCondEx2(), TFCondEx2_VampireRune); + CONDGET(IsReflectRune, m_nPlayerCondEx2(), TFCondEx2_ReflectRune); + CONDGET(IsPrecisionRune, m_nPlayerCondEx3(), TFCondEx3_PrecisionRune); + CONDGET(IsAgilityRune, m_nPlayerCondEx3(), TFCondEx3_AgilityRune); + CONDGET(IsKnockoutRune, m_nPlayerCondEx3(), TFCondEx3_KnockoutRune); + CONDGET(IsImbalanceRune, m_nPlayerCondEx3(), TFCondEx3_ImbalanceRune); + CONDGET(IsCritTempRune, m_nPlayerCondEx3(), TFCondEx3_CritboostedTempRune); + CONDGET(IsKingRune, m_nPlayerCondEx3(), TFCondEx3_KingRune); + CONDGET(IsPlagueRune, m_nPlayerCondEx3(), TFCondEx3_PlagueRune); + CONDGET(IsSupernovaRune, m_nPlayerCondEx3(), TFCondEx3_SupernovaRune); + CONDGET(IsBuffedByKing, m_nPlayerCondEx3(), TFCondEx3_KingBuff); + + Vec3 GetEyeAngles() + { + return { m_angEyeAnglesX(), m_angEyeAnglesY(), 0.f }; + } + + Vec3 GetViewOffset() // use on nonlocal players + { + auto getMainOffset = [this]() -> Vec3 + { + if (IsDucking()) + return { 0.f, 0.f, 45.f }; + + switch (m_iClass()) + { + case TF_CLASS_SCOUT: return { 0.f, 0.f, 65.f }; + case TF_CLASS_SOLDIER: return { 0.f, 0.f, 68.f }; + case TF_CLASS_PYRO: return { 0.f, 0.f, 68.f }; + case TF_CLASS_DEMOMAN: return { 0.f, 0.f, 68.f }; + case TF_CLASS_HEAVY: return { 0.f, 0.f, 75.f }; + case TF_CLASS_ENGINEER: return { 0.f, 0.f, 68.f }; + case TF_CLASS_MEDIC: return { 0.f, 0.f, 75.f }; + case TF_CLASS_SNIPER: return { 0.f, 0.f, 75.f }; + case TF_CLASS_SPY: return { 0.f, 0.f, 75.f }; + } + + const Vec3 vOffset = m_vecViewOffset(); + if (vOffset.z) + return vOffset; + + return { 0.f, 0.f, 68.f }; + }; + + const float flSize = (m_vecMins().z + m_vecMaxs().z) / (IsDucking() ? 62 : 82); + return getMainOffset() * flSize; + } + + bool IsFriend() + { + return S::CTFPlayer_IsPlayerOnSteamFriendsList.As()(this, this); + } + + bool InCond(const ETFCond cond) + { + const int iCond = static_cast(cond); + switch (iCond / 32) + { + case 0: + { + const int bit = (1 << iCond); + if ((m_nPlayerCond() & bit) == bit || (_condition_bits() & bit) == bit) + return true; + break; + } + case 1: + { + const int bit = 1 << (iCond - 32); + if ((m_nPlayerCondEx() & bit) == bit) + return true; + break; + } + case 2: + { + const int bit = 1 << (iCond - 64); + if ((m_nPlayerCondEx2() & bit) == bit) + return true; + break; + } + case 3: + { + const int bit = 1 << (iCond - 96); + if ((m_nPlayerCondEx3() & bit) == bit) + return true; + break; + } + case 4: + { + const int bit = 1 << (iCond - 128); + if ((m_nPlayerCondEx4() & bit) == bit) + return true; + break; + } + } + + return false; + } + + bool IsInvisible() + { + if (this->InCond(TF_COND_BURNING) + || this->InCond(TF_COND_BURNING_PYRO) + || this->InCond(TF_COND_MAD_MILK) + || this->InCond(TF_COND_URINE)) + return false; + + return m_flInvisibility() >= 1.f; + } + + float GetInvisPercentage() + { + static auto tf_spy_invis_time = I::CVar->FindVar("tf_spy_invis_time"); + const float flInvisTime = tf_spy_invis_time ? tf_spy_invis_time->GetFloat() : 1.f; + const float GetInvisPercent = Math::RemapValClamped(m_flInvisChangeCompleteTime() - I::GlobalVars->curtime, flInvisTime, 0.f, 0.f, 100.f); + + return GetInvisPercent; + } + + bool IsZoomed() + { + return InCond(TF_COND_ZOOMED); + } + + bool IsInvulnerable() + { + return InCond(TF_COND_INVULNERABLE) + || InCond(TF_COND_INVULNERABLE_CARD_EFFECT) + || InCond(TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED) + || InCond(TF_COND_INVULNERABLE_USER_BUFF) + || InCond(TF_COND_PHASE); + } + + bool IsUbered() + { + return InCond(TF_COND_INVULNERABLE) + || InCond(TF_COND_INVULNERABLE_CARD_EFFECT) + || InCond(TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED) + || InCond(TF_COND_INVULNERABLE_USER_BUFF); + } + + bool IsCritBoosted() + { + return InCond(TF_COND_CRITBOOSTED) + || InCond(TF_COND_CRITBOOSTED_BONUS_TIME) + || InCond(TF_COND_CRITBOOSTED_CARD_EFFECT) + || InCond(TF_COND_CRITBOOSTED_CTF_CAPTURE) + || InCond(TF_COND_CRITBOOSTED_FIRST_BLOOD) + || InCond(TF_COND_CRITBOOSTED_ON_KILL) + || InCond(TF_COND_CRITBOOSTED_PUMPKIN) + || InCond(TF_COND_CRITBOOSTED_RAGE_BUFF) + || InCond(TF_COND_CRITBOOSTED_RUNE_TEMP) + || InCond(TF_COND_CRITBOOSTED_USER_BUFF); + } + + bool IsMiniCritBoosted() + { + return InCond(TF_COND_MINICRITBOOSTED_ON_KILL) + || InCond(TF_COND_NOHEALINGDAMAGEBUFF) + || InCond(TF_COND_ENERGY_BUFF) + /*|| InCond(TF_COND_CRITBOOSTED_DEMO_CHARGE)*/; + } + + bool IsMarked() + { + return InCond(TF_COND_URINE) + || InCond(TF_COND_MARKEDFORDEATH) + || InCond(TF_COND_MARKEDFORDEATH_SILENT); + } + + bool CanAttack() + { + if (!IsAlive() || IsTaunting() || IsBonked() || IsAGhost() || IsInBumperKart() || m_fFlags() & FL_FROZEN) + return false; + + if (m_iClass() == TF_CLASS_SPY) + { + if (m_bFeignDeathReady() && !IsCloaked()) + return false; + + //Invis + static float flTimer = 0.f; + if (IsCloaked()) + { + flTimer = 0.f; + return false; + } + else + { + if (!flTimer) + flTimer = I::GlobalVars->curtime; + + if (flTimer > I::GlobalVars->curtime) + flTimer = 0.f; + + if ((I::GlobalVars->curtime - flTimer) < 2.f) + return false; + } + } + + return true; + } + + CTFWeaponBase* GetWeaponFromSlot(int nSlot) + { + static int nOffset = U::NetVars.GetNetVar("CBaseCombatCharacter", "m_hMyWeapons"); + int hWeapon = *reinterpret_cast(reinterpret_cast(this) + nOffset + nSlot * 4); + return I::ClientEntityList->GetClientEntityFromHandle(hWeapon)->As(); + } + + float TeamFortress_CalculateMaxSpeed(bool bIgnoreSpecialAbility = false) + { + return S::TeamFortress_CalculateMaxSpeed.As()(this, bIgnoreSpecialAbility); + } + + float& m_flLastMovementStunChange() + { + static int nOffset = 7072; + return *reinterpret_cast(reinterpret_cast(this) + nOffset); + } + + float& m_flStunLerpTarget() + { + static int nOffset = 7068; + return *reinterpret_cast(reinterpret_cast(this) + nOffset); + } + + bool& m_bStunNeedsFadeOut() + { + static int nOffset = 7064; + return *reinterpret_cast(reinterpret_cast(this) + nOffset); + } + + void UpdateClientSideAnimation() + { + S::CTFPlayer_UpdateClientSideAnimation.As()(this); + } + + float GetCritMult() + { + return Math::RemapValClamped(static_cast(m_iCritMult()), 0.f, 255.f, 1.f, 4.f); + } + + void UpdateWearables() + { + S::CTFPlayer_UpdateWearables.As()(this); + } + + void ThirdPersonSwitch() + { + reinterpret_cast(S::CTFPlayer_ThirdPersonSwitch())(this); + } +}; + +class CTFRagdoll : public CBaseFlex +{ +public: + NETVAR(m_hPlayer, EHANDLE, "CTFRagdoll", "m_hPlayer") + NETVAR(m_vecRagdollOrigin, Vec3, "CTFRagdoll", "m_vecRagdollOrigin"); + NETVAR(m_iPlayerIndex, int, "CTFRagdoll", "m_iPlayerIndex"); + NETVAR(m_vecForce, Vec3, "CTFRagdoll", "m_vecForce"); + NETVAR(m_vecRagdollVelocity, Vec3, "CTFRagdoll", "m_vecRagdollVelocity"); + NETVAR(m_nForceBone, int, "CTFRagdoll", "m_nForceBone"); + NETVAR(m_bGib, bool, "CTFRagdoll", "m_bGib"); + NETVAR(m_bBurning, bool, "CTFRagdoll", "m_bBurning"); + NETVAR(m_bElectrocuted, bool, "CTFRagdoll", "m_bElectrocuted"); + NETVAR(m_bFeignDeath, bool, "CTFRagdoll", "m_bFeignDeath"); + NETVAR(m_bWasDisguised, bool, "CTFRagdoll", "m_bWasDisguised"); + NETVAR(m_bOnGround, bool, "CTFRagdoll", "m_bOnGround"); + NETVAR(m_bCloaked, bool, "CTFRagdoll", "m_bCloaked"); + NETVAR(m_bBecomeAsh, bool, "CTFRagdoll", "m_bBecomeAsh"); + NETVAR(m_iDamageCustom, int, "CTFRagdoll", "m_iDamageCustom"); + NETVAR(m_iTeam, int, "CTFRagdoll", "m_iTeam"); + NETVAR(m_iClass, int, "CTFRagdoll", "m_iClass"); + NETVAR(m_bGoldRagdoll, bool, "CTFRagdoll", "m_bGoldRagdoll"); + NETVAR(m_bIceRagdoll, bool, "CTFRagdoll", "m_bIceRagdoll"); + NETVAR(m_bCritOnHardHit, bool, "CTFRagdoll", "m_bCritOnHardHit"); + NETVAR(m_flHeadScale, float, "CTFRagdoll", "m_flHeadScale"); + NETVAR(m_flTorsoScale, float, "CTFRagdoll", "m_flTorsoScale"); + NETVAR(m_flHandScale, float, "CTFRagdoll", "m_flHandScale"); + + NETVAR_OFF(m_bDissolving, bool, "CTFRagdoll", "m_bFeignDeath", -1); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CTFPlayerResource.h b/Amalgam/src/SDK/Definitions/Main/CTFPlayerResource.h new file mode 100644 index 0000000..1d56663 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CTFPlayerResource.h @@ -0,0 +1,165 @@ +#pragma once +#include "../Misc/CPlayerResource.h" + +enum MM_PlayerConnectionState_t +{ + MM_DISCONNECTED = 0, + MM_CONNECTED, + MM_CONNECTING, + MM_LOADING, + MM_WAITING_FOR_PLAYER +}; + +enum ETFStreak +{ + kTFStreak_Kills = 0, + kTFStreak_KillsAll = 1, + kTFStreak_Ducks = 2, + kTFStreak_Duck_levelup = 3, + kTFStreak_COUNT = 4 +}; + +class CTFPlayerResource : public CPlayerResource +{ +public: + NETVAR(m_iTotalScore, void*, "CTFPlayerResource", "m_iTotalScore"); + NETVAR(m_iMaxHealth, void*, "CTFPlayerResource", "m_iMaxHealth"); + NETVAR(m_iMaxBuffedHealth, void*, "CTFPlayerResource", "m_iMaxBuffedHealth"); + NETVAR(m_iPlayerClass, void*, "CTFPlayerResource", "m_iPlayerClass"); + NETVAR(m_bArenaSpectator, void*, "CTFPlayerResource", "m_bArenaSpectator"); + NETVAR(m_iActiveDominations, void*, "CTFPlayerResource", "m_iActiveDominations"); + NETVAR(m_flNextRespawnTime, void*, "CTFPlayerResource", "m_flNextRespawnTime"); + NETVAR(m_iChargeLevel, void*, "CTFPlayerResource", "m_iChargeLevel"); + NETVAR(m_iDamage, void*, "CTFPlayerResource", "m_iDamage"); + NETVAR(m_iDamageAssist, void*, "CTFPlayerResource", "m_iDamageAssist"); + NETVAR(m_iDamageBoss, void*, "CTFPlayerResource", "m_iDamageBoss"); + NETVAR(m_iHealing, void*, "CTFPlayerResource", "m_iHealing"); + NETVAR(m_iHealingAssist, void*, "CTFPlayerResource", "m_iHealingAssist"); + NETVAR(m_iDamageBlocked, void*, "CTFPlayerResource", "m_iDamageBlocked"); + NETVAR(m_iCurrencyCollected, void*, "CTFPlayerResource", "m_iCurrencyCollected"); + NETVAR(m_iBonusPoints, void*, "CTFPlayerResource", "m_iBonusPoints"); + NETVAR(m_iPlayerLevel, void*, "CTFPlayerResource", "m_iPlayerLevel"); + NETVAR(m_iStreaks, void*, "CTFPlayerResource", "m_iStreaks"); + NETVAR(m_iUpgradeRefundCredits, void*, "CTFPlayerResource", "m_iUpgradeRefundCredits"); + NETVAR(m_iBuybackCredits, void*, "CTFPlayerResource", "m_iBuybackCredits"); + NETVAR(m_iPartyLeaderRedTeamIndex, int, "CTFPlayerResource", "m_iPartyLeaderRedTeamIndex"); + NETVAR(m_iPartyLeaderBlueTeamIndex, int, "CTFPlayerResource", "m_iPartyLeaderBlueTeamIndex"); + NETVAR(m_iEventTeamStatus, int, "CTFPlayerResource", "m_iEventTeamStatus"); + NETVAR(m_iPlayerClassWhenKilled, void*, "CTFPlayerResource", "m_iPlayerClassWhenKilled"); + NETVAR(m_iConnectionState, void*, "CTFPlayerResource", "m_iConnectionState"); + NETVAR(m_flConnectTime, void*, "CTFPlayerResource", "m_flConnectTime"); + + int GetPing(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iPing"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int GetKills(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iScore"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int GetDeaths(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iDeaths"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + bool GetConnected(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_bConnected"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx); + } + + int GetTeam(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iTeam"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + bool IsAlive(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_bAlive"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx); + } + + int GetHealth(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iHealth"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + unsigned GetAccountID(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iAccountID"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + bool GetValid(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_bValid"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx); + } + + int GetUserID(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iUserID"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + const char* GetPlayerName(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iPing") - 816; + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 8); + } + + int GetScore(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iTotalScore"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int GetLevel(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iPlayerLevel"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int GetDamage(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iDamage"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int GetClass(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iPlayerClass"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int GetMaxHealth(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iMaxHealth"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + int* GetStreaks(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_iStreaks"); + return reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + float GetConnectionTime(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_flConnectTime"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } + + float GetNextRespawnTime(int idx) + { + static int nOffset = U::NetVars.GetNetVar("CTFPlayerResource", "m_flNextRespawnTime"); + return *reinterpret_cast(std::uintptr_t(this) + nOffset + idx * 4); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CTFWeaponBase.cpp b/Amalgam/src/SDK/Definitions/Main/CTFWeaponBase.cpp new file mode 100644 index 0000000..91242cb --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CTFWeaponBase.cpp @@ -0,0 +1,638 @@ +#include "CTFWeaponBase.h" +#include "../../Helpers/Draw/Draw.h" + +#define ReturnTexture(string) { static CHudTexture* pTexture = H::Draw.GetIcon(string); return pTexture; } + +CHudTexture* CTFWeaponBase::GetWeaponIcon() // wow this is stupid +{ + switch (m_iItemDefinitionIndex()) + { + case 13: + case 200: + case 669: + case 799: + case 808: + case 888: + case 897: + case 906: + case 915: + case 964: + case 973: + case 15002: + case 15015: + case 15021: + case 15029: + case 15036: + case 15053: + case 15065: + case 15069: + case 15106: + case 15107: + case 15108: + case 15131: + case 15151: + case 15157: + ReturnTexture("d_scattergun"); + case 45: + case 1078: + ReturnTexture("d_force_a_nature"); + case 220: + ReturnTexture("d_shortstop"); + case 448: + ReturnTexture("d_soda_popper"); + case 772: + ReturnTexture("d_pep_brawlerblaster"); + case 1103: + ReturnTexture("d_back_scatter"); + case 22: + case 23: + case 209: + case 15013: + case 15018: + case 15035: + case 15041: + case 15046: + case 15056: + case 15060: + case 15061: + case 15100: + case 15101: + case 15102: + case 15126: + case 15148: + ReturnTexture("d_pistol"); + case 46: + ReturnTexture("d_taunt_scout"); //Bonk has no icon but there is a taunt kill that says bonk so we'll use that + case 1145: + ReturnTexture("d_taunt_scout"); //Bonk has no icon but there is a taunt kill that says bonk so we'll use that + case 160: + ReturnTexture("d_maxgun"); + case 294: + ReturnTexture("d_maxgun"); + case 449: + ReturnTexture("d_the_winger"); + case 773: + ReturnTexture("d_pep_pistol"); + case 812: + ReturnTexture("d_guillotine"); + case 833: + ReturnTexture("d_guillotine"); + case 30666: + ReturnTexture("d_the_capper"); + case 0: + ReturnTexture("d_bat"); + case 190: + ReturnTexture("d_bat"); + case 660: + ReturnTexture("d_bat"); + case 44: + ReturnTexture("d_sandman"); + case 221: + ReturnTexture("d_holymackerel"); + case 999: + ReturnTexture("d_holymackerel"); + case 317: + ReturnTexture("d_candycane"); + case 325: + ReturnTexture("d_bostonbasher"); + case 349: + ReturnTexture("d_lavabat"); + case 355: + ReturnTexture("d_warfan"); + case 450: + ReturnTexture("d_atomizer"); + case 452: + ReturnTexture("d_scout_sword"); + case 474: + ReturnTexture("d_nonnonviolent_protest"); + case 572: + ReturnTexture("d_unarmed_combat"); + case 648: + ReturnTexture("d_wrap_assassin"); + case 939: + ReturnTexture("d_skull"); + case 880: + ReturnTexture("d_freedom_staff"); + case 954: + ReturnTexture("d_memory_maker"); //Scout_t_TheMemoryMaker = 954, killme + case 1013: + ReturnTexture("d_ham_shank"); + case 1123: + ReturnTexture("d_necro_smasher"); + case 1127: + ReturnTexture("d_crossing_guard");//dunno if this is right but i dont have the weapon so + case 30667: + ReturnTexture("d_batsaber"); + case 30758: + ReturnTexture("d_prinny_machete"); + case 18: + case 205: + case 800: + case 809: + case 889: + case 898: + case 907: + case 916: + case 965: + case 974: + case 15006: + case 15014: + case 15028: + case 15043: + case 15052: + case 15057: + case 15081: + case 15104: + case 15105: + case 15130: + case 15150: + case 237:// rocket jumper :| + case 658: + ReturnTexture("d_tf_projectile_rocket"); + case 127: + ReturnTexture("d_rocketlauncher_directhit"); + case 228: + ReturnTexture("d_blackbox"); + case 1085: + ReturnTexture("d_blackbox"); + case 414: + ReturnTexture("d_liberty_launcher"); + case 441: + ReturnTexture("d_cow_mangler"); + case 513: + ReturnTexture("d_quake_rl"); + case 730: + ReturnTexture("d_dumpster_device"); + case 1104: + ReturnTexture("d_airstrike"); + case 10: + case 199: + case 15003: + case 15016: + case 15044: + case 15047: + case 15085: + case 15109: + case 15132: + case 15133: + case 15152: + case 1141: + case 12: + case 11: + case 9: + ReturnTexture("d_shotgun_soldier"); + case 415: + ReturnTexture("d_reserve_shooter"); + case 442: + ReturnTexture("d_righteous_bison"); + case 1153: + ReturnTexture("d_panic_attack"); + case 6: + ReturnTexture("d_shovel"); + case 196: + ReturnTexture("d_shovel"); + case 128: + ReturnTexture("d_pickaxe"); + case 154: + ReturnTexture("d_paintrain"); + case 357: + ReturnTexture("d_demokatana"); + case 416: + ReturnTexture("d_market_gardener"); + case 447: + ReturnTexture("d_disciplinary_action"); + case 775: + ReturnTexture("d_pickaxe_escape"); + case 21: + case 208: + case 659: + case 798: + case 807: + case 887: + case 896: + case 905: + case 914: + case 963: + case 972: + case 15005: + case 15017: + case 15030: + case 15034: + case 15049: + case 15054: + case 15066: + case 15067: + case 15068: + case 15089: + case 15090: + case 15115: + case 15141: + ReturnTexture("d_flamethrower"); + case 40: + case 1146: + ReturnTexture("d_backburner"); + case 215: + ReturnTexture("d_degreaser"); + case 594: + ReturnTexture("d_phlogistinator"); + case 741: + ReturnTexture("d_rainblower"); + case 1178: + ReturnTexture("d_dragons_fury"); + case 39: + case 1081: + ReturnTexture("d_flaregun"); + case 740: + ReturnTexture("d_scorch_shot"); + case 595: + ReturnTexture("d_manmelter"); + case 351: + ReturnTexture("d_detonator"); + case 1179: + ReturnTexture("d_rocketpack"); + case 2: + case 192: + ReturnTexture("d_fireaxe"); + case 38: + case 1000: + ReturnTexture("d_axtinguisher"); + case 153: + ReturnTexture("d_sledgehammer"); + case 214: + ReturnTexture("d_powerjack"); + case 326: + ReturnTexture("d_back_scratcher"); + case 348: + ReturnTexture("d_lava_axe"); + case 457: + ReturnTexture("d_mailbox"); + case 466: + ReturnTexture("d_the_maul"); + case 593: + ReturnTexture("d_thirddegree"); + case 739: + ReturnTexture("d_lollichop"); + case 813: + case 834: + ReturnTexture("d_annihilator"); + case 1181: + ReturnTexture("d_hot_hand"); + case 19: + case 206: + case 15077: + case 15079: + case 15091: + case 15092: + case 15116: + case 15117: + case 15142: + case 15158: + case 1007: + ReturnTexture("d_tf_projectile_pipe"); + case 308: + ReturnTexture("d_loch_n_load"); + case 996: + ReturnTexture("d_loose_cannon"); + case 1151: + ReturnTexture("d_iron_bomber"); + case 20: + case 207: + case 661: + case 797: + case 806: + case 886: + case 895: + case 904: + case 913: + case 962: + case 971: + case 265: + case 15009: + case 15012: + case 15024: + case 15038: + case 15045: + case 15048: + case 15082: + case 15083: + case 15084: + case 15113: + case 15137: + case 15138: + case 15155: + ReturnTexture("d_tf_projectile_pipe_remote"); + case 130: + ReturnTexture("d_sticky_resistance"); + case 131: + ReturnTexture("d_demoshield"); + case 1144: + ReturnTexture("d_demoshield"); + case 1099: + ReturnTexture("d_tide_turner"); + case 406: + ReturnTexture("d_splendid_screen"); + case 1150: + ReturnTexture("d_quickiebomb_launcher"); + case 1: + case 191: + ReturnTexture("d_bottle"); + case 132: + ReturnTexture("d_sword"); + case 1082: + ReturnTexture("d_sword"); + case 172: + ReturnTexture("d_battleaxe"); + case 266: + ReturnTexture("d_headtaker"); + case 307: + ReturnTexture("d_ullapool_caber_explosion"); + case 327: + ReturnTexture("d_claidheamohmor"); + case 404: + ReturnTexture("d_persian_persuader"); + case 482: + ReturnTexture("d_nessieclub"); + case 609: + ReturnTexture("d_scotland_shard"); + case 15: + case 202: + case 654: + case 793: + case 802: + case 41: + case 312: + case 424: + case 882: + case 891: + case 900: + case 909: + case 958: + case 967: + case 15004: + case 15020: + case 15026: + case 15031: + case 15040: + case 15055: + case 15086: + case 15087: + case 15088: + case 15098: + case 15099: + case 15123: + case 15124: + case 15125: + case 15147: + ReturnTexture("d_minigun"); + case 811: + ReturnTexture("d_long_heatmaker"); + case 832: + ReturnTexture("d_long_heatmaker"); + case 850: + ReturnTexture("d_iron_curtain"); + case 298: + ReturnTexture("d_iron_curtain"); + case 425: + ReturnTexture("d_family_business"); + case 5: + case 195: + ReturnTexture("d_fists"); + case 43: + ReturnTexture("d_gloves"); + case 239: + ReturnTexture("d_gloves_running_urgently"); + case 1084: + ReturnTexture("d_gloves_running_urgently"); + case 1184: + ReturnTexture("d_gloves_running_urgently"); + case 310: + ReturnTexture("d_warrior_spirit"); + case 331: + ReturnTexture("d_steel_fists"); + case 426: + ReturnTexture("d_eviction_notice"); + case 587: + ReturnTexture("d_apocofists"); + case 656: + ReturnTexture("d_holiday_punch"); + case 1100: + ReturnTexture("d_bread_bite"); + case 141: + ReturnTexture("d_frontier_justice"); + case 1004: + ReturnTexture("d_frontier_justice"); + case 527: + ReturnTexture("d_widowmaker"); + case 588: + ReturnTexture("d_pomson"); + case 997: + ReturnTexture("d_rescue_ranger"); + case 140: + ReturnTexture("d_wrangler_kill"); + case 1086: + ReturnTexture("d_wrangler_kill"); + case 528: + ReturnTexture("d_short_circuit"); + case 30668: + ReturnTexture("d_giger_counter"); + case 7: + case 197: + case 662: + case 795: + case 804: + case 884: + case 893: + case 902: + case 911: + case 960: + case 969: + case 15073: + case 15074: + case 15075: + case 15139: + case 15140: + case 15114: + case 15156: + case 169: + ReturnTexture("d_wrench"); + case 142: + ReturnTexture("d_robot_arm"); + case 155: + ReturnTexture("d_southern_hospitality"); + case 329: + ReturnTexture("d_wrench_jag"); + case 589: + ReturnTexture("d_eureka_effect"); + case 17: + case 204: + ReturnTexture("d_syringegun_medic"); + case 36: + ReturnTexture("d_blutsauger"); + case 305: + case 1079: + ReturnTexture("d_crusaders_crossbow"); + case 412: + ReturnTexture("d_proto_syringe"); + case 8: + case 198: + case 1143: + ReturnTexture("d_bonesaw"); + case 37: + ReturnTexture("d_ubersaw"); + case 1003: + ReturnTexture("d_ubersaw"); + case 173: + ReturnTexture("d_battleneedle"); + case 304: + ReturnTexture("d_amputator"); + case 413: + ReturnTexture("d_solemnvow"); + case 14: + case 201: + case 664: + case 792: + case 801: + case 881: + case 890: + case 899: + case 908: + case 957: + case 966: + case 15000: + case 15007: + case 15019: + case 15023: + case 15033: + case 15059: + case 15070: + case 15071: + case 15072: + case 15111: + case 15112: + case 15135: + case 15136: + case 851: + ReturnTexture("d_sniperrifle"); + case 56: + ReturnTexture("d_tf_projectile_arrow"); + case 1005: + ReturnTexture("d_tf_projectile_arrow"); + case 1092: + ReturnTexture("d_tf_projectile_arrow"); + case 30665: + ReturnTexture("d_shooting_star"); + case 1098: + ReturnTexture("d_the_classic"); + case 752: + ReturnTexture("d_pro_rifle"); + case 526: + ReturnTexture("d_machina"); + case 402: + ReturnTexture("d_bazaar_bargain"); + case 230: + ReturnTexture("d_sydney_sleeper"); + case 16: + case 203: + case 1149: + case 15001: + case 15022: + case 15032: + case 15037: + case 15058: + case 15076: + case 15110: + case 15134: + case 15153: + ReturnTexture("d_smg"); + case 3: + ReturnTexture("d_club"); + case 193: + ReturnTexture("d_club"); + case 171: + ReturnTexture("d_tribalkukri"); + case 232: + ReturnTexture("d_bushwacka"); + case 401: + ReturnTexture("d_shahanshah"); + case 24: + case 210: + case 1142: + case 15011: + case 15027: + case 15042: + case 15051: + case 15062: + case 15063: + case 15064: + case 15103: + case 15128: + case 15129: + case 15149: + ReturnTexture("d_revolver"); + case 61: + ReturnTexture("d_ambassador"); + case 1006: + ReturnTexture("d_ambassador"); + case 161: + ReturnTexture("d_samrevolver"); + case 224: + ReturnTexture("d_letranger"); + case 460: + ReturnTexture("d_enforcer"); + case 525: + ReturnTexture("d_diamondback"); + case 735: + ReturnTexture("d_psapper"); + case 736: + ReturnTexture("d_psapper"); + case 1080: + ReturnTexture("d_psapper"); + case 810: + ReturnTexture("d_recorder"); + case 831: + ReturnTexture("d_recorder"); + case 933: + ReturnTexture("d_psapper"); // :( + case 1102: + ReturnTexture("d_psapper"); // :( + case 225: + ReturnTexture("d_eternal_reward"); + case 356: + ReturnTexture("d_kunai"); + case 461: + ReturnTexture("d_big_earner"); + case 574: + ReturnTexture("d_voodoo_pin"); + case 638: + ReturnTexture("d_sharp_dresser"); + case 649: + ReturnTexture("d_spy_cicle"); + case 4: + case 194: + case 665: + case 794: + case 803: + case 883: + case 892: + case 901: + case 910: + case 959: + case 968: + case 15094: + case 15095: + case 15096: + case 15118: + case 15119: + case 15143: + case 15144: + case 727: // :( + ReturnTexture("d_knife"); + case 27: + ReturnTexture("hud_spy_disguise_menu_icon"); + case 264: + ReturnTexture("d_fryingpan"); + case 1071: + ReturnTexture("d_fryingpan"); + } + ReturnTexture("d_skull"); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CTFWeaponBase.h b/Amalgam/src/SDK/Definitions/Main/CTFWeaponBase.h new file mode 100644 index 0000000..449fd48 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CTFWeaponBase.h @@ -0,0 +1,442 @@ +#pragma once +#include "CBaseCombatWeapon.h" +#include "CBasePlayer.h" + +MAKE_SIGNATURE(CTFWeaponBase_GetSpreadAngles, "client.dll", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 0F 29 74 24 ? 48 8B DA 48 8B F9 E8 ? ? ? ? 48 8B C8", 0x0); +MAKE_SIGNATURE(CTFWeaponBase_UpdateAllViewmodelAddons, "client.dll", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B D9 E8 ? ? ? ? 48 8B F8", 0x0); +MAKE_SIGNATURE(CTFWeaponBaseMelee_CalcIsAttackCriticalHelper, "client.dll", "40 57 48 83 EC ? 48 8B 05 ? ? ? ? 48 8B F9 83 78 ? ? 75", 0x0); +MAKE_SIGNATURE(CTFWeaponBase_CalcIsAttackCriticalHelper, "client.dll", "48 89 5C 24 ? 55 56 57 48 81 EC ? ? ? ? 0F 29 74 24", 0x0); +MAKE_SIGNATURE(CTFWeaponBase_GetAppropriateWorldOrViewModel, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B D9 E8 ? ? ? ? 48 8B C8 C7 44 24 ? ? ? ? ? 4C 8D 0D ? ? ? ? 33 D2 4C 8D 05 ? ? ? ? E8 ? ? ? ? 48 8B F8 48 85 C0 74 ? 48 8B CB", 0x0); +MAKE_SIGNATURE(CTFWeaponBaseGun_GetWeaponSpread, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 4C 63 91", 0x0); + +//credits: KGB (all weapon info stuff below) +typedef unsigned short WEAPON_FILE_INFO_HANDLE; + +typedef enum +{ + EMPTY, + SINGLE, + SINGLE_NPC, + WPN_DOUBLE, + DOUBLE_NPC, + BURST, + RELOAD, + RELOAD_NPC, + MELEE_MISS, + MELEE_HIT, + MELEE_HIT_WORLD, + SPECIAL1, + SPECIAL2, + SPECIAL3, + TAUNT, + DEPLOY, + NUM_SHOOT_SOUND_TYPES, +} WeaponSound_t; + +#define MAX_SHOOT_SOUNDS 16 +#define MAX_WEAPON_STRING 80 +#define MAX_WEAPON_PREFIX 16 +#define MAX_WEAPON_AMMO_NAME 32 + +class FileWeaponInfo_t +{ +public: + void* m_pVtable; + + 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 +}; + +struct WeaponData_t +{ + int m_nDamage; + int m_nBulletsPerShot; + float m_flRange; + float m_flSpread; + float m_flPunchAngle; + float m_flTimeFireDelay; // Time to delay between firing + float m_flTimeIdle; // Time to idle after firing + float m_flTimeIdleEmpty; // Time to idle after firing last bullet in clip + float m_flTimeReloadStart; // Time to start into a reload (ie. shotgun) + float m_flTimeReload; // Time to reload + bool m_bDrawCrosshair; // Should the weapon draw a crosshair + int m_iProjectile; // The type of projectile this mode fires + int m_iAmmoPerShot; // How much ammo each shot consumes + float m_flProjectileSpeed; // Start speed for projectiles (nail, etc.); NOTE: union with something non-projectile + float m_flSmackDelay; // how long after swing should damage happen for melee weapons + bool m_bUseRapidFireCrits; + + void Init() + { + m_nDamage = 0; + m_nBulletsPerShot = 0; + m_flRange = 0.f; + m_flSpread = 0.f; + m_flPunchAngle = 0.f; + m_flTimeFireDelay = 0.f; + m_flTimeIdle = 0.f; + m_flTimeIdleEmpty = 0.f; + m_flTimeReloadStart = 0.f; + m_flTimeReload = 0.f; + m_iProjectile = 0; + m_iAmmoPerShot = 0; + m_flProjectileSpeed = 0.f; + m_flSmackDelay = 0.f; + m_bUseRapidFireCrits = false; + }; +}; + +class CTFWeaponInfo : public FileWeaponInfo_t +{ +public: + WeaponData_t m_WeaponData[2]; //0x06F8 + int m_iWeaponType; //0x0778 + int m_bGrenade; //0x077C + float m_flDamageRadius; //0x0780 + float m_flPrimerTime; //0x0784 + bool m_bLowerWeapon; //0x0788 + bool m_bSuppressGrenTimer; //0x0789 + bool m_bHasTeamSkins_Viewmodel; //0x078A + bool m_bHasTeamSkins_Worldmodel; //0x078B + char m_szMuzzleFlashModel[128]; //0x078C + float m_flMuzzleFlashModelDuration; //0x080C + char m_szMuzzleFlashParticleEffect[128]; //0x0810 + char m_szTracerEffect[128]; //0x0890 + bool m_bDoInstantEjectBrass; //0x0910 + char m_szBrassModel[128]; //0x0911 + char m_szExplosionSound[128]; //0x0991 + char m_szExplosionEffect[128]; //0x0A11 + char m_szExplosionPlayerEffect[128]; //0x0A91 + char m_szExplosionWaterEffect[128]; //0x0B11 + bool m_bDontDrop; //0x0B91 + + WeaponData_t const& GetWeaponData(int iWeapon) const { return m_WeaponData[iWeapon]; } +}; + +class CTFWeaponBase : public CBaseCombatWeapon +{ +public: + NETVAR(m_bLowered, bool, "CTFWeaponBase", "m_bLowered"); + NETVAR(m_iReloadMode, int, "CTFWeaponBase", "m_iReloadMode"); + NETVAR(m_bResetParity, bool, "CTFWeaponBase", "m_bResetParity"); + NETVAR(m_bReloadedThroughAnimEvent, bool, "CTFWeaponBase", "m_bReloadedThroughAnimEvent"); + NETVAR(m_bDisguiseWeapon, bool, "CTFWeaponBase", "m_bDisguiseWeapon"); + NETVAR(m_flLastCritCheckTime, float, "CTFWeaponBase", "m_flLastCritCheckTime"); + NETVAR(m_flReloadPriorNextFire, float, "CTFWeaponBase", "m_flReloadPriorNextFire"); + NETVAR(m_flLastFireTime, float, "CTFWeaponBase", "m_flLastFireTime"); + NETVAR(m_flEffectBarRegenTime, float, "CTFWeaponBase", "m_flEffectBarRegenTime"); + NETVAR(m_flObservedCritChance, float, "CTFWeaponBase", "m_flObservedCritChance"); + NETVAR(m_flEnergy, float, "CTFWeaponBase", "m_flEnergy"); + NETVAR(m_hExtraWearable, EHANDLE, "CTFWeaponBase", "m_hExtraWearable"); + NETVAR(m_hExtraWearableViewModel, EHANDLE, "CTFWeaponBase", "m_hExtraWearableViewModel"); + NETVAR(m_bBeingRepurposedForTaunt, bool, "CTFWeaponBase", "m_bBeingRepurposedForTaunt"); + NETVAR(m_nKillComboClass, int, "CTFWeaponBase", "m_nKillComboClass"); + NETVAR(m_nKillComboCount, int, "CTFWeaponBase", "m_nKillComboCount"); + NETVAR(m_flInspectAnimEndTime, float, "CTFWeaponBase", "m_flInspectAnimEndTime"); + NETVAR(m_nInspectStage, int, "CTFWeaponBase", "m_nInspectStage"); + NETVAR(m_iConsecutiveShots, int, "CTFWeaponBase", "m_iConsecutiveShots"); + NETVAR(m_iItemDefinitionIndex, int, "CEconEntity", "m_iItemDefinitionIndex"); + + NETVAR_OFF(GetWeaponInfo, CTFWeaponInfo*, "CTFWeaponBase", "m_flEffectBarRegenTime", 16); + NETVAR_OFF(m_flSmackTime, float, "CTFWeaponBase", "m_nInspectStage", 28); + NETVAR_OFF(m_flCritTokenBucket, float, "CTFWeaponBase", "m_iReloadMode", -244); + NETVAR_OFF(m_nCritChecks, int, "CTFWeaponBase", "m_iReloadMode", -240); + NETVAR_OFF(m_nCritSeedRequests, int, "CTFWeaponBase", "m_iReloadMode", -236); + NETVAR_OFF(m_flCritTime, float, "CTFWeaponBase", "m_flLastCritCheckTime", -4); + NETVAR_OFF(m_iCurrentSeed, int, "CTFWeaponBase", "m_flLastCritCheckTime", 8); + NETVAR_OFF(m_flLastRapidFireCritCheckTime, float, "CTFWeaponBase", "m_flLastCritCheckTime", 12); + + VIRTUAL(m_iSlot, int, int(__thiscall*)(void*), this, 330); + VIRTUAL(m_iWeaponID, int, int(__thiscall*)(void*), this, 381); + VIRTUAL(m_iDamageType, int, int(__thiscall*)(void*), this, 382); + VIRTUAL(m_bEnergyWeapon, bool, bool(__thiscall*)(void*), this, 432); + + OFFSET(m_iWeaponMode, int, 996); + + float GetSwingRange(CBaseEntity* pLocal) + { + return reinterpret_cast(U::Memory.GetVFunc(this, 455))(pLocal); + } + + float GetSwingRange() + { + return m_iWeaponID() == TF_WEAPON_SWORD ? 72.f : 48.f; + } + + bool CanFireCriticalShot(CBasePlayer* pOwner, bool bIsHeadshot = false) + { + bool bOut = false; + + if (pOwner) + { + int& iFOV = pOwner->m_iFOV(), nFovBackup = iFOV; + iFOV = 70; + bOut = reinterpret_cast(U::Memory.GetVFunc(this, 425))(this, bIsHeadshot, nullptr); + iFOV = nFovBackup; + } + + return bOut; + } + + bool CanPrimaryAttack(CBasePlayer* pOwner) + { + bool bOut = false; + + if (pOwner) + { + float flCurTime = static_cast(pOwner->m_nTickBase()) * I::GlobalVars->interval_per_tick; + bOut = m_flNextPrimaryAttack() <= flCurTime && pOwner->m_flNextAttack() <= flCurTime; + } + + return bOut; + } + + bool CanSecondaryAttack(CBasePlayer* pOwner) + { + bool bOut = false; + + if (pOwner) + { + float flCurTime = static_cast(pOwner->m_nTickBase()) * I::GlobalVars->interval_per_tick; + bOut = m_flNextSecondaryAttack() <= flCurTime && pOwner->m_flNextAttack() <= flCurTime; + } + + return bOut; + } + + bool HasPrimaryAmmoForShot() + { + if (m_bEnergyWeapon()) + return m_flEnergy() > 0.f; + + int nClip1 = m_iClip1(); + + if (nClip1 == -1) + { + if (auto pOwner = m_hOwnerEntity().Get()) + { + int nAmmoCount = pOwner->As()->GetAmmoCount(m_iPrimaryAmmoType()); + + if (m_iItemDefinitionIndex() == Engi_m_TheWidowmaker) + return nAmmoCount > 29; + + return nAmmoCount > 0; + } + } + + return nClip1 > 0; + } + + bool IsInReload() + { + static int nOffset = U::NetVars.GetNetVar("CBaseCombatWeapon", "m_flNextPrimaryAttack") + 12; + bool m_bInReload = *reinterpret_cast(std::uintptr_t(this) + nOffset); + return (m_bInReload || m_iReloadMode() != 0); + } + + bool IsStreamingWeapon() + { + auto pWeaponInfo = GetWeaponInfo(); + return pWeaponInfo && pWeaponInfo->GetWeaponData(0).m_bUseRapidFireCrits; + } + + bool CanHeadShot(CBasePlayer* pOwner) + { + bool bOut = false; + + if (pOwner) + bOut = (m_iDamageType() & DMG_USE_HITLOCATIONS) && CanFireCriticalShot(pOwner, true); + + return bOut; + } + + bool AmbassadorCanHeadshot() + { + if ((m_iItemDefinitionIndex() == Spy_m_TheAmbassador || m_iItemDefinitionIndex() == Spy_m_FestiveAmbassador) && I::GlobalVars->curtime - m_flLastFireTime() <= 1.f) + return false; + return true; + } + + void GetProjectileFireSetup(void* pPlayer, Vector vecOffset, Vector* vecSrc, QAngle* angForward, bool bHitTeammates = true, float flEndDist = 2000.f) + { + using fn = void(__thiscall*)(CTFWeaponBase*, void*, Vector, Vector*, QAngle*, bool, float); + reinterpret_cast(U::Memory.GetVFunc(this, 399))(this, pPlayer, vecOffset, vecSrc, angForward, bHitTeammates, flEndDist); + } + + void GetSpreadAngles(Vec3& out) + { + S::CTFWeaponBase_GetSpreadAngles.As()(this, out); + } + + Vec3 GetSpreadAngles() + { + Vec3 vOut; + GetSpreadAngles(vOut); + return vOut; + } + + void UpdateAllViewmodelAddons() + { + return S::CTFWeaponBase_UpdateAllViewmodelAddons.As()(this); + } + + float ApplyFireDelay(float flDelay) + { + return reinterpret_cast(U::Memory.GetVFunc(this, 407))(this, flDelay); + } + + bool CalcIsAttackCriticalHelperMelee() + { + return S::CTFWeaponBaseMelee_CalcIsAttackCriticalHelper.As()(this); + } + + bool CalcIsAttackCriticalHelper() + { + return S::CTFWeaponBase_CalcIsAttackCriticalHelper.As()(this); + } + + CBaseAnimating* GetAppropriateWorldOrViewModel() + { + return S::CTFWeaponBase_GetAppropriateWorldOrViewModel.As()(this); + } + + float GetWeaponSpread() + { + return S::CTFWeaponBaseGun_GetWeaponSpread.As()(this); + } + + CHudTexture* GetWeaponIcon(); +}; + +class CTFKnife : public CTFWeaponBase +{ +public: + NETVAR(m_bReadyToBackstab, bool, "CTFKnife", "m_bReadyToBackstab"); + NETVAR(m_bKnifeExists, bool, "CTFKnife", "m_bKnifeExists"); + NETVAR(m_flKnifeRegenerateDuration, float, "CTFKnife", "m_flKnifeRegenerateDuration"); + NETVAR(m_flKnifeMeltTimestamp, float, "CTFKnife", "m_flKnifeMeltTimestamp"); +}; + +class CTFMinigun : public CTFWeaponBase +{ +public: + NETVAR(m_iWeaponState, int, "CTFMinigun", "m_iWeaponState"); + NETVAR(m_bCritShot, bool, "CTFMinigun", "m_bCritShot"); +}; + +class CWeaponMedigun : public CTFWeaponBase +{ +public: + NETVAR(m_hHealingTarget, EHANDLE, "CWeaponMedigun", "m_hHealingTarget"); + NETVAR(m_bHealing, bool, "CWeaponMedigun", "m_bHealing"); + NETVAR(m_bAttacking, bool, "CWeaponMedigun", "m_bAttacking"); + NETVAR(m_bChargeRelease, bool, "CWeaponMedigun", "m_bChargeRelease"); + NETVAR(m_bHolstered, bool, "CWeaponMedigun", "m_bHolstered"); + NETVAR(m_nChargeResistType, int, "CWeaponMedigun", "m_nChargeResistType"); + NETVAR(m_hLastHealingTarget, EHANDLE, "CWeaponMedigun", "m_hLastHealingTarget"); + NETVAR(m_flChargeLevel, float, "CWeaponMedigun", "m_flChargeLevel"); + + int GetMedigunType() + { + int iMode = 0; + iMode = static_cast(SDK::AttribHookValue(static_cast(iMode), "set_weapon_mode", this)); + return iMode; + } + + MedigunChargeTypes GetChargeType() + { + int iTmp = MEDIGUN_CHARGE_INVULN; + iTmp = static_cast(SDK::AttribHookValue(static_cast(iTmp), "set_charge_type", this)); + + if (GetMedigunType() == MEDIGUN_RESIST) + iTmp += m_nChargeResistType(); + + return MedigunChargeTypes(iTmp); + } + + medigun_resist_types_t GetResistType() + { + int nCurrentActiveResist = (GetChargeType() - MEDIGUN_CHARGE_BULLET_RESIST); + nCurrentActiveResist = nCurrentActiveResist % MEDIGUN_NUM_RESISTS; + return medigun_resist_types_t(nCurrentActiveResist); + } +}; + +class CTFPipebombLauncher : public CTFWeaponBase +{ +public: + NETVAR(m_iPipebombCount, int, "CTFPipebombLauncher", "m_iPipebombCount"); + NETVAR(m_flChargeBeginTime, float, "CTFPipebombLauncher", "m_flChargeBeginTime"); + + NETVAR_OFF(m_Pipebombs, CUtlVector>, "CTFPipebombLauncher", "m_flChargeBeginTime", -28); +}; + +class CTFSniperRifle : public CTFWeaponBase +{ +public: + NETVAR(m_flChargedDamage, float, "CTFSniperRifle", "m_flChargedDamage"); +}; + +class CTFGrenadeLauncher : public CTFWeaponBase +{ +public: + NETVAR(m_flDetonateTime, float, "CTFGrenadeLauncher", "m_flDetonateTime"); + NETVAR(m_iCurrentTube, int, "CTFGrenadeLauncher", "m_iCurrentTube"); + NETVAR(m_iGoalTube, int, "CTFGrenadeLauncher", "m_iGoalTube"); +}; + +class CTFSniperRifleClassic : public CTFSniperRifle +{ +public: + NETVAR(m_bCharging, bool, "CTFSniperRifleClassic", "m_bCharging"); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CUserCmd.h b/Amalgam/src/SDK/Definitions/Main/CUserCmd.h new file mode 100644 index 0000000..ac7552b --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/CUserCmd.h @@ -0,0 +1,69 @@ +#pragma once +#include "../Types.h" + +class CUserCmd +{ +public: + virtual ~CUserCmd() {}; + int command_number = 0; + int tick_count = 0; + QAngle viewangles = {}; + float forwardmove = 0.0f; + float sidemove = 0.0f; + float upmove = 0.0f; + int buttons = 0; + unsigned char impulse = 0; + int weaponselect = 0; + int weaponsubtype = 0; + int random_seed = 0; + short mousedx = 0; + short mousedy = 0; + bool hasbeenpredicted = false; + + CUserCmd() {}; + + CUserCmd(const CUserCmd& other) + { + command_number = other.command_number; + tick_count = other.tick_count; + viewangles = other.viewangles; + forwardmove = other.forwardmove; + sidemove = other.sidemove; + upmove = other.upmove; + buttons = other.buttons; + impulse = other.impulse; + weaponselect = other.weaponselect; + weaponsubtype = other.weaponsubtype; + random_seed = other.random_seed; + mousedx = other.mousedx; + mousedy = other.mousedy; + hasbeenpredicted = other.hasbeenpredicted; + } +}; + +#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) +#define IN_SPEED (1 << 17) +#define IN_WALK (1 << 18) +#define IN_ZOOM (1 << 19) +#define IN_WEAPON1 (1 << 20) +#define IN_WEAPON2 (1 << 21) +#define IN_BULLRUSH (1 << 22) +#define IN_GRENADE1 (1 << 23) +#define IN_GRENADE2 (1 << 24) +#define IN_ATTACK3 (1 << 25) \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IAchievementMgr.h b/Amalgam/src/SDK/Definitions/Main/IAchievementMgr.h new file mode 100644 index 0000000..29338da --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IAchievementMgr.h @@ -0,0 +1,70 @@ +#ifndef IACHIEVEMENTMGR_H +#define IACHIEVEMENTMGR_H +#ifdef _WIN32 +#pragma once +#endif + +class CBaseAchievement; + +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; +}; + +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 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 \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IClientEntity.h b/Amalgam/src/SDK/Definitions/Main/IClientEntity.h new file mode 100644 index 0000000..f82b677 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IClientEntity.h @@ -0,0 +1,96 @@ +#pragma once +#include "IClientNetworkable.h" +#include "IClientRenderable.h" +#include "IClientThinkable.h" +#include "../Interfaces.h" + +class CMouthInfo; +struct SpatializationInfo_t; + +class IClientEntity : public IClientUnknown, public IClientRenderable, public IClientNetworkable, public IClientThinkable +{ +public: + virtual void Release(void) = 0; + virtual const Vector& GetAbsOrigin(void) const = 0; + virtual const QAngle& GetAbsAngles(void) const = 0; + virtual CMouthInfo* GetMouth(void) = 0; + virtual bool GetSoundSpatialization(SpatializationInfo_t& info) = 0; + + bool IsPlayer() + { + return GetClassID() == ETFClassID::CTFPlayer; + } + + bool IsSentrygun() + { + return GetClassID() == ETFClassID::CObjectSentrygun; + } + + bool IsDispenser() + { + return GetClassID() == ETFClassID::CObjectDispenser; + } + + bool IsTeleporter() + { + return GetClassID() == ETFClassID::CObjectTeleporter; + } + + bool IsBaseCombatWeapon() + { + return GetClassID() == ETFClassID::CBaseCombatWeapon; + } + + bool IsWearable() + { + return GetClassID() == ETFClassID::CTFWearable; + } + + bool IsBuilding() + { + switch (GetClassID()) + { + case ETFClassID::CObjectDispenser: + case ETFClassID::CObjectSentrygun: + case ETFClassID::CObjectTeleporter: return true; + default: return false; + } + } + + bool IsPickup() + { + switch (GetClassID()) + { + case ETFClassID::CBaseAnimating: return I::ModelInfoClient->GetModelName(GetModel())[24] != 'h'; + case ETFClassID::CTFAmmoPack: return true; + default: return false; + } + } + + bool IsNPC() + { + switch (GetClassID()) + { + case ETFClassID::CHeadlessHatman: + case ETFClassID::CTFTankBoss: + case ETFClassID::CMerasmus: + case ETFClassID::CZombie: + case ETFClassID::CEyeballBoss: + return true; + default: return false; + } + } + + bool IsBomb() + { + switch (GetClassID()) + { + case ETFClassID::CTFPumpkinBomb: + case ETFClassID::CTFGenericBomb: + return true; + default: return false; + } + } + + template inline T* As() { return static_cast(this); } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IClientNetworkable.h b/Amalgam/src/SDK/Definitions/Main/IClientNetworkable.h new file mode 100644 index 0000000..a0075d9 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IClientNetworkable.h @@ -0,0 +1,46 @@ +#pragma once +#include "IClientUnknown.h" +#include "../Misc/bitbuf.h" +#include "../Misc/ClientClass.h" +#include "../Definitions.h" + +class IClientEntity; + +enum ShouldTransmitState_t +{ + SHOULDTRANSMIT_START = 0, + SHOULDTRANSMIT_END +}; + +enum DataUpdateType_t +{ + DATA_UPDATE_CREATED = 0, + DATA_UPDATE_DATATABLE_CHANGED +}; + +class IClientNetworkable +{ +public: + virtual IClientUnknown* GetIClientUnknown() = 0; + virtual void Release() = 0; + virtual ClientClass* GetClientClass() = 0; + virtual void NotifyShouldTransmit(ShouldTransmitState_t state) = 0; + virtual void OnPreDataChanged(DataUpdateType_t updateType) = 0; + virtual void OnDataChanged(DataUpdateType_t updateType) = 0; + virtual void PreDataUpdate(DataUpdateType_t updateType) = 0; + virtual void PostDataUpdate(DataUpdateType_t updateType) = 0; + virtual bool IsDormant(void) = 0; + virtual int entindex(void) const = 0; + virtual void ReceiveMessage(int classID, bf_read& msg) = 0; + virtual void* GetDataTableBasePtr() = 0; + virtual void SetDestroyedOnRecreateEntities(void) = 0; + virtual void OnDataUnchangedInPVS() = 0; + + ETFClassID GetClassID() + { + if (auto pClientClass = GetClientClass()) + return static_cast(pClientClass->m_ClassID); + + return static_cast(0); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IClientRenderable.h b/Amalgam/src/SDK/Definitions/Main/IClientRenderable.h new file mode 100644 index 0000000..6f05507 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IClientRenderable.h @@ -0,0 +1,79 @@ +#pragma once +#include "IClientUnknown.h" +#include "../Types.h" + +typedef unsigned short ClientShadowHandle_t; + +enum +{ + CLIENTSHADOW_INVALID_HANDLE = (ClientShadowHandle_t)~0 +}; + +enum ShadowType_t +{ + SHADOWS_NONE = 0, + SHADOWS_SIMPLE, + SHADOWS_RENDER_TO_TEXTURE, + SHADOWS_RENDER_TO_TEXTURE_DYNAMIC, + SHADOWS_RENDER_TO_DEPTH_TEXTURE +}; + +class IPVSNotify +{ +public: + virtual void OnPVSStatusChanged(bool bInPVS) = 0; +}; + +using ClientRenderHandle_t = void*; +using ModelInstanceHandle_t = unsigned short; +struct model_t; + +class IClientRenderable +{ +public: + virtual IClientUnknown* GetIClientUnknown() = 0; + 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; + virtual ClientRenderHandle_t& RenderHandle() = 0; + virtual const model_t* GetModel() const = 0; + virtual int DrawModel(int flags) = 0; + virtual int GetBody() = 0; + virtual void ComputeFxBlend() = 0; + virtual int GetFxBlend(void) = 0; + virtual void GetColorModulation(float* color) = 0; + virtual bool LODTest() = 0; + virtual bool SetupBones(matrix3x4* pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime) = 0; + virtual void SetupWeights(const matrix3x4* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights) = 0; + virtual void DoAnimationEvents(void) = 0; + virtual IPVSNotify* GetPVSNotifyInterface() = 0; + virtual void GetRenderBounds(Vector& mins, Vector& maxs) = 0; + virtual void GetRenderBoundsWorldspace(Vector& mins, Vector& maxs) = 0; + virtual void GetShadowRenderBounds(Vector& mins, Vector& maxs, ShadowType_t shadowType) = 0; + virtual bool ShouldReceiveProjectedTextures(int flags) = 0; + virtual bool GetShadowCastDistance(float* pDist, ShadowType_t shadowType) const = 0; + virtual bool GetShadowCastDirection(Vector* pDirection, ShadowType_t shadowType) const = 0; + virtual bool IsShadowDirty() = 0; + virtual void MarkShadowDirty(bool bDirty) = 0; + virtual IClientRenderable* GetShadowParent() = 0; + virtual IClientRenderable* FirstShadowChild() = 0; + virtual IClientRenderable* NextShadowPeer() = 0; + virtual ShadowType_t ShadowCastType() = 0; + virtual void CreateModelInstance() = 0; + virtual ModelInstanceHandle_t GetModelInstance() = 0; + virtual const matrix3x4& RenderableToWorldTransform() = 0; + virtual int LookupAttachment(const char* pAttachmentName) = 0; + virtual bool GetAttachment(int number, Vector& origin, QAngle& angles) = 0; + virtual bool GetAttachment(int number, matrix3x4& matrix) = 0; + virtual float* GetRenderClipPlane(void) = 0; + virtual int GetSkin() = 0; + virtual bool IsTwoPass(void) = 0; + virtual void OnThreadedDrawSetup() = 0; + virtual bool UsesFlexDelayedWeights() = 0; + virtual void RecordToolMessage() = 0; + virtual bool IgnoresZBuffer(void) const = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IClientThinkable.h b/Amalgam/src/SDK/Definitions/Main/IClientThinkable.h new file mode 100644 index 0000000..9f6e97e --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IClientThinkable.h @@ -0,0 +1,15 @@ +#pragma once +#include "IClientUnknown.h" + +class CClientThinkHandlePtr; +typedef CClientThinkHandlePtr* ClientThinkHandle_t; + +class IClientThinkable +{ +public: + virtual IClientUnknown* GetIClientUnknown() = 0; + virtual void ClientThink() = 0; + virtual ClientThinkHandle_t GetThinkHandle() = 0; + virtual void SetThinkHandle(ClientThinkHandle_t hThink) = 0; + virtual void Release() = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IClientUnknown.h b/Amalgam/src/SDK/Definitions/Main/IClientUnknown.h new file mode 100644 index 0000000..49e8829 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IClientUnknown.h @@ -0,0 +1,20 @@ +#pragma once +#include "IHandleEntity.h" + +class IClientNetworkable; +class CBaseEntity; +class IClientRenderable; +class ICollideable; +class IClientEntity; +class IClientThinkable; + +class IClientUnknown : public IHandleEntity +{ +public: + virtual ICollideable* GetCollideable() = 0; + virtual IClientNetworkable* GetClientNetworkable() = 0; + virtual IClientRenderable* GetClientRenderable() = 0; + virtual IClientEntity* GetIClientEntity() = 0; + virtual CBaseEntity* GetBaseEntity() = 0; + virtual IClientThinkable* GetClientThinkable() = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IHandleEntity.h b/Amalgam/src/SDK/Definitions/Main/IHandleEntity.h new file mode 100644 index 0000000..541982d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IHandleEntity.h @@ -0,0 +1,11 @@ +#pragma once + +class CBaseHandle; + +class IHandleEntity +{ +public: + virtual ~IHandleEntity() {} + virtual void SetRefEHandle(const CBaseHandle& handle) = 0; + virtual const CBaseHandle& GetRefEHandle() const = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IMaterial.h b/Amalgam/src/SDK/Definitions/Main/IMaterial.h new file mode 100644 index 0000000..ef80f4a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IMaterial.h @@ -0,0 +1,225 @@ +#pragma once +#include "../Interfaces/IMaterialSystem.h" + +class IMaterialVar; +class ITexture; +class IMaterialProxy; + +#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 ) +#define VERTEX_WRINKLE 0x0040 +#define VERTEX_BONE_INDEX 0x0080 +#define VERTEX_FORMAT_VERTEX_SHADER 0x0100 +#define VERTEX_FORMAT_USE_EXACT_FORMAT 0x0200 +#define VERTEX_FORMAT_COMPRESSED 0x400 +#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 +#define VERTEX_FORMAT_UNKNOWN 0 + +#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) )) + +enum VertexElement_t +{ + VERTEX_ELEMENT_NONE = -1, + 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 +}; + +#define COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 0 +#define COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 1 +#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 + +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) +}; + +enum MaterialVarFlags2_t +{ + 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), + 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), + 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) +}; + +enum PreviewImageRetVal_t +{ + MATERIAL_PREVIEW_IMAGE_BAD = 0, + MATERIAL_PREVIEW_IMAGE_OK, + MATERIAL_NO_PREVIEW_IMAGE +}; + +class IMaterial +{ +public: + virtual const char* GetName() const = 0; + virtual const char* GetTextureGroupName() const = 0; + virtual PreviewImageRetVal_t GetPreviewImageProperties(int* width, int* height, ImageFormat* imageFormat, bool* isTranslucent) const = 0; + 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; + virtual bool InMaterialPage(void) = 0; + virtual void GetMaterialOffset(float* pOffset) = 0; + virtual void GetMaterialScale(float* pScale) = 0; + virtual IMaterial* GetMaterialPage(void) = 0; + virtual IMaterialVar* FindVar(const char* varName, bool* found, bool complain = true) = 0; + virtual void IncrementReferenceCount(void) = 0; + virtual void DecrementReferenceCount(void) = 0; + inline void AddRef() { IncrementReferenceCount(); } + inline void Release() { DecrementReferenceCount(); } + virtual int GetEnumerationID(void) const = 0; + virtual void GetLowResColorSample(float s, float t, float* color) const = 0; + virtual void RecomputeStateSnapshots() = 0; + virtual bool IsTranslucent() = 0; + virtual bool IsAlphaTested() = 0; + virtual bool IsVertexLit() = 0; + virtual VertexFormat_t GetVertexFormat() const = 0; + 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; + virtual bool NeedsSoftwareSkinning(void) = 0; + virtual void AlphaModulate(float alpha) = 0; + virtual void ColorModulate(float r, float g, float b) = 0; + virtual void SetMaterialVarFlag(MaterialVarFlags_t flag, bool on) = 0; + virtual bool GetMaterialVarFlag(MaterialVarFlags_t flag) const = 0; + virtual void GetReflectivity(Vector& reflect) = 0; + virtual bool GetPropertyFlag(MaterialPropertyTypes_t type) = 0; + virtual bool IsTwoSided() = 0; + virtual void SetShader(const char* pShaderName) = 0; + virtual int GetNumPasses(void) = 0; + virtual int GetTextureMemoryBytes(void) = 0; + virtual void Refresh() = 0; + virtual bool NeedsLightmapBlendAlpha(void) = 0; + virtual bool NeedsSoftwareLighting(void) = 0; + virtual int ShaderParamCount() const = 0; + virtual IMaterialVar** GetShaderParams(void) = 0; + virtual bool IsErrorMaterial() const = 0; + virtual void SetUseFixedFunctionBakedLighting(bool bEnable) = 0; + virtual float GetAlphaModulation() = 0; + virtual void GetColorModulation(float* r, float* g, float* b) = 0; + virtual MorphFormat_t GetMorphFormat() const = 0; + virtual IMaterialVar* FindVarFast(char const* pVarName, unsigned int* pToken) = 0; + 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(); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/IMaterialVar.h b/Amalgam/src/SDK/Definitions/Main/IMaterialVar.h new file mode 100644 index 0000000..8bb60b3 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/IMaterialVar.h @@ -0,0 +1,72 @@ +#pragma once +#include "../Misc/BaseTypes.h" +#include "../Types.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 )) +#define FOURCC_UNKNOWN MAKE_MATERIALVAR_FOURCC('U','N','K','N') + +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; +typedef unsigned long FourCC; + +class IMaterialVar +{ +private: + char* m_pStringVal; + int m_intVal; + Vector4D m_VecVal; + uint8 m_Type : 4; + uint8 m_nNumVectorComps : 3; + uint8 m_bFakeMaterialVar : 1; + uint8 m_nTempIndex; + //CUtlSymbol m_Name; + +public: + 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; + virtual void SetFourCCValue(FourCC type, void* pData) = 0; + virtual void GetFourCCValue(FourCC* type, void** ppData) = 0; + 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; + virtual void SetTextureValue(ITexture*) = 0; + virtual IMaterial* GetMaterialValue(void) = 0; + virtual void SetMaterialValue(IMaterial*) = 0; + virtual bool IsDefined() const = 0; + virtual void SetUndefined() = 0; + virtual void SetMatrixValue(VMatrix const& matrix) = 0; + virtual const VMatrix& GetMatrixValue() = 0; + virtual bool MatrixIsIdentity() const = 0; + virtual void CopyFrom(IMaterialVar* pMaterialVar) = 0; + virtual void SetValueAutodetectType(char const* val) = 0; + virtual IMaterial* GetOwningMaterial() = 0; + virtual void SetVecComponentValue(float fVal, int nComponent) = 0; + 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; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/INetChannel.h b/Amalgam/src/SDK/Definitions/Main/INetChannel.h new file mode 100644 index 0000000..3c3dfa8 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/INetChannel.h @@ -0,0 +1,90 @@ +#pragma once +#include "NetChannel.h" +#include "INetChannelInfo.h" +#include "INetMessage.h" + +class IDemoRecorder; +class INetChannelHandler; + +class INetChannel : public INetChannelInfo +{ +public: + virtual ~INetChannel(void) {}; + virtual void SetDataRate(float rate) = 0; + virtual bool RegisterMessage(INetMessage* msg) = 0; + //virtual bool StartStreaming(unsigned int challengeNr) = 0; + //virtual void ResetStreaming(void) = 0; + virtual void SetTimeout(float seconds) = 0; + virtual void SetDemoRecorder(IDemoRecorder* recorder) = 0; + virtual void SetChallengeNr(unsigned int chnr) = 0; + virtual void Reset(void) = 0; + virtual void Clear(void) = 0; + virtual void Shutdown(const char* reason) = 0; + virtual void ProcessPlayback(void) = 0; + //virtual bool ProcessStream(void) = 0; + virtual void ProcessPacket(struct netpacket_s* packet, bool bHasHeader) = 0; + virtual bool SendNetMsg(INetMessage& msg, bool bForceReliable = false, bool bVoice = false) = 0; + virtual bool SendData(bf_write& msg, bool bReliable = true) = 0; + virtual bool SendFile(const char* filename, unsigned int transferID) = 0; + virtual void DenyFile(const char* filename, unsigned int transferID) = 0; + virtual void RequestFile_OLD(const char* filename, unsigned int transferID) = 0; + virtual void SetChoked(void) = 0; + virtual int SendDatagram(bf_write* data) = 0; + virtual bool Transmit(bool onlyReliable = false) = 0; + virtual const netadr_t& GetRemoteAddress(void) const = 0; + virtual INetChannelHandler* GetMsgHandler(void) const = 0; + virtual int GetDropNumber(void) const = 0; + virtual int GetSocket(void) const = 0; + virtual unsigned int GetChallengeNr(void) const = 0; + virtual void GetSequenceData(int& nOutSequenceNr, int& nInSequenceNr, int& nOutSequenceNrAck) = 0; + virtual void SetSequenceData(int nOutSequenceNr, int nInSequenceNr, int nOutSequenceNrAck) = 0; + virtual void UpdateMessageStats(int msggroup, int bits) = 0; + virtual bool CanPacket(void) const = 0; + virtual bool IsOverflowed(void) const = 0; + virtual bool IsTimedOut(void) const = 0; + virtual bool HasPendingReliableData(void) = 0; + virtual void SetFileTransmissionMode(bool bBackgroundMode) = 0; + virtual void SetCompressionMode(bool bUseCompression) = 0; + virtual unsigned int RequestFile(const char* filename) = 0; + virtual float GetTimeSinceLastReceived(void) const = 0; + virtual void SetMaxBufferSize(bool bReliable, int nBytes, bool bVoice = false) = 0; + virtual bool IsNull() const = 0; + virtual int GetNumBitsWritten(bool bReliable) = 0; + virtual void SetInterpolationAmount(float flInterpolationAmount) = 0; + virtual void SetRemoteFramerate(float flFrameTime, float flFrameTimeStdDeviation) = 0; + virtual void SetMaxRoutablePayloadSize(int nSplitSize) = 0; + virtual int GetMaxRoutablePayloadSize() = 0; + virtual int GetProtocolVersion() = 0; +}; + +class CNetChannel : public INetChannel +{ +public: + virtual ConnectionStatus_t GetConnectionState(); + virtual const netadr_t& GetRemoteAddress(void) const; + + ConnectionStatus_t m_ConnectionState; + int m_nOutSequenceNr; + int m_nInSequenceNr; + int m_nOutSequenceNrAck; + int m_nOutReliableState; + int m_nInReliableState; + int m_nChokedPackets; + int m_PacketDrop; + bf_write m_StreamReliable; + byte m_ReliableDataBuffer[8 * 1024]; + CUtlVector m_ReliableDataBufferMP; + bf_write m_StreamUnreliable; + byte m_UnreliableDataBuffer[NET_MAX_DATAGRAM_PAYLOAD]; + CUDPSocket* m_pSocket; + int m_StreamSocket; + unsigned int m_MaxReliablePayloadSize; + netadr_t remote_address; + float last_received; + float connect_time; + int m_Rate; + float m_fClearTime; + float m_Timeout; + char m_Name[32]; + INetworkMessageHandler* m_MessageHandler; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/INetChannelInfo.h b/Amalgam/src/SDK/Definitions/Main/INetChannelInfo.h new file mode 100644 index 0000000..a5c4ade --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/INetChannelInfo.h @@ -0,0 +1,36 @@ +#pragma once + +#define FLOW_OUTGOING 0 +#define FLOW_INCOMING 1 +#define MAX_FLOWS 2 + +class INetChannelInfo +{ +public: + virtual const char* GetName(void) const = 0; + virtual const char* GetAddress(void) const = 0; + virtual float GetTime(void) const = 0; + virtual float GetTimeConnected(void) const = 0; + virtual int GetBufferSize(void) const = 0; + virtual int GetDataRate(void) const = 0; + virtual bool IsLoopback(void) const = 0; + virtual bool IsTimingOut(void) const = 0; + virtual bool IsPlayback(void) const = 0; + virtual float GetLatency(int flow) const = 0; + virtual float GetAvgLatency(int flow) const = 0; + virtual float GetAvgLoss(int flow) const = 0; + virtual float GetAvgChoke(int flow) const = 0; + virtual float GetAvgData(int flow) const = 0; + virtual float GetAvgPackets(int flow) const = 0; + virtual int GetTotalData(int flow) const = 0; + virtual int GetSequenceNr(int flow) const = 0; + virtual bool IsValidPacket(int flow, int frame_number) const = 0; + virtual float GetPacketTime(int flow, int frame_number) const = 0; + virtual int GetPacketBytes(int flow, int frame_number, int group) const = 0; + virtual bool GetStreamProgress(int flow, int* received, int* total) const = 0; + virtual float GetTimeSinceLastReceived(void) const = 0; + virtual float GetCommandInterpolationAmount(int flow, int frame_number) const = 0; + virtual void GetPacketResponseLatency(int flow, int frame_number, int* pnLatencyMsecs, int* pnChoke) const = 0; + virtual void GetRemoteFramerate(float* pflFrameTime, float* pflFrameTimeStdDeviation) const = 0; + virtual float GetTimeoutSeconds() const = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/INetMessage.cpp b/Amalgam/src/SDK/Definitions/Main/INetMessage.cpp new file mode 100644 index 0000000..4f3cb66 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/INetMessage.cpp @@ -0,0 +1,150 @@ +#include "INetMessage.h" + +#include +#include + +#define NETMSG_TYPE_BITS 6 +#define NUM_NEW_COMMAND_BITS 4 +#define NUM_BACKUP_COMMAND_BITS 3 + +const char* CLC_Move::ToString(void) const { return "CLC_Move"; } + +bool CLC_Move::WriteToBuffer(bf_write& buffer) +{ + buffer.WriteUBitLong(GetType(), NETMSG_TYPE_BITS); + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong(m_nNewCommands, NUM_NEW_COMMAND_BITS); + buffer.WriteUBitLong(m_nBackupCommands, NUM_BACKUP_COMMAND_BITS); + + buffer.WriteWord(m_nLength); + + return buffer.WriteBits(m_DataOut.GetData(), m_nLength); +} + +bool CLC_Move::ReadFromBuffer(bf_read& buffer) +{ + m_nNewCommands = buffer.ReadUBitLong(NUM_NEW_COMMAND_BITS); + m_nBackupCommands = buffer.ReadUBitLong(NUM_BACKUP_COMMAND_BITS); + m_nLength = buffer.ReadWord(); + m_DataIn = buffer; + return buffer.SeekRelative(m_nLength); +} + +const char* NET_SetConVar::ToString() const { return "(NULL)"; } + +bool NET_SetConVar::WriteToBuffer(bf_write& buffer) +{ + buffer.WriteUBitLong(GetType(), 6); + const int numVars = 1; + buffer.WriteByte(numVars); + buffer.WriteString(ConVar.Name); + buffer.WriteString(ConVar.Value); + + return !buffer.IsOverflowed(); +} + +bool NET_SetConVar::ReadFromBuffer(bf_read& buffer) +{ + const int numVars = buffer.ReadByte(); + + for (int i = 0; i < numVars; i++) + { + CVar_t cvar; + buffer.ReadString(cvar.Name, sizeof(cvar.Name)); + buffer.ReadString(cvar.Value, sizeof(cvar.Value)); + } + return !buffer.IsOverflowed(); +} + +bool NET_SignonState::WriteToBuffer(bf_write& buffer) +{ + buffer.WriteUBitLong(GetType(), 6); + buffer.WriteByte(m_nSignonState); + buffer.WriteLong(m_nSpawnCount); + + return !buffer.IsOverflowed(); +} + +bool NET_SignonState::ReadFromBuffer(bf_read& buffer) +{ + /* + m_nSignonState = buffer.ReadByte(); + m_nSpawnCount = buffer.ReadLong(); + */ + return true; +} + +const char* NET_SignonState::ToString(void) const +{ + return std::format("net_SignonState: state {}, count {}", m_nSignonState, m_nSpawnCount).c_str(); +} + +#define NET_TICK_SCALEUP 100000.0f + +bool NET_Tick::WriteToBuffer(bf_write& buffer) +{ + buffer.WriteUBitLong(GetType(), NETMSG_TYPE_BITS); + buffer.WriteLong(m_nTick); + buffer.WriteUBitLong(std::clamp((int)(NET_TICK_SCALEUP * m_flHostFrameTime), 0, 65535), 16); + buffer.WriteUBitLong(std::clamp((int)(NET_TICK_SCALEUP * m_flHostFrameTimeStdDeviation), 0, 65535), 16); + return !buffer.IsOverflowed(); +} + +bool NET_Tick::ReadFromBuffer(bf_read& buffer) +{ + m_nTick = buffer.ReadLong(); + m_flHostFrameTime = (float)buffer.ReadUBitLong(16) / NET_TICK_SCALEUP; + m_flHostFrameTimeStdDeviation = (float)buffer.ReadUBitLong(16) / NET_TICK_SCALEUP; + return !buffer.IsOverflowed(); +} + + +const char* NET_Tick::ToString(void) const +{ + return std::format("{}: tick {}", GetName(), m_nTick).c_str(); +} + +const char* CLC_VoiceData::ToString(void) const +{ + return std::format("{}: {} bytes", GetName(), static_cast(m_nLength * 0.125f)).c_str(); +} + + +bool CLC_VoiceData::WriteToBuffer(bf_write& buffer) +{ + buffer.WriteUBitLong(GetType(), NETMSG_TYPE_BITS); + m_nLength = m_DataOut.GetNumBitsWritten(); + buffer.WriteWord(m_nLength); // length in bits + + return buffer.WriteBits(m_DataOut.GetBasePointer(), m_nLength); +} + +bool CLC_VoiceData::ReadFromBuffer(bf_read& buffer) +{ + m_nLength = buffer.ReadWord(); // length in bits + m_DataIn = buffer; + + return buffer.SeekRelative(m_nLength); +} + +bool CLC_BaselineAck::WriteToBuffer(bf_write& buffer) +{ + buffer.WriteUBitLong(GetType(), NETMSG_TYPE_BITS); + buffer.WriteLong(m_nBaselineTick); + buffer.WriteUBitLong(m_nBaselineNr, 1); + return !buffer.IsOverflowed(); +} + +bool CLC_BaselineAck::ReadFromBuffer(bf_read& buffer) +{ + + m_nBaselineTick = buffer.ReadLong(); + m_nBaselineNr = buffer.ReadUBitLong(1); + return !buffer.IsOverflowed(); +} + +const char* CLC_BaselineAck::ToString(void) const +{ + return std::format("{}: tick {}", GetName(), m_nBaselineTick).c_str(); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/INetMessage.h b/Amalgam/src/SDK/Definitions/Main/INetMessage.h new file mode 100644 index 0000000..f5b7731 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/INetMessage.h @@ -0,0 +1,255 @@ +#pragma once +#include "../Misc/bitbuf.h" +#include "../Types.h" + +#define MAX_OSPATH 260 // max length of a filesystem pathname +#define net_NOP 0 // nop command used for padding +#define net_Disconnect 1 // disconnect, last message in connection +#define net_File 2 // file transmission message request/deny +#define net_Tick 3 // send last world tick +#define net_StringCmd 4 // a string command +#define net_SetConVar 5 // sends one/multiple convar settings +#define net_SignonState 6 // signals current signon state +#define clc_ClientInfo 8 +#define clc_Move 9 +#define clc_VoiceData 10 +#define clc_BaselineAck 11 +#define clc_ListenEvents 12 +#define clc_RespondCvarValue 13 +#define clc_FileCRCCheck 14 +#define clc_CmdKeyValues 16 + +class INetChannel; + +enum +{ + GENERIC = 0, // must be first and is default group + LOCALPLAYER, // bytes for local player entity update + OTHERPLAYERS, // bytes for other players update + ENTITIES, // all other entity bytes + SOUNDS, // game sounds + EVENTS, // event messages + USERMESSAGES, // user messages + ENTMESSAGES, // entity messages + VOICE, // voice data + STRINGTABLE, // a stringtable update + MOVE, // client move cmds + STRINGCMD, // string command + SIGNON, // various signondata + TOTAL, // must be last and is not a real group +}; + +class INetMessage +{ +public: + virtual ~INetMessage() {}; + 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 +}; + +class CNetMessage : public INetMessage +{ +public: + CNetMessage() + { + m_bReliable = true; + m_NetChannel = nullptr; + } + + virtual ~CNetMessage() {}; + + virtual int GetGroup() const { return GENERIC; } + INetChannel* GetNetChannel() const { return m_NetChannel; } + + virtual void SetReliable(bool state) { m_bReliable = state; }; + virtual bool IsReliable() const { return m_bReliable; }; + virtual void SetNetChannel(INetChannel* netchan) { m_NetChannel = netchan; } + virtual bool Process() { return false; }; // no handler set + +protected: + bool m_bReliable; // true if message should be send reliable + INetChannel* m_NetChannel; // netchannel this message is from/for + byte pad0[8]; +}; + +class CLC_Move : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return clc_Move; } + const char* GetName() const { return "clc_Move"; } + void* m_pMessageHandler; + int GetGroup() const { return MOVE; } + + CLC_Move() { m_bReliable = false; } + +public: + int m_nBackupCommands; + int m_nNewCommands; + int m_nLength; + bf_read m_DataIn; + bf_write m_DataOut; +}; + +class NET_SetConVar : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return net_SetConVar; } + const char* GetName() const { return "net_SetConVar"; } + void* m_pMessageHandler; + int GetGroup() const { return STRINGCMD; } + + NET_SetConVar() {} + NET_SetConVar(const char* name, const char* value) + { + CVar_t cvar; + strncpy_s(cvar.Name, name, MAX_OSPATH); + strncpy_s(cvar.Value, value, MAX_OSPATH); + ConVar = cvar; + } + +public: + typedef struct CVar_s + { + char Name[MAX_OSPATH]; + char Value[MAX_OSPATH]; + } CVar_t; + CVar_t ConVar; +}; + +class NET_SignonState : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return net_SignonState; } + const char* GetName() const { return "net_SignonState"; } + void* m_pMessageHandler; + + int GetGroup() const { return SIGNON; } + + NET_SignonState() {}; + NET_SignonState(int state, int spawncount) { m_nSignonState = state; m_nSpawnCount = spawncount; }; + +public: + int m_nSignonState; // See SIGNONSTATE_ defines + int m_nSpawnCount; // server spawn count (session number) +}; + +class NET_Tick : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return net_Tick; } + const char* GetName() const { return "net_Tick"; } + void* m_pMessageHandler; + + NET_Tick() + { + m_bReliable = false; + m_flHostFrameTime = 0; + m_flHostFrameTimeStdDeviation = 0; + }; + NET_Tick(int tick, float hostFrametime, float hostFrametime_stddeviation) + { + m_bReliable = false; + m_nTick = tick; + m_flHostFrameTime = hostFrametime; + m_flHostFrameTimeStdDeviation = hostFrametime_stddeviation; + }; + +public: + int m_nTick; + float m_flHostFrameTime; + float m_flHostFrameTimeStdDeviation; +}; + +class CLC_VoiceData : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return clc_VoiceData; } + const char* GetName() const { return "clc_VoiceData"; } + void* m_pMessageHandler; + + int GetGroup() const { return VOICE; } + + CLC_VoiceData() { m_bReliable = false; } + +public: + int m_nLength; + bf_read m_DataIn; + bf_write m_DataOut; + uint64_t m_xuid; +}; + +class CLC_RespondCvarValue : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return clc_RespondCvarValue; } + const char* GetName() const { return "clc_RespondCvarValue"; } + void* m_pMessageHandler; + + int m_iCookie; + + const char* m_szCvarName; + const char* m_szCvarValue; // The sender sets this, and it automatically points it at m_szCvarNameBuffer when receiving. + + int m_eStatusCode; + +private: + char m_szCvarNameBuffer[256]; + char m_szCvarValueBuffer[256]; +}; + +class SVC_FixAngle : public CNetMessage +{ + SVC_FixAngle() { m_bReliable = false; }; + SVC_FixAngle(bool bRelative, QAngle angle) { m_bReliable = false; m_bRelative = bRelative; m_Angle = angle; } + +public: + bool m_bRelative; + QAngle m_Angle; +}; + +class CLC_BaselineAck : public CNetMessage +{ +public: + bool ReadFromBuffer(bf_read& buffer); + bool WriteToBuffer(bf_write& buffer); + const char* ToString() const; + int GetType() const { return clc_BaselineAck; } + const char* GetName() const { return "clc_BaselineAck"; } + void* m_pMessageHandler; + + CLC_BaselineAck() {}; + CLC_BaselineAck(int tick, int baseline) { m_nBaselineTick = tick; m_nBaselineNr = baseline; } + + int GetGroup() const { return ENTITIES; } + +public: + int m_nBaselineTick; // sequence number of baseline + int m_nBaselineNr; // 0 or 1 +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/INetworkMessage.h b/Amalgam/src/SDK/Definitions/Main/INetworkMessage.h new file mode 100644 index 0000000..9b7ecdf --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/INetworkMessage.h @@ -0,0 +1,73 @@ +#pragma once +#include "INetMessage.h" + +class INetChannel; + +enum +{ + NETWORKSYSTEM_FIRST_GROUP = 1 +}; + +class INetworkMessage +{ +public: + virtual void SetNetChannel(INetChannel* netchan) = 0; + virtual void SetReliable(bool state) = 0; + virtual bool ReadFromBuffer(bf_read& buffer) = 0; + virtual bool WriteToBuffer(bf_write& buffer) = 0; + virtual bool IsReliable(void) const = 0; + virtual int GetGroup(void) const = 0; + virtual int GetType(void) const = 0; + virtual const char* GetGroupName(void) const = 0; + virtual const char* GetName(void) const = 0; + virtual INetChannel* GetNetChannel(void) const = 0; + virtual const char* ToString(void) const = 0; + virtual void Release() = 0; + virtual ~INetworkMessage() {}; +}; + +class CNetworkMessage : public INetworkMessage +{ +public: + CNetworkMessage() + { + m_bReliable = true; + m_pNetChannel = nullptr; + } + + virtual void Release() + { + delete this; + } + + virtual ~CNetworkMessage() {}; + + virtual void SetReliable(bool state) + { + m_bReliable = state; + } + + virtual bool IsReliable() const + { + return m_bReliable; + } + + virtual void SetNetChannel(INetChannel* netchan) + { + m_pNetChannel = netchan; + } + + virtual bool Process() + { + return false; + } + + INetChannel* GetNetChannel() const + { + return m_pNetChannel; + } + +protected: + bool m_bReliable; + INetChannel* m_pNetChannel; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/INetworkSystem.h b/Amalgam/src/SDK/Definitions/Main/INetworkSystem.h new file mode 100644 index 0000000..ea48d92 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/INetworkSystem.h @@ -0,0 +1,68 @@ +#pragma once +#include "INetworkMessage.h" +#include "../Misc/IAppSystem.h" +#include "../Misc/NetAdr.h" + +enum +{ + NETWORKSYSTEM_DEFAULT_SERVER_PORT = 27001, + NETWORKSYSTEM_DEFAULT_CLIENT_PORT = 27002 +}; + +typedef int ConnectionHandle_t; + +enum ConnectionStatus_t +{ + CONNECTION_STATE_DISCONNECTED = 0, + CONNECTION_STATE_CONNECTING, + CONNECTION_STATE_CONNECTION_FAILED, + CONNECTION_STATE_CONNECTED +}; + +enum NetworkEventType_t +{ + NETWORK_EVENT_CONNECTED = 0, + NETWORK_EVENT_DISCONNECTED, + NETWORK_EVENT_MESSAGE_RECEIVED, +}; + +struct NetworkEvent_t +{ + NetworkEventType_t m_nType; +}; + +struct NetworkConnectionEvent_t : public NetworkEvent_t +{ + void* m_pChannel; +}; + +struct NetworkDisconnectionEvent_t : public NetworkEvent_t +{ + void* m_pChannel; +}; + +struct NetworkMessageReceivedEvent_t : public NetworkEvent_t +{ + void* m_pChannel; + INetworkMessage* m_pNetworkMessage; +}; + +class INetworkSystem : public IAppSystem +{ +public: + virtual bool RegisterMessage(INetworkMessage* msg) = 0; + virtual bool StartServer(unsigned short nServerListenPort = NETWORKSYSTEM_DEFAULT_SERVER_PORT) = 0; + virtual void ShutdownServer() = 0; + virtual void ServerReceiveMessages() = 0; + virtual void ServerSendMessages() = 0; + virtual bool StartClient(unsigned short nClientListenPort = NETWORKSYSTEM_DEFAULT_CLIENT_PORT) = 0; + virtual void ShutdownClient() = 0; + virtual void ClientSendMessages() = 0; + virtual void ClientReceiveMessages() = 0; + virtual void* ConnectClientToServer(const char* pServer, int nServerListenPort = NETWORKSYSTEM_DEFAULT_SERVER_PORT) = 0; + virtual void DisconnectClientFromServer(void* pChan) = 0; + virtual NetworkEvent_t* FirstNetworkEvent() = 0; + virtual NetworkEvent_t* NextNetworkEvent() = 0; + virtual const char* GetLocalHostName(void) const = 0; + virtual const char* GetLocalAddress(void) const = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/ITexture.h b/Amalgam/src/SDK/Definitions/Main/ITexture.h new file mode 100644 index 0000000..1151272 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/ITexture.h @@ -0,0 +1,58 @@ +#pragma once +#include "../Misc/BaseTypes.h" +#include "../Misc/ImageFormat.h" + +class IVTFTexture; +class ITexture; +struct Rect_t; + +class ITextureRegenerator +{ +public: + virtual void RegenerateTextureBits(ITexture* pTexture, IVTFTexture* pVTFTexture, Rect_t* pRect) = 0; + virtual void Release() = 0; +}; + +class ITexture +{ +public: + 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; + virtual void* GetResourceData(uint32 eDataType, size_t* pNumBytes) const = 0; + virtual void IncrementReferenceCount(void) = 0; + virtual void DecrementReferenceCount(void) = 0; + inline void AddRef() { IncrementReferenceCount(); } + inline void Release() { DecrementReferenceCount(); } + virtual void SetTextureRegenerator(ITextureRegenerator* pTextureRegen) = 0; + virtual void Download(Rect_t* pRect = 0, int nAdditionalCreationFlags = 0) = 0; + virtual int GetApproximateVidMemBytes(void) const = 0; + virtual bool IsError() const = 0; + 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; + virtual bool IsRenderTarget() const = 0; + virtual bool IsCubeMap() const = 0; + virtual bool IsNormalMap() const = 0; + virtual bool IsProcedural() const = 0; + virtual void DeleteIfUnreferenced() = 0; + virtual void SwapContents(ITexture* pOther) = 0; + virtual unsigned int GetFlags(void) const = 0; + virtual void ForceLODOverride(int iNumLodsOverrideUpOrDown) = 0; + virtual bool SaveToFile(const char* fileName) = 0; + virtual void CopyToStagingTexture(ITexture* pDstTex) = 0; + virtual void SetErrorTexture(bool bIsErrorTexture) = 0; +}; + +inline bool IsErrorTexture(ITexture* pTex) +{ + return !pTex || pTex->IsError(); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/KeyValues.cpp b/Amalgam/src/SDK/Definitions/Main/KeyValues.cpp new file mode 100644 index 0000000..09cfab1 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/KeyValues.cpp @@ -0,0 +1,422 @@ +#include "KeyValues.h" + +#include "../../SDK.h" + +#define Q_ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) + +MAKE_SIGNATURE(KeyValues_LoadFromBuffer, "engine.dll", "4C 89 4C 24 ? 48 89 4C 24 ? 55 56", 0x0); +MAKE_SIGNATURE(KeyValues_Initialize, "engine.dll", "40 53 48 83 EC ? 48 8B D9 C7 01", 0x0); +MAKE_SIGNATURE(KeyValues_FindKey, "client.dll", "48 8B C4 53 57 41 56", 0x0); + +int UnicodeToUTF8(const wchar_t* unicode, char* ansi, int ansiBufferSize) +{ + int result = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL); + ansi[ansiBufferSize - 1] = 0; + return result; +} + +int UTF8ToUnicode(const char* ansi, wchar_t* unicode, int unicodeBufferSizeInBytes) +{ + int chars = MultiByteToWideChar(CP_UTF8, 0, ansi, -1, unicode, unicodeBufferSizeInBytes / sizeof(wchar_t)); + unicode[(unicodeBufferSizeInBytes / sizeof(wchar_t)) - 1] = 0; + return chars; +} + + +bool KeyValues::LoadFromBuffer(char const* resource_name, const char* buffer, void* file_system, const char* path_id) +{ + return S::KeyValues_LoadFromBuffer.As()(this, resource_name, buffer, file_system, path_id); +} + +void KeyValues::Initialize(char* name) +{ + S::KeyValues_Initialize.As()(this, name); +} + +KeyValues::KeyValues(const char* name) +{ + char _name[128]; + sprintf_s(_name, sizeof(_name), name); + this->Initialize((char *)_name); +} + +KeyValues *KeyValues::FindKey(const char *keyName, bool bCreate) +{ + return S::KeyValues_FindKey.As()(this, keyName, bCreate); +} + + +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: + return 0; + case TYPE_INT: + case TYPE_PTR: + default: + return dat->m_iValue; + }; + } + return defaultValue; +} + +uint64_t KeyValues::GetUint64(const char* keyName, uint64_t defaultValue) +{ + KeyValues* dat = FindKey(keyName, false); + if (dat) + { + switch (dat->m_iDataType) + { + case TYPE_STRING: + return (uint64_t)_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_t*)dat->m_sValue); + case TYPE_INT: + case TYPE_PTR: + default: + return dat->m_iValue; + }; + } + return defaultValue; +} + +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: + return (float)_wtof(dat->m_wsValue); + case TYPE_FLOAT: + return dat->m_flValue; + case TYPE_INT: + return (float)dat->m_iValue; + case TYPE_UINT64: + return (float)(*((uint64_t*)dat->m_sValue)); + case TYPE_PTR: + default: + return 0.0f; + }; + } + return defaultValue; +} + +const char* KeyValues::GetString(const char* keyName, const char* defaultValue) +{ + KeyValues* dat = FindKey(keyName, false); + if (dat) + { + char buf[64]; + switch (dat->m_iDataType) + { + case TYPE_FLOAT: + snprintf(buf, sizeof(buf), "%f", dat->m_flValue); + SetString(keyName, buf); + break; + case TYPE_PTR: + snprintf(buf, sizeof(buf), "%lld", (int64_t)(size_t)dat->m_pValue); + SetString(keyName, buf); + break; + case TYPE_INT: + snprintf(buf, sizeof(buf), "%d", dat->m_iValue); + SetString(keyName, buf); + break; + case TYPE_UINT64: + snprintf(buf, sizeof(buf), "%lld", *((uint64_t*)(dat->m_sValue))); + SetString(keyName, buf); + break; + case TYPE_WSTRING: + { + char wideBuf[512]; + int result = UnicodeToUTF8(dat->m_wsValue, wideBuf, 512); + if (result) + { + 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_t)(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_t*)(dat->m_sValue))); + SetWString(keyName, wbuf); + } + break; + + case TYPE_WSTRING: + break; + case TYPE_STRING: + { + const auto bufSize = strlen(dat->m_sValue) + 1; + wchar_t* pWBuf = new wchar_t[bufSize]; + const int result = UTF8ToUnicode(dat->m_sValue, pWBuf, static_cast(bufSize) * sizeof(wchar_t)); + if (result >= 0) + { + SetWString(keyName, pWBuf); + } + else + { + delete[] pWBuf; + return defaultValue; + } + delete[] pWBuf; + break; + } + default: + return defaultValue; + }; + + return (const wchar_t*)dat->m_wsValue; + } + return defaultValue; +} + +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; +} + +bool KeyValues::GetBool(const char* keyName, bool defaultValue) +{ + if (FindKey(keyName)) + { + /*if (optGotDefault) + (*optGotDefault) = false;*/ + + return 0 != GetInt(keyName, 0); + } + + /*if (optGotDefault) + (*optGotDefault) = true;*/ + + return defaultValue; +} + +Color_t KeyValues::GetColor(const char* keyName) +{ + Color_t color{ 0, 0, 0, 0 }; + KeyValues* dat = FindKey(keyName, false); + if (dat) + { + if (dat->m_iDataType == TYPE_COLOR) + { + color.r = dat->m_Color[0]; + color.g = dat->m_Color[1]; + color.b = dat->m_Color[2]; + color.a = dat->m_Color[3]; + } + else if (dat->m_iDataType == TYPE_FLOAT) + { + color.r = dat->m_flValue; + } + else if (dat->m_iDataType == TYPE_INT) + { + color.r = dat->m_iValue; + } + else if (dat->m_iDataType == TYPE_STRING) + { + float a = 0.0f, b = 0.0f, c = 0.0f, d = 0.0f; + sscanf_s(dat->m_sValue, "%f %f %f %f", &a, &b, &c, &d); + color.r = (unsigned char)a; + color.g = (unsigned char)b; + color.b = (unsigned char)c; + color.a = (unsigned char)d; + } + } + return color; +} + +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; +} + + +void KeyValues::SetWString(const char* keyName, const wchar_t* value) +{ + KeyValues* dat = FindKey(keyName, true); + if (dat) + { + delete[] dat->m_wsValue; + delete[] dat->m_sValue; + dat->m_sValue = NULL; + + if (!value) + { + value = L""; + } + + int len = int(wcslen(value)); + dat->m_wsValue = new wchar_t[len + 1]; + memcpy(dat->m_wsValue, value, (len + 1) * sizeof(wchar_t)); + + dat->m_iDataType = TYPE_WSTRING; + } +} + +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[] dat->m_sValue; + delete[] dat->m_wsValue; + dat->m_wsValue = NULL; + + if (!value) + { + value = ""; + } + + int len = int(strlen(value)); + dat->m_sValue = new char[len + 1]; + memcpy(dat->m_sValue, value, len + 1); + + dat->m_iDataType = TYPE_STRING; + } +} + +void KeyValues::SetInt(const char* keyName, int value) +{ + KeyValues* dat = FindKey(keyName, true); + + if (dat) + { + dat->m_iValue = value; + dat->m_iDataType = TYPE_INT; + } +} + +void KeyValues::SetUint64(const char* keyName, uint64_t value) +{ + KeyValues* dat = FindKey(keyName, true); + + if (dat) + { + delete[] dat->m_sValue; + delete[] dat->m_wsValue; + dat->m_wsValue = NULL; + + dat->m_sValue = new char[sizeof(uint64_t)]; + *((uint64_t*)dat->m_sValue) = value; + dat->m_iDataType = TYPE_UINT64; + } +} + +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::SetPtr(const char* keyName, void* value) +{ + KeyValues* dat = FindKey(keyName, true); + + if (dat) + { + dat->m_pValue = value; + dat->m_iDataType = TYPE_PTR; + } +} + +void KeyValues::SetColor(const char* keyName, Color_t value) +{ + KeyValues* dat = FindKey(keyName, true); + + if (dat) + { + dat->m_iDataType = TYPE_COLOR; + dat->m_Color[0] = value.r; + dat->m_Color[1] = value.g; + dat->m_Color[2] = value.b; + dat->m_Color[3] = value.a; + } +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/KeyValues.h b/Amalgam/src/SDK/Definitions/Main/KeyValues.h new file mode 100644 index 0000000..2f4d63c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/KeyValues.h @@ -0,0 +1,66 @@ +#pragma once +#include "../Types.h" +#include + +enum types_t +{ + TYPE_NONE = 0, + TYPE_STRING, + TYPE_INT, + TYPE_FLOAT, + TYPE_PTR, + TYPE_WSTRING, + TYPE_COLOR, + TYPE_UINT64, + TYPE_NUMTYPES, +}; + +class KeyValues +{ +private: + int m_iKeyName; + char* m_sValue; + wchar_t* m_wsValue; + + union + { + int m_iValue; + float m_flValue; + void* m_pValue; + unsigned char m_Color[4]; + }; + + char m_iDataType; + char m_bHasEscapeSequences; + char m_bEvaluateConditionals; + char unused[1]; + + KeyValues* m_pPeer; + KeyValues* m_pSub; + KeyValues* m_pChain; + +public: + bool LoadFromBuffer(char const* resource_name, const char* buffer, void* file_system = 0, const char* path_id = 0); + void Initialize(char* name); + KeyValues(const char* name); + KeyValues* FindKey(const char* keyName, bool bCreate = false); + + int GetInt(const char* keyName, int defaultValue = 0); + uint64_t GetUint64(const char* keyName, uint64_t defaultValue = 0); + float GetFloat(const char* keyName, float defaultValue = 0.0f); + const char* GetString(const char* keyName, const char* defaultValue = ""); + const wchar_t* GetWString(const char* keyName, const wchar_t* defaultValue = L""); + void* GetPtr(const char* keyName, void* defaultValue = (void*)0); + bool GetBool(const char* keyName, bool defaultValue = false); + Color_t GetColor(const char* keyName); + bool IsEmpty(const char* keyName); + + 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_t value); + void SetFloat(const char* keyName, float value); + void SetPtr(const char* keyName, void* value); + void SetColor(const char* keyName, Color_t value); + void SetBool(const char* keyName, bool value) { SetInt(keyName, value ? 1 : 0); } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/MD5.cpp b/Amalgam/src/SDK/Definitions/Main/MD5.cpp new file mode 100644 index 0000000..8839acb --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/MD5.cpp @@ -0,0 +1,200 @@ +#include "MD5.h" +#include + +#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)) + +#define MD5STEP(f, w, x, y, z, data, s) ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +#pragma warning (disable : 5033) + +static void MD5Transform(unsigned int buf[4], unsigned int const in[16]) +{ + /*register*/ 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; +} + +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; +} + +void MD5Update(MD5Context_t* ctx, unsigned char const* buf, unsigned int len) +{ + unsigned int t; + + t = ctx->bits[0]; + + if ((ctx->bits[0] = t + ((unsigned int)len << 3)) < t) + ctx->bits[1]++; + + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; + + 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); + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) + { + memcpy(ctx->in, buf, 64); + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + buf += 64; + len -= 64; + } + + memcpy(ctx->in, buf, len); +} + +void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5Context_t* ctx) +{ + unsigned count; + unsigned char* p; + + count = (ctx->bits[0] >> 3) & 0x3F; + p = ctx->in + count; + *p++ = 0x80; + + count = 64 - 1 - count; + + if (count < 8) + { + memset(p, 0, count); + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + memset(ctx->in, 0, 56); + } + + else + { + memset(p, 0, count - 8); + } + + ((unsigned int*)ctx->in)[14] = ctx->bits[0]; + ((unsigned int*)ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (unsigned int*)ctx->in); + memcpy(digest, ctx->buf, MD5_DIGEST_LENGTH); + memset(ctx, 0, sizeof(*ctx)); +} + +unsigned int MD5_PseudoRandom(unsigned int nSeed) +{ + MD5Context_t ctx; + unsigned char digest[MD5_DIGEST_LENGTH]; + + memset(&ctx, 0, sizeof(ctx)); + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)&nSeed, sizeof(nSeed)); + MD5Final(digest, &ctx); + + return *(unsigned int*)(digest + 6); +} + +bool MD5_Compare(const MD5Value_t& data, const MD5Value_t& compare) +{ + return memcmp(data.bits, compare.bits, MD5_DIGEST_LENGTH) == 0; +} + +void MD5Value_t::Zero() +{ + memset(bits, 0, sizeof(bits)); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/MD5.h b/Amalgam/src/SDK/Definitions/Main/MD5.h new file mode 100644 index 0000000..e4cff78 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/MD5.h @@ -0,0 +1,39 @@ +#pragma once + +#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; + +}; + +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); +void MD5_ProcessSingleBuffer(const void* p, int len, MD5Value_t& md5Result); +unsigned int MD5_PseudoRandom(unsigned int nSeed); +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); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/NetChannel.h b/Amalgam/src/SDK/Definitions/Main/NetChannel.h new file mode 100644 index 0000000..51eea1c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Main/NetChannel.h @@ -0,0 +1,94 @@ +#pragma once +#include "INetworkSystem.h" +#include "UtlVector.h" +#include "../Misc/bitbuf.h" +#include "../Misc/BaseTypes.h" + +enum +{ + FRAG_NORMAL_STREAM = 0, + FRAG_FILE_STREAM, + MAX_STREAMS +}; + +#define NET_MAX_DATAGRAM_PAYLOAD 1400 +#define NET_MAX_PAYLOAD_BITS 11 +#define DEFAULT_RATE 10000 +#define SIGNON_TIME_OUT 120.0f +#define CONNECTION_PROBLEM_TIME 15.0f + +#define MAX_RATE 50000 +#define MIN_RATE 100 + +#define FRAGMENT_BITS 8 +#define FRAGMENT_SIZE (1< +#include + +#pragma warning (push) +#pragma warning (disable : 4100) +#pragma warning (disable : 4514) +#pragma warning (disable : 26495) + +template +inline void Construct(T* pMemory) { + ::new(pMemory) T; +} + +template +inline void CopyConstruct(T* pMemory, T const& src) { + ::new(pMemory) T(src); +} + +template +inline void Destruct(T* pMemory) { + pMemory->~T(); +} + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T > +class CUtlMemory { +public: + // constructor, destructor + CUtlMemory(int nGrowSize = 0, int nInitSize = 0); + CUtlMemory(T* pMemory, int numElements); + ~CUtlMemory(); + + // element access + T& operator[](int i); + T const& operator[](int i) const; + T& Element(int i); + T const& Element(int i) const; + + // Can we use this index? + bool IsIdxValid(int i) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Attaches the buffer to external memory.... + void SetExternalBuffer(T* pMemory, int numElements); + + // Size + int NumAllocated() const; + int Count() const; + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow(int num = 1); + + // Memory deallocation + void Purge(); + + // is the memory externally allocated? + bool IsExternallyAllocated() const; + + // Set the size by which the memory grows + void SetGrowSize(int size); + +private: + enum { + EXTERNAL_BUFFER_MARKER = -1, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< class T > +CUtlMemory::CUtlMemory(int nGrowSize, int nInitAllocationCount) : m_pMemory(0), +m_nAllocationCount(nInitAllocationCount), m_nGrowSize(nGrowSize) { + //Assert((nGrowSize >= 0) && (nGrowSize != EXTERNAL_BUFFER_MARKER)); + if (m_nAllocationCount) { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +template< class T > +CUtlMemory::CUtlMemory(T* pMemory, int numElements) : m_pMemory(pMemory), +m_nAllocationCount(numElements) { + // Special marker indicating externally supplied memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T > +CUtlMemory::~CUtlMemory() { + Purge(); +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T > +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; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T > +inline T& CUtlMemory::operator[](int i) { + //Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T const& CUtlMemory::operator[](int i) const { + //Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T& CUtlMemory::Element(int i) { + //Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T const& CUtlMemory::Element(int i) const { + //Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + + +//----------------------------------------------------------------------------- +// is the memory externally allocated? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlMemory::IsExternallyAllocated() const { + return m_nGrowSize == EXTERNAL_BUFFER_MARKER; +} + + +template< class T > +void CUtlMemory::SetGrowSize(int nSize) { + //Assert((nSize >= 0) && (nSize != EXTERNAL_BUFFER_MARKER)); + m_nGrowSize = nSize; +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- +template< class T > +inline T* CUtlMemory::Base() { + return m_pMemory; +} + +template< class T > +inline T const* CUtlMemory::Base() const { + return m_pMemory; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlMemory::NumAllocated() const { + return m_nAllocationCount; +} + +template< class T > +inline int CUtlMemory::Count() const { + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T > +inline bool CUtlMemory::IsIdxValid(int i) const { + return (i >= 0) && (i < m_nAllocationCount); +} + +#pragma warning (push) +#pragma warning (disable : 6308) + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +template< class T > +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; + while (m_nAllocationCount < nAllocationRequested) { + if (m_nAllocationCount != 0) { + if (m_nGrowSize) { + m_nAllocationCount += m_nGrowSize; + } + else { + m_nAllocationCount += m_nAllocationCount; + } + } + else { + // Compute an allocation which is at least as big as a cache line... + m_nAllocationCount = (31 + sizeof(T)) / sizeof(T); + assert(m_nAllocationCount != 0); + } + } + + if (m_pMemory) { + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } + else { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +#pragma warning (pop) + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::Purge() { + if (!IsExternallyAllocated()) { + if (m_pMemory) { + free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + +template +class CUtlVector { +public: + typedef T ElemType_t; + + // constructor, destructor + CUtlVector(int growSize = 0, int initSize = 0); + CUtlVector(T* pMemory, int numElements); + ~CUtlVector(); + + // Copy the array. + CUtlVector& operator=(const CUtlVector& other); + + // 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; + + // Returns the number of elements in the vector + // SIZE IS DEPRECATED! + int Count() const; + int Size() const; // don't use me! + + // Is element index valid? + bool IsValidIndex(int i) const; + static int InvalidIndex(void); + + // 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(T const& src); + int AddToTail(T const& src); + int InsertBefore(int elem, T const& src); + int InsertAfter(int elem, T const& 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); + + // Calls SetSize and copies each element. + void CopyArray(T const* pArray, int size); + + // Add the specified array to the tail. + int AddVectorToTail(CUtlVector const& src); + + // Finds an element (element needs operator== defined) + int Find(T const& src) const; + + bool HasElement(T const& src); + + // 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 + void FindAndRemove(T const& src); // removes first occurrence of src, preserves order, shifts elements + void RemoveMultiple(int elem, int num); // preserves order, shifts elements + void RemoveAll(); // doesn't deallocate memory + + // Memory deallocation + void Purge(); + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize(int size); + + // Can't copy this unless we explicitly do it! + CUtlVector(CUtlVector const& vec) { + assert(0); + } + +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); + + // For easier access to the elements through the debugger + void ResetDbgInfo(); + + CUtlMemory m_Memory; + int m_Size; + + // 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; +}; + +//----------------------------------------------------------------------------- +// For easier access to the elements through the debugger +//----------------------------------------------------------------------------- + +template< class T > +inline void CUtlVector::ResetDbgInfo() { + m_pElements = m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T > +inline CUtlVector::CUtlVector(int growSize, int initSize) : + m_Memory(growSize, initSize), m_Size(0) { + ResetDbgInfo(); +} + +template< class T > +inline CUtlVector::CUtlVector(T* pMemory, int numElements) : + m_Memory(pMemory, numElements), m_Size(0) { + ResetDbgInfo(); +} + +template< class T > +inline CUtlVector::~CUtlVector() { + Purge(); +} + +template +inline CUtlVector& CUtlVector::operator=(const CUtlVector& other) { + CopyArray(other.Base(), other.Count()); + return *this; +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- + +template< class T > +inline T& CUtlVector::operator[](int i) { + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template< class T > +inline T const& CUtlVector::operator[](int i) const { + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template< class T > +inline T& CUtlVector::Element(int i) { + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template< class T > +inline T const& CUtlVector::Element(int i) const { + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- + +template< class T > +inline T* CUtlVector::Base() { + return m_Memory.Base(); +} + +template< class T > +inline T const* CUtlVector::Base() const { + return m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::Size() const { + return m_Size; +} + +template< class T > +inline int CUtlVector::Count() const { + return m_Size; +} + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- + +template< class T > +inline bool CUtlVector::IsValidIndex(int i) const { + return (i >= 0) && (i < m_Size); +} + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlVector::InvalidIndex(void) { + return -1; +} + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::GrowVector(int num) { + if (m_Size + num - 1 >= m_Memory.NumAllocated()) { + m_Memory.Grow(m_Size + num - m_Memory.NumAllocated()); + } + + m_Size += num; + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::EnsureCount(int num) { + if (Count() < num) + AddMultipleToTail(num - Count()); +} + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< class T > +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)) + memmove(&Element(elem + num), &Element(elem), numToMove * sizeof(T)); +} + +template< class T > +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)) { + memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T)); + +#ifdef _DEBUG + memset(&Element(m_Size - num), 0xDD, num * sizeof(T)); +#endif + } +} + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddToHead() { + return InsertBefore(0); +} + +template< class T > +inline int CUtlVector::AddToTail() { + return InsertBefore(m_Size); +} + +template< class T > +inline int CUtlVector::InsertAfter(int elem) { + return InsertBefore(elem + 1); +} + +template< class T > +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< class T > +inline int CUtlVector::AddToHead(T const& src) { + return InsertBefore(0, src); +} + +template< class T > +inline int CUtlVector::AddToTail(T const& src) { + return InsertBefore(m_Size, src); +} + +template< class T > +inline int CUtlVector::InsertAfter(int elem, T const& src) { + return InsertBefore(elem + 1, src); +} + +template< class T > +int CUtlVector::InsertBefore(int elem, T const& src) { + // 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< class T > +inline int CUtlVector::AddMultipleToHead(int num) { + return InsertMultipleBefore(0, num); +} + +template< class T > +inline int CUtlVector::AddMultipleToTail(int num, const T* pToCopy) { + return InsertMultipleBefore(m_Size, num, pToCopy); +} + +template< class T > +int CUtlVector::InsertMultipleAfter(int elem, int num) { + return InsertMultipleBefore(elem + 1, num); +} + + +template< class T > +void CUtlVector::SetCount(int count) { + RemoveAll(); + AddMultipleToTail(count); +} + +template< class T > +inline void CUtlVector::SetSize(int size) { + SetCount(size); +} + +template< class T > +void CUtlVector::CopyArray(T const* pArray, int size) { + SetSize(size); + for (int i = 0; i < size; i++) + (*this)[i] = pArray[i]; +} + +template< class T > +int CUtlVector::AddVectorToTail(CUtlVector const& src) { + 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< class T > +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< class T > +int CUtlVector::Find(T const& src) const { + for (int i = 0; i < Count(); ++i) { + if (Element(i) == src) + return i; + } + return -1; +} + +template< class T > +bool CUtlVector::HasElement(T const& src) { + return (Find(src) >= 0); +} + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- + +template< class T > +void CUtlVector::FastRemove(int elem) { + assert(IsValidIndex(elem)); + + Destruct(&Element(elem)); + if (m_Size > 0) { + Q_memcpy(&Element(elem), &Element(m_Size - 1), sizeof(T)); + --m_Size; + } +} + +template< class T > +void CUtlVector::Remove(int elem) { + Destruct(&Element(elem)); + ShiftElementsLeft(elem); + --m_Size; +} + +template< class T > +void CUtlVector::FindAndRemove(T const& src) { + int elem = Find(src); + if (elem != -1) { + Remove(elem); + } +} + +template< class T > +void CUtlVector::RemoveMultiple(int elem, int num) { + assert(IsValidIndex(elem)); + assert(elem + num <= Count()); + + for (int i = elem + num; --i >= elem;) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< class T > +void CUtlVector::RemoveAll() { + for (int i = m_Size; --i >= 0;) + Destruct(&Element(i)); + + m_Size = 0; +} + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< class T > +void CUtlVector::Purge() { + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + +template +inline void CUtlVector::PurgeAndDeleteElements() { + for (int i = 0; i < m_Size; i++) + delete Element(i); + + Purge(); +} + +template< class T > +void CUtlVector::SetGrowSize(int size) { + m_Memory.SetGrowSize(size); +} + +#pragma warning (pop) \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/Activity.h b/Amalgam/src/SDK/Definitions/Misc/Activity.h new file mode 100644 index 0000000..9c6d657 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/Activity.h @@ -0,0 +1,2200 @@ +#pragma once + +#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, + + // passtime + ACT_BALL_VM_CATCH, + ACT_BALL_VM_PICKUP, + ACT_BALL_VM_IDLE, + ACT_BALL_VM_THROW_START, + ACT_BALL_VM_THROW_LOOP, + ACT_BALL_VM_THROW_END, + + // Competitive loser + ACT_MP_COMPETITIVE_LOSERSTATE, + ACT_MP_COMPETITIVE_WINNERSTATE, + + // Shortstop alt-fire + ACT_SECONDARY_VM_ALTATTACK, + ACT_MP_PUSH_STAND_SECONDARY, + ACT_MP_PUSH_CROUCH_SECONDARY, + ACT_MP_PUSH_SWIM_SECONDARY, + + // this is the end of the global activities, private per-monster activities start here. + LAST_SHARED_ACTIVITY, +} Activity; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/AnalogCode.h b/Amalgam/src/SDK/Definitions/Misc/AnalogCode.h new file mode 100644 index 0000000..22431be --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/AnalogCode.h @@ -0,0 +1,17 @@ +#pragma once +#include "InputEnums.h" + +#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 ) ) + +enum AnalogCode_t +{ + ANALOG_CODE_INVALID = -1, + MOUSE_X = 0, + MOUSE_Y, + MOUSE_XY, + MOUSE_WHEEL, + JOYSTICK_FIRST_AXIS, + JOYSTICK_LAST_AXIS = JOYSTICK_AXIS_INTERNAL(MAX_JOYSTICKS - 1, MAX_JOYSTICK_AXES - 1), + ANALOG_CODE_LAST +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h b/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h new file mode 100644 index 0000000..4568126 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h @@ -0,0 +1,126 @@ +#pragma once + +#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) diff --git a/Amalgam/src/SDK/Definitions/Misc/BaseTypes.h b/Amalgam/src/SDK/Definitions/Misc/BaseTypes.h new file mode 100644 index 0000000..70be8c0 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/BaseTypes.h @@ -0,0 +1,96 @@ +#pragma once +#include "CommonMacros.h" + +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; +} + +template< class T > +T Min(T const& val1, T const& val2) +{ + return val1 < val2 ? val1 : val2; +} + +template< class T > +T Max(T const& val1, T const& val2) +{ + return val1 > val2 ? val1 : val2; +} + +typedef int qboolean; +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned short word; +typedef wchar_t ucs2; + +enum ThreeState_t +{ + TRS_FALSE, + TRS_TRUE, + TRS_NONE +}; + +typedef float vec_t; + +struct color24 +{ + byte r, g, b; +}; + +typedef struct color32_s +{ + byte r, g, b, a; +} color32; + +struct colorVec +{ + unsigned r, g, b, a; +}; + +struct vrect_t +{ + int x, y, width, height; + vrect_t* pnext; +}; + +struct Rect_t +{ + int x, y; + int width, height; +}; + +struct wrect_t +{ + int left; + int right; + int top; + int bottom; +}; + +struct interval_t +{ + float start; + float range; +}; + +using uint32 = unsigned int; +typedef unsigned char uint8; +typedef signed char int8; +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; +typedef uint32 RTime32; +typedef float float32; +typedef double float64; +typedef unsigned int uint; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ButtonCode.h b/Amalgam/src/SDK/Definitions/Misc/ButtonCode.h new file mode 100644 index 0000000..9cbdece --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ButtonCode.h @@ -0,0 +1,245 @@ +#pragma once +#include "InputEnums.h" + +enum +{ + JOYSTICK_MAX_BUTTON_COUNT = 32, + JOYSTICK_POV_BUTTON_COUNT = 4, + JOYSTICK_AXIS_BUTTON_COUNT = MAX_JOYSTICK_AXES * 2 +}; + +enum +{ + STEAMCONTROLLER_MAX_BUTTON_COUNT = SK_MAX_KEYS - 1, + STEAMCONTROLLER_AXIS_BUTTON_COUNT = MAX_STEAMPADAXIS * 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 ) ) + +#define STEAMCONTROLLER_BUTTON_INTERNAL( _joystick, _button ) ( STEAMCONTROLLER_FIRST_BUTTON + ((_joystick) * STEAMCONTROLLER_MAX_BUTTON_COUNT) + (_button) ) +#define STEAMCONTROLLER_AXIS_BUTTON_INTERNAL( _joystick, _button ) ( STEAMCONTROLLER_FIRST_AXIS_BUTTON + ((_joystick) * STEAMCONTROLLER_AXIS_BUTTON_COUNT) + (_button) ) +#define STEAMCONTROLLER_BUTTON( _joystick, _button ) ( (ButtonCode_t)STEAMCONTROLLER_BUTTON_INTERNAL( _joystick, _button ) ) +#define STEAMCONTROLLER_AXIS_BUTTON( _joystick, _button ) ( (ButtonCode_t)STEAMCONTROLLER_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_FIRST = KEY_LAST + 1, + MOUSE_LEFT = MOUSE_FIRST, + MOUSE_RIGHT, + MOUSE_MIDDLE, + MOUSE_4, + MOUSE_5, + MOUSE_WHEEL_UP, + MOUSE_WHEEL_DOWN, + MOUSE_LAST = MOUSE_WHEEL_DOWN, + MOUSE_COUNT = MOUSE_LAST - MOUSE_FIRST + 1, + 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, + NOVINT_FIRST = JOYSTICK_LAST + 2, + 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, + STEAMCONTROLLER_FIRST = NOVINT_LAST + 1, + STEAMCONTROLLER_FIRST_BUTTON = STEAMCONTROLLER_FIRST, + STEAMCONTROLLER_LAST_BUTTON = STEAMCONTROLLER_BUTTON_INTERNAL(MAX_STEAM_CONTROLLERS - 1, STEAMCONTROLLER_MAX_BUTTON_COUNT - 1), + STEAMCONTROLLER_FIRST_AXIS_BUTTON, + STEAMCONTROLLER_LAST_AXIS_BUTTON = STEAMCONTROLLER_AXIS_BUTTON_INTERNAL(MAX_STEAM_CONTROLLERS - 1, STEAMCONTROLLER_AXIS_BUTTON_COUNT - 1), + STEAMCONTROLLER_LAST = STEAMCONTROLLER_LAST_AXIS_BUTTON, + BUTTON_CODE_LAST, + BUTTON_CODE_COUNT = BUTTON_CODE_LAST - KEY_FIRST + 1, + KEY_XBUTTON_UP = JOYSTICK_FIRST_POV_BUTTON, + KEY_XBUTTON_RIGHT, + KEY_XBUTTON_DOWN, + KEY_XBUTTON_LEFT, + KEY_XBUTTON_A = JOYSTICK_FIRST_BUTTON, + 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, + KEY_XSTICK1_LEFT, + KEY_XSTICK1_DOWN, + KEY_XSTICK1_UP, + KEY_XBUTTON_LTRIGGER, + KEY_XBUTTON_RTRIGGER, + KEY_XSTICK2_RIGHT, + KEY_XSTICK2_LEFT, + KEY_XSTICK2_DOWN, + KEY_XSTICK2_UP, + STEAMCONTROLLER_A = STEAMCONTROLLER_FIRST_BUTTON, + STEAMCONTROLLER_B, + STEAMCONTROLLER_X, + STEAMCONTROLLER_Y, + STEAMCONTROLLER_DPAD_UP, + STEAMCONTROLLER_DPAD_RIGHT, + STEAMCONTROLLER_DPAD_DOWN, + STEAMCONTROLLER_DPAD_LEFT, + STEAMCONTROLLER_LEFT_BUMPER, + STEAMCONTROLLER_RIGHT_BUMPER, + STEAMCONTROLLER_LEFT_TRIGGER, + STEAMCONTROLLER_RIGHT_TRIGGER, + STEAMCONTROLLER_LEFT_GRIP, + STEAMCONTROLLER_RIGHT_GRIP, + STEAMCONTROLLER_LEFT_PAD_FINGERDOWN, + STEAMCONTROLLER_RIGHT_PAD_FINGERDOWN, + STEAMCONTROLLER_LEFT_PAD_CLICK, + STEAMCONTROLLER_RIGHT_PAD_CLICK, + STEAMCONTROLLER_LEFT_PAD_UP, + STEAMCONTROLLER_LEFT_PAD_RIGHT, + STEAMCONTROLLER_LEFT_PAD_DOWN, + STEAMCONTROLLER_LEFT_PAD_LEFT, + STEAMCONTROLLER_RIGHT_PAD_UP, + STEAMCONTROLLER_RIGHT_PAD_RIGHT, + STEAMCONTROLLER_RIGHT_PAD_DOWN, + STEAMCONTROLLER_RIGHT_PAD_LEFT, + STEAMCONTROLLER_SELECT, + STEAMCONTROLLER_START, + STEAMCONTROLLER_STEAM, + STEAMCONTROLLER_INACTIVE_START, + STEAMCONTROLLER_F1, + STEAMCONTROLLER_F2, + STEAMCONTROLLER_F3, + STEAMCONTROLLER_F4, + STEAMCONTROLLER_F5, + STEAMCONTROLLER_F6, + STEAMCONTROLLER_F7, + STEAMCONTROLLER_F8, + STEAMCONTROLLER_F9, + STEAMCONTROLLER_F10, + STEAMCONTROLLER_F11, + STEAMCONTROLLER_F12 +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/CGameEventListener.h b/Amalgam/src/SDK/Definitions/Misc/CGameEventListener.h new file mode 100644 index 0000000..1561925 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/CGameEventListener.h @@ -0,0 +1,11 @@ +#pragma once +#include "../Interfaces/IGameEvents.h" + +class CGameEventListener : public IGameEventListener2 +{ +public: + virtual void FireGameEvent(IGameEvent* event) = 0; + +private: + bool m_bRegisteredForEvents; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/CPlayerResource.h b/Amalgam/src/SDK/Definitions/Misc/CPlayerResource.h new file mode 100644 index 0000000..92a8902 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/CPlayerResource.h @@ -0,0 +1,22 @@ +#pragma once +#include "IGameResources.h" +#include "String.h" +#include "../Main/CBaseEntity.h" + +#define PLAYER_UNCONNECTED_NAME "unconnected" +#define PLAYER_ERROR_NAME "ERRORNAME" + +class CPlayerResource : public CBaseEntity, public IGameResources +{ +public: + NETVAR(m_iPing, void*, "CPlayerResource", "m_iPing"); + NETVAR(m_iScore, void*, "CPlayerResource", "m_iScore"); + NETVAR(m_iDeaths, void*, "CPlayerResource", "m_iDeaths"); + NETVAR(m_bConnected, void*, "CPlayerResource", "m_bConnected"); + NETVAR(m_iTeam, void*, "CPlayerResource", "m_iTeam"); + NETVAR(m_bAlive, void*, "CPlayerResource", "m_bAlive"); + NETVAR(m_iHealth, void*, "CPlayerResource", "m_iHealth"); + NETVAR(m_iAccountID, void*, "CPlayerResource", "m_iAccountID"); + NETVAR(m_bValid, void*, "CPlayerResource", "m_bValid"); + NETVAR(m_iUserID, void*, "CPlayerResource", "m_iUserID"); +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/CViewSetup.h b/Amalgam/src/SDK/Definitions/Misc/CViewSetup.h new file mode 100644 index 0000000..ef4f902 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/CViewSetup.h @@ -0,0 +1,48 @@ +#pragma once +#include "../Types.h" + +enum StereoEye_t +{ + STEREO_EYE_MONO = 0, + STEREO_EYE_LEFT = 1, + STEREO_EYE_RIGHT = 2, + STEREO_EYE_MAX = 3 +}; + +class CViewSetup +{ +public: + int x; + int m_nUnscaledX; + int y; + int m_nUnscaledY; + int width; + int m_nUnscaledWidth; + int height; + StereoEye_t m_eStereoEye; + int m_nUnscaledHeight; + bool m_bOrtho; + float m_OrthoLeft; + float m_OrthoTop; + float m_OrthoRight; + float m_OrthoBottom; + float fov; + float fovViewmodel; + Vector origin; + QAngle angles; + float zNear; + float zFar; + float zNearViewmodel; + float zFarViewmodel; + bool m_bRenderToSubrectOfLargerScreen; + float m_flAspectRatio; + bool m_bOffCenter; + float m_flOffCenterTop; + float m_flOffCenterBottom; + float m_flOffCenterLeft; + float m_flOffCenterRight; + bool m_bDoBloomAndToneMapping; + bool m_bCacheFullSceneState; + bool m_bViewToProjectionOverride; + VMatrix m_ViewToProjection; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ChecksumCRC.cpp b/Amalgam/src/SDK/Definitions/Misc/ChecksumCRC.cpp new file mode 100644 index 0000000..3126a2c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ChecksumCRC.cpp @@ -0,0 +1,179 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic CRC functions +// +//=============================================================================// + +#include "ChecksumCRC.h" +#include + +#define CRC32_INIT_VALUE 0xFFFFFFFFUL +#define CRC32_XOR_VALUE 0xFFFFFFFFUL +#define LittleLong( val )( val ) + +#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]; +} + +#pragma warning (disable : 26819) + +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 = std::uintptr_t(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; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ChecksumCRC.h b/Amalgam/src/SDK/Definitions/Misc/ChecksumCRC.h new file mode 100644 index 0000000..ab5b2ad --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ChecksumCRC.h @@ -0,0 +1,19 @@ +#pragma once + +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; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ClientClass.h b/Amalgam/src/SDK/Definitions/Misc/ClientClass.h new file mode 100644 index 0000000..aee8622 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ClientClass.h @@ -0,0 +1,20 @@ +#pragma once +#include "dt_recv.h" + +class IClientNetworkable; + +typedef IClientNetworkable* (*CreateClientClassFn)(int entnum, int serialNum); +typedef IClientNetworkable* (*CreateEventFn)(); + +class ClientClass +{ +public: + CreateClientClassFn m_pCreateFn; + CreateEventFn m_pCreateEventFn; + const char* m_pNetworkName; + RecvTable* m_pRecvTable; + ClientClass* m_pNext; + int m_ClassID; + + const char* GetName() { return m_pNetworkName; } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/CommonMacros.h b/Amalgam/src/SDK/Definitions/Misc/CommonMacros.h new file mode 100644 index 0000000..fe4ebb2 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/CommonMacros.h @@ -0,0 +1,8 @@ +#pragma once + +#define MAKEID(d, c, b, a) (((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d))) +#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)) \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ConVar.h b/Amalgam/src/SDK/Definitions/Misc/ConVar.h new file mode 100644 index 0000000..74cbb7c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ConVar.h @@ -0,0 +1,172 @@ +#pragma once +#include "IConVar.h" +#include "../Main/UtlVector.h" + +class ConVar; +class CCommand; +class ConCommand; +class ConCommandBase; +struct characterset_t; + +class IConCommandBaseAccessor +{ +public: + virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; +}; + +typedef void (*FnCommandCallbackVoid_t)(void); +typedef void (*FnCommandCallback_t)(const CCommand& command); + +#define COMMAND_COMPLETION_MAXITEMS 64 +#define COMMAND_COMPLETION_ITEM_LENGTH 64 + +typedef int (*FnCommandCompletionCallback)(const char* partial, char commands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]); + +class ICommandCallback +{ +public: + virtual void CommandCallback(const CCommand& command) = 0; +}; + +class ICommandCompletionCallback +{ +public: + virtual int CommandCompletionCallback(const char* pPartial, CUtlVector< /*CUtlString*/ void* >& commands) = 0; +}; + +class ConCommandBase +{ +public: + virtual ~ConCommandBase(void); + virtual bool IsCommand(void) const; + virtual bool IsFlagSet(int flag) const; + virtual void AddFlags(int flags); + virtual const char* GetName(void) const; + virtual const char* GetHelpText(void) const; + virtual bool IsRegistered(void) const; + virtual void* GetDLLIdentifier() const; + virtual void CreateBase(const char* pName, const char* pHelpString = 0, int flags = 0); + virtual void Init(); + +public: + ConCommandBase* m_pNext; + bool m_bRegistered; + const char* m_pszName; + const char* m_pszHelpString; + int m_nFlags; + +protected: + static ConCommandBase* s_pConCommandBases; + static IConCommandBaseAccessor* s_pAccessor; +}; + +enum +{ + COMMAND_MAX_ARGC = 64, + COMMAND_MAX_LENGTH = 512 +}; + +class CCommand +{ +public: + 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]; +}; + +class ConCommand : public ConCommandBase +{ +public: + virtual ~ConCommand(void); + virtual bool IsCommand(void) const; + virtual int AutoCompleteSuggest(const char* partial, CUtlVector< /*CUtlString*/ void* >& commands); + virtual bool CanAutoComplete(void); + virtual void Dispatch(const CCommand& command); + +private: + 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; +}; + +class ConVar : public ConCommandBase, public IConVar +{ +public: + virtual ~ConVar(void) {}; + virtual bool IsFlagSet(int flag) const = 0; + virtual const char* GetHelpText(void) const = 0; + virtual bool IsRegistered(void) const = 0; + virtual const char* GetName(void) const = 0; + virtual void AddFlags(int flags) = 0; + virtual bool IsCommand(void) const = 0; + + inline float GetFloat(void) const; + inline int GetInt(void) const; + inline bool GetBool() const { return !!GetInt(); } + inline char const* GetString(void) const; + + virtual void SetValue(const char* value) = 0; + virtual void SetValue(float value) = 0; + virtual void SetValue(int value) = 0; + +private: + virtual void InternalSetValue(const char* value) = 0; + virtual void InternalSetFloatValue(float fNewValue, bool bForce = false) = 0; + virtual void InternalSetIntValue(int nValue) = 0; + virtual bool ClampValue(float& value) = 0; + virtual void ChangeStringValue(const char* tempVal, float flOldValue) = 0; + virtual void Init() = 0; + + int GetFlags() { return m_pParent->m_nFlags; } + +public: + ConVar* m_pParent; + const char* m_pszDefaultValue; + char* m_pszString; + int m_StringLength; + float m_fValue; + int m_nValue; + bool m_bHasMin; + float m_fMinVal; + bool m_bHasMax; + float m_fMaxVal; + bool m_bHasCompMin; + float m_fCompMinVal; + bool m_bHasCompMax; + float m_fCompMaxVal; + bool m_bCompetitiveRestrictions; + FnChangeCallback_t m_fnChangeCallback; +}; + +inline float ConVar::GetFloat(void) const +{ + return m_pParent->m_fValue; +} + +inline int ConVar::GetInt(void) const +{ + return m_pParent->m_nValue; +} + +inline 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 : ""; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/Cursor.h b/Amalgam/src/SDK/Definitions/Misc/Cursor.h new file mode 100644 index 0000000..fd98eff --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/Cursor.h @@ -0,0 +1,27 @@ +#pragma once +#include "VGUI.h" + +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, + dc_last, + dc_alwaysvisible_push, + dc_alwaysvisible_pop +}; + +typedef unsigned long HCursor; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/Datamap.h b/Amalgam/src/SDK/Definitions/Misc/Datamap.h new file mode 100644 index 0000000..9dd132d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/Datamap.h @@ -0,0 +1,123 @@ +#pragma once + +struct inputdata_t; + +#define INVALID_TIME (FLT_MAX * -1.0) + +typedef enum _fieldtypes +{ + FIELD_VOID = 0, + FIELD_FLOAT, + FIELD_STRING, + FIELD_VECTOR, + FIELD_QUATERNION, + FIELD_INTEGER, + FIELD_BOOLEAN, + FIELD_SHORT, + FIELD_CHARACTER, + FIELD_COLOR32, + FIELD_EMBEDDED, + FIELD_CUSTOM, + FIELD_CLASSPTR, + FIELD_EHANDLE, + FIELD_EDICT, + FIELD_POSITION_VECTOR, + FIELD_TIME, + FIELD_TICK, + FIELD_MODELNAME, + FIELD_SOUNDNAME, + FIELD_INPUT, + FIELD_FUNCTION, + FIELD_VMATRIX, + FIELD_VMATRIX_WORLDSPACE, + FIELD_MATRIX3X4_WORLDSPACE, + FIELD_INTERVAL, + FIELD_MODELINDEX, + FIELD_MATERIALINDEX, + FIELD_VECTOR2D, + FIELD_TYPECOUNT +} fieldtype_t; + +template +class CDatamapFieldSizeDeducer +{ +public: + enum + { + SIZE = 0 + }; + + static int FieldSize() + { + return 0; + } +}; + +#define FIELD_SIZE( _fieldType ) CDatamapFieldSizeDeducer<_fieldType>::SIZE +#define FIELD_BITS( _fieldType ) (FIELD_SIZE( _fieldType ) * 8) + +#define ARRAYSIZE2D(p) (sizeof(p)/sizeof(p[0][0])) +#define SIZE_OF_ARRAY(p) _ARRAYSIZE(p) + +#define _hacky_datamap_offsetof(s,m) ((size_t)&(((s *)0)->m)) + +#define FTYPEDESC_GLOBAL 0x0001 +#define FTYPEDESC_SAVE 0x0002 +#define FTYPEDESC_KEY 0x0004 +#define FTYPEDESC_INPUT 0x0008 +#define FTYPEDESC_OUTPUT 0x0010 +#define FTYPEDESC_FUNCTIONTABLE 0x0020 +#define FTYPEDESC_PTR 0x0040 +#define FTYPEDESC_OVERRIDE 0x0080 +#define FTYPEDESC_INSENDTABLE 0x0100 +#define FTYPEDESC_PRIVATE 0x0200 +#define FTYPEDESC_NOERRORCHECK 0x0400 +#define FTYPEDESC_MODELINDEX 0x0800 +#define FTYPEDESC_INDEX 0x1000 +#define FTYPEDESC_VIEW_OTHER_PLAYER 0x2000 +#define FTYPEDESC_VIEW_OWN_TEAM 0x4000 +#define FTYPEDESC_VIEW_NEVER 0x8000 +#define TD_MSECTOLERANCE 0.001f + +struct typedescription_t; +class ISaveRestoreOps; + +typedef void (*inputfunc_t)(inputdata_t& data); + +struct datamap_t; +struct typedescription_t; + +enum +{ + TD_OFFSET_NORMAL = 0, + TD_OFFSET_PACKED = 1, + TD_OFFSET_COUNT +}; + +struct typedescription_t +{ + fieldtype_t fieldType; + const char* fieldName; + int fieldOffset[TD_OFFSET_COUNT]; + unsigned short fieldSize; + short flags; + const char* externalName; + ISaveRestoreOps* pSaveRestoreOps; + inputfunc_t inputFunc; + datamap_t* td; + int fieldSizeInBytes; + struct typedescription_t* override_field; + int override_count; + float fieldTolerance; +}; + +struct datamap_t +{ + typedescription_t* dataDesc; + int dataNumFields; + char const* dataClassName; + datamap_t* baseMap; + bool chains_validated; + bool packed_offsets_computed; + int packed_size; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/Deformations.h b/Amalgam/src/SDK/Definitions/Misc/Deformations.h new file mode 100644 index 0000000..6b0dce9 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/Deformations.h @@ -0,0 +1,24 @@ +#pragma once +#include "../Types.h" + +enum DeformationType_t +{ + DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE = 1 +}; + +struct DeformationBase_t +{ + DeformationType_t m_eType; +}; + +struct BoxDeformation_t : DeformationBase_t +{ + Vector m_SourceMins; + float m_flPad0; + Vector m_SourceMaxes; + float m_flPad1; + Vector m_ClampMins; + float m_flPad2; + Vector m_ClampMaxes; + float m_flPad3; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IAppSystem.h b/Amalgam/src/SDK/Definitions/Misc/IAppSystem.h new file mode 100644 index 0000000..8c2c9e9 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IAppSystem.h @@ -0,0 +1,19 @@ +#pragma once +#include "../Interfaces/Interface.h" + +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + INIT_LAST_VAL, +}; + +class IAppSystem +{ +public: + 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; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IClientMode.h b/Amalgam/src/SDK/Definitions/Misc/IClientMode.h new file mode 100644 index 0000000..b509b03 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IClientMode.h @@ -0,0 +1,86 @@ +#pragma once +#include "VGUI.h" +#include "ButtonCode.h" +#include "../Main/CUserCmd.h" + +class CViewSetup; +class CBaseEntity; +class CBasePlayer; +class Panel; +class AnimationController; +class KeyValues; + +enum +{ + MM_NONE = 0, + MM_SAY, + MM_SAY_TEAM +}; + +enum HeadtrackMovementMode_t +{ + HMM_SHOOTFACE_MOVEFACE = 0, + HMM_SHOOTFACE_MOVETORSO, + HMM_SHOOTMOUSE_MOVEFACE, + HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEFACE, + HMM_SHOOTBOUNDEDMOUSE_LOOKFACE_MOVEMOUSE, + HMM_SHOOTMOVELOOKMOUSEFACE, + HMM_SHOOTMOVEMOUSE_LOOKFACE, + HMM_SHOOTMOVELOOKMOUSE, + HMM_LAST, + HMM_NOOVERRIDE = HMM_LAST +}; + +class IClientMode +{ +public: + virtual ~IClientMode() {} + virtual void InitViewport() = 0; + virtual void Init() = 0; + virtual void VGui_Shutdown() = 0; + virtual void Shutdown() = 0; + virtual void Enable() = 0; + virtual void Disable() = 0; + virtual void Layout() = 0; + virtual Panel* GetViewport() = 0; + virtual AnimationController* GetViewportAnimationController() = 0; + virtual void ProcessInput(bool bActive) = 0; + virtual bool ShouldDrawDetailObjects() = 0; + virtual bool ShouldDrawEntity(CBaseEntity* pEnt) = 0; + virtual bool ShouldDrawLocalPlayer(CBasePlayer* pPlayer) = 0; + virtual bool ShouldDrawParticles() = 0; + 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 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; + virtual bool ShouldDrawViewModel(void) = 0; + virtual bool ShouldDrawCrosshair(void) = 0; + virtual void AdjustEngineViewport(int& x, int& y, int& width, int& height) = 0; + virtual void PreRender(CViewSetup* pSetup) = 0; + virtual void PostRender(void) = 0; + virtual void PostRenderVGui() = 0; + virtual void ActivateInGameVGuiContext(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; + virtual wchar_t* GetServerName() = 0; + virtual void SetServerName(wchar_t* name) = 0; + virtual wchar_t* GetMapName() = 0; + virtual void SetMapName(wchar_t* name) = 0; + virtual bool DoPostScreenSpaceEffects(const CViewSetup* pSetup) = 0; + virtual void DisplayReplayMessage(const char* pLocalizeName, float flDuration, bool bUrgent, const char* pSound, bool bDlg) = 0; + virtual void Update() = 0; + virtual bool ShouldBlackoutAroundHUD() = 0; + virtual HeadtrackMovementMode_t ShouldOverrideHeadtrackControl() = 0; + virtual bool IsInfoPanelAllowed() = 0; + virtual void InfoPanelDisplayed() = 0; + virtual bool IsHTMLInfoPanelAllowed() = 0; + virtual void OnDemoRecordStart(char const* pDemoBaseName) = 0; + virtual void OnDemoRecordStop() = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IColorCorrectionSystem.h b/Amalgam/src/SDK/Definitions/Misc/IColorCorrectionSystem.h new file mode 100644 index 0000000..36ded3b --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IColorCorrectionSystem.h @@ -0,0 +1,40 @@ +#pragma once +#include "ImageFormat.h" +#include "BaseTypes.h" + +typedef unsigned int ColorCorrectionHandle_t; +struct ShaderColorCorrectionInfo_t; + +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; + virtual void GetCurrentColorCorrection(ShaderColorCorrectionInfo_t* pInfo) = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IConVar.h b/Amalgam/src/SDK/Definitions/Misc/IConVar.h new file mode 100644 index 0000000..c6881c6 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IConVar.h @@ -0,0 +1,48 @@ +#pragma once + +class IConVar; +class CCommand; + +#define FCVAR_NONE 0 +#define FCVAR_UNREGISTERED (1<<0) +#define FCVAR_DEVELOPMENTONLY (1<<1) +#define FCVAR_GAMEDLL (1<<2) +#define FCVAR_CLIENTDLL (1<<3) +#define FCVAR_HIDDEN (1<<4) +#define FCVAR_PROTECTED (1<<5) +#define FCVAR_SPONLY (1<<6) +#define FCVAR_ARCHIVE (1<<7) +#define FCVAR_NOTIFY (1<<8) +#define FCVAR_USERINFO (1<<9) +#define FCVAR_CHEAT (1<<14) +#define FCVAR_PRINTABLEONLY (1<<10) +#define FCVAR_UNLOGGED (1<<11) +#define FCVAR_NEVER_AS_STRING (1<<12) +#define FCVAR_REPLICATED (1<<13) +#define FCVAR_DEMO (1<<16) +#define FCVAR_DONTRECORD (1<<17) +#define FCVAR_RELOAD_MATERIALS (1<<20) +#define FCVAR_RELOAD_TEXTURES (1<<21) +#define FCVAR_NOT_CONNECTED (1<<22) +#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) +#define FCVAR_ARCHIVE_XBOX (1<<24) +#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) +#define FCVAR_SERVER_CAN_EXECUTE (1<<28) +#define FCVAR_SERVER_CANNOT_QUERY (1<<29) +#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) +#define FCVAR_EXEC_DESPITE_DEFAULT (1<<31) +#define FCVAR_INTERNAL_USE (1<<15) +#define FCVAR_ALLOWED_IN_COMPETITIVE (1<<18) +#define FCVAR_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD ) + +typedef void (*FnChangeCallback_t)(IConVar* var, const char* pOldValue, float flOldValue); + +class IConVar +{ +public: + virtual void SetValue(const char* pValue) = 0; + virtual void SetValue(float flValue) = 0; + virtual void SetValue(int nValue) = 0; + virtual const char* GetName(void) const = 0; + virtual bool IsFlagSet(int nFlag) const = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IGameResources.h b/Amalgam/src/SDK/Definitions/Misc/IGameResources.h new file mode 100644 index 0000000..db118ad --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IGameResources.h @@ -0,0 +1,21 @@ +#pragma once + +class IGameResources +{ +public: + /*virtual ~IGameResources() {}; + virtual const char *GetTeamName(int index) = 0; + virtual int GetTeamScore(int index) = 0; + virtual const Color &GetTeamColor(int index) = 0; + virtual bool IsConnected(int index) = 0; + virtual bool IsAlive(int index) = 0; + virtual bool IsFakePlayer(int index) = 0; + virtual bool IsLocalPlayer(int index) = 0; + virtual const char *GetPlayerName(int index) = 0; + virtual int GetPlayerScore(int index) = 0; + virtual int GetPing(int index) = 0; + virtual int GetDeaths(int index) = 0; + virtual int GetFrags(int index) = 0; + virtual int GetTeam(int index) = 0; + virtual int GetHealth(int index) = 0;*/ +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IHTML.h b/Amalgam/src/SDK/Definitions/Misc/IHTML.h new file mode 100644 index 0000000..081a4de --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IHTML.h @@ -0,0 +1,109 @@ +#pragma once +#include "Cursor.h" +#include "IImage.h" +#include "KeyCode.h" +#include "MouseCode.h" + +enum MOUSE_STATE +{ + UP, + DOWN, + MMOVE, + DBLCLICK +}; + +enum EWebPageLoadError +{ + eLoadErrorNone = 0, + eMimeTypeNotSupported, + eCacheMiss, + eBadURL, + eConnectionProblem, + eProxyConnectionProblem, + eLoadErrorUnknown +}; + +class IHTML +{ +public: + virtual void OpenURL(const char*) = 0; + virtual bool StopLoading() = 0; + virtual bool Refresh() = 0; + virtual bool Show(bool shown) = 0; + virtual const char* GetOpenedPage() = 0; + virtual void Obsolete_OnSize(int x, int y, int w, int h) = 0; + virtual void GetHTMLSize(int& wide, int& tall) = 0; + virtual void Clear() = 0; + virtual void AddText(const char* text) = 0; + 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 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; + virtual void OnKeyUp(KeyCode code, bool bPopupMenu) = 0; + virtual void PostURL(const char* pchURL, const char* pchPostData) = 0; + 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; + virtual void AddHeader(const char* pchHeader, const char* pchValue) = 0; + virtual void SetFileDialogChoice(const char* pchFileName) = 0; + virtual void HidePopup() = 0; + virtual void SetHTMLFocus() = 0; + virtual void KillHTMLFocus() = 0; + 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; + virtual bool IsIERender() = 0; + virtual void GetIDispatchPtr(void** pIDispatch) = 0; + virtual void GetHTMLScroll(int& top, int& left) = 0; +}; + +class IHTMLEvents +{ +public: + 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; + virtual void OnURLChanged(const char* url, const char* pchPostData, bool bIsRedirect) = 0; + virtual void OnFinishRequest(const char* url, const char* pageTitle) = 0; + virtual bool OnStartRequestInternal(const char* url, const char* target, const char* pchPostData, bool bIsRedirect) = 0; + virtual void ShowPopup(int x, int y, int wide, int tall) = 0; + virtual void HidePopup() = 0; + virtual bool OnPopupHTMLWindow(const char* pchURL, int x, int y, int wide, int tall) = 0; + virtual void SetHTMLTitle(const char* pchTitle) = 0; + virtual void OnLoadingResource(const char* pchURL) = 0; + virtual void OnSetStatusText(const char* text) = 0; + virtual void OnSetCursor(CursorCode cursor) = 0; + virtual void OnFileLoadDialog(const char* pchTitle, const char* pchInitialFile) = 0; + virtual void OnShowToolTip(const char* pchText) = 0; + virtual void OnUpdateToolTip(const char* pchText) = 0; + virtual void OnHideToolTip() = 0; + 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; + virtual bool OnOpenNewTab(const char* pchURL, bool bForeground) = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IImage.h b/Amalgam/src/SDK/Definitions/Misc/IImage.h new file mode 100644 index 0000000..1ee7ed3 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IImage.h @@ -0,0 +1,30 @@ +#pragma once +#include "VGUI.h" +#include "../Types.h" + +typedef unsigned long HTexture; + +enum iimage_rotation_t +{ + ROTATED_UNROTATED = 0, + ROTATED_CLOCKWISE_90, + ROTATED_ANTICLOCKWISE_90, + ROTATED_FLIPPED +}; + +class IImage +{ +public: + virtual void Paint() = 0; + virtual void SetPos(int x, int y) = 0; + virtual void GetContentSize(int& wide, int& tall) = 0; + virtual void GetSize(int& wide, int& tall) = 0; + virtual void SetSize(int wide, int tall) = 0; + virtual void SetColor(Color_t col) = 0; + virtual ~IImage() {} + virtual bool Evict() = 0; + virtual int GetNumFrames() = 0; + virtual void SetFrame(int nFrame) = 0; + virtual HTexture GetID() = 0; + virtual void SetRotation(int iRotation) = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IMDLCache.h b/Amalgam/src/SDK/Definitions/Misc/IMDLCache.h new file mode 100644 index 0000000..f75019f --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IMDLCache.h @@ -0,0 +1,109 @@ +#pragma once +#include "IAppSystem.h" + +struct studiohdr_t; +struct studiohwdata_t; +struct vcollide_t; +struct virtualmodel_t; +struct vertexFileHeader_t; +struct FileHeader_t; + +typedef unsigned short MDLHandle_t; + +enum +{ + MDLHANDLE_INVALID = (MDLHandle_t)~0 +}; + +enum MDLCacheDataType_t +{ + MDLCACHE_STUDIOHDR = 0, + MDLCACHE_STUDIOHWDATA, + MDLCACHE_VCOLLIDE, + MDLCACHE_ANIMBLOCK, + MDLCACHE_VIRTUALMODEL, + MDLCACHE_VERTEXES, + MDLCACHE_DECODEDANIMBLOCK +}; + +class IMDLCacheNotify +{ +public: + virtual void OnDataLoaded(MDLCacheDataType_t type, MDLHandle_t handle) = 0; + virtual void OnDataUnloaded(MDLCacheDataType_t type, MDLHandle_t handle) = 0; +}; + +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 +}; + +class IMDLCache : public IAppSystem +{ +public: + virtual void SetCacheNotify(IMDLCacheNotify* pNotify) = 0; + virtual MDLHandle_t FindMDL(const char* pMDLRelativePath) = 0; + virtual int AddRef(MDLHandle_t handle) = 0; + virtual int Release(MDLHandle_t handle) = 0; + virtual int GetRef(MDLHandle_t handle) = 0; + 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; + virtual void TouchAllData(MDLHandle_t handle) = 0; + virtual void SetUserData(MDLHandle_t handle, void* pData) = 0; + virtual void* GetUserData(MDLHandle_t handle) = 0; + virtual bool IsErrorModel(MDLHandle_t handle) = 0; + virtual void Flush(MDLCacheFlush_t nFlushFlags = MDLCACHE_FLUSH_ALL) = 0; + virtual void Flush(MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL) = 0; + virtual const char* GetModelName(MDLHandle_t handle) = 0; + virtual virtualmodel_t* GetVirtualModelFast(const studiohdr_t* pStudioHdr, MDLHandle_t handle) = 0; + virtual void BeginLock() = 0; + virtual void EndLock() = 0; + virtual int* GetFrameUnlockCounterPtrOLD() = 0; + 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; + virtual void ResetErrorModelStatus(MDLHandle_t handle) = 0; + virtual void MarkFrame() = 0; +}; + +class CMDLCacheCriticalSection +{ +public: + CMDLCacheCriticalSection(IMDLCache* pCache) : m_pCache(pCache) + { + m_pCache->BeginLock(); + } + + ~CMDLCacheCriticalSection() + { + m_pCache->EndLock(); + } + +private: + IMDLCache* m_pCache; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IMaterialSystemHardwareConfig.h b/Amalgam/src/SDK/Definitions/Misc/IMaterialSystemHardwareConfig.h new file mode 100644 index 0000000..4331af4 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IMaterialSystemHardwareConfig.h @@ -0,0 +1,96 @@ +#pragma once + +enum HDRType_t +{ + HDR_TYPE_NONE, + HDR_TYPE_INTEGER, + HDR_TYPE_FLOAT +}; + +enum VertexCompressionType_t +{ + VERTEX_COMPRESSION_INVALID = 0xFFFFFFFF, + VERTEX_COMPRESSION_NONE = 0, + VERTEX_COMPRESSION_ON = 1 +}; + +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) virtual ret_type method const = 0; + +class IMaterialSystemHardwareConfig +{ +public: + 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; + virtual bool SupportsNormalMapCompression() const { return false; } + 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; + 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; + 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; + DEFCONFIGMETHOD(int, GetDXSupportLevel(), 98); + virtual const char* GetShaderDLLName() const = 0; + virtual bool ReadPixelsFromFrontBuffer() const = 0; + 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; + virtual bool PreferReducedFillrate() const = 0; + virtual int GetMaxDXSupportLevel() const = 0; + virtual bool SpecifiesFogColorInLinearSpace() const = 0; + DEFCONFIGMETHOD(bool, SupportsSRGB(), true); + DEFCONFIGMETHOD(bool, FakeSRGBWrite(), false); + DEFCONFIGMETHOD(bool, CanDoSRGBReadFromRTs(), true); + virtual bool SupportsGLMixedSizeTargets() const = 0; + virtual bool IsAAEnabled() const = 0; + 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; + 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; + virtual bool CanStretchRectFromTextures(void) const = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IPrediction.h b/Amalgam/src/SDK/Definitions/Misc/IPrediction.h new file mode 100644 index 0000000..4183805 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IPrediction.h @@ -0,0 +1,21 @@ +#pragma once +#include "../Types.h" + +class IPrediction +{ +public: + virtual ~IPrediction(void) {}; + virtual void Init(void) = 0; + virtual void Shutdown(void) = 0; + virtual void Update(int startframe, bool validframe, int incoming_acknowledged, int outgoing_command) = 0; + 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; + 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; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IRefCounted.h b/Amalgam/src/SDK/Definitions/Misc/IRefCounted.h new file mode 100644 index 0000000..e64f86a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IRefCounted.h @@ -0,0 +1,8 @@ +#pragma once + +class IRefCounted +{ +public: + virtual int AddRef() = 0; + virtual int Release() = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ISpatialPartition.h b/Amalgam/src/SDK/Definitions/Misc/ISpatialPartition.h new file mode 100644 index 0000000..bc06d82 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ISpatialPartition.h @@ -0,0 +1,106 @@ +#pragma once +#include "../Definitions.h" +#include "../Types.h" + +struct Ray_t; +class IHandleEntity; + +#define PARTITION_ALL_CLIENT_EDICTS (PARTITION_CLIENT_NON_STATIC_EDICTS | PARTITION_CLIENT_STATIC_PROPS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_SOLID_EDICTS) + +#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) + +enum IterationRetval_t +{ + ITERATION_CONTINUE = 0, + ITERATION_STOP +}; + +typedef unsigned short SpatialPartitionHandle_t; +typedef int SpatialPartitionListMask_t; +typedef int SpatialTempHandle_t; + +class IPartitionEnumerator +{ +public: + virtual IterationRetval_t EnumElement(IHandleEntity* pHandleEntity) = 0; +}; + +class IPartitionQueryCallback +{ +public: + virtual void OnPreQuery_V1() = 0; + virtual void OnPreQuery(SpatialPartitionListMask_t listMask) = 0; + virtual void OnPostQuery(SpatialPartitionListMask_t listMask) = 0; +}; + +enum +{ + PARTITION_INVALID_HANDLE = (SpatialPartitionHandle_t)~0 +}; + +class ISpatialPartition +{ +public: + virtual ~ISpatialPartition() {} + virtual SpatialPartitionHandle_t CreateHandle(IHandleEntity* pHandleEntity) = 0; + virtual SpatialPartitionHandle_t CreateHandle(IHandleEntity* pHandleEntity, SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs) = 0; + virtual void DestroyHandle(SpatialPartitionHandle_t handle) = 0; + virtual void Insert(SpatialPartitionListMask_t listMask, SpatialPartitionHandle_t handle) = 0; + virtual void Remove(SpatialPartitionListMask_t listMask, SpatialPartitionHandle_t handle) = 0; + virtual void RemoveAndInsert(SpatialPartitionListMask_t removeMask, SpatialPartitionListMask_t insertMask, SpatialPartitionHandle_t handle) = 0; + virtual void Remove(SpatialPartitionHandle_t handle) = 0; + virtual void ElementMoved(SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs) = 0; + virtual SpatialTempHandle_t HideElement(SpatialPartitionHandle_t handle) = 0; + virtual void UnhideElement(SpatialPartitionHandle_t handle, SpatialTempHandle_t tempHandle) = 0; + virtual void InstallQueryCallback_V1(IPartitionQueryCallback* pCallback) = 0; + virtual void RemoveQueryCallback(IPartitionQueryCallback* pCallback) = 0; + + 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; + + 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; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ISurface.h b/Amalgam/src/SDK/Definitions/Misc/ISurface.h new file mode 100644 index 0000000..ec85ff7 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ISurface.h @@ -0,0 +1,247 @@ +#pragma once +#include "IAppSystem.h" +#include "IHTML.h" +#include "ImageFormat.h" +#include "IVguiMatInfo.h" +#include "../Types.h" + +#undef CreateFont +#undef PlaySound + +struct Vertex_t +{ + Vector2D m_Position = {}; + Vector2D m_TexCoord = {}; + + Vertex_t() {} + + Vertex_t(const Vector2D& pos, const Vector2D& coord = Vector2D(0.0f, 0.0f)) { + m_Position = pos; + m_TexCoord = coord; + } + + void Init(const Vector2D& pos, const Vector2D& coord = Vector2D(0.0f, 0.0f)) { + m_Position = pos; + m_TexCoord = coord; + } +}; + +enum FontDrawType_t +{ + FONT_DRAW_DEFAULT = 0, + FONT_DRAW_NONADDITIVE, + FONT_DRAW_ADDITIVE, + FONT_DRAW_TYPE_COUNT = 2, +}; + +struct CharRenderInfo +{ + int x = 0, y = 0; + Vertex_t* verts = nullptr; + int textureId = 0; + int abcA = 0; + int abcB = 0; + int abcC = 0; + int fontTall = 0; + HFont currentFont = {}; + FontDrawType_t drawType = {}; + wchar_t ch = {}; + bool valid = false; + bool shouldclip = false; +}; + +struct IntRect +{ + int x0 = 0; + int y0 = 0; + int x1 = 0; + int y1 = 0; +}; + +enum ETextureFormat +{ + eTextureFormat_RGBA, + eTextureFormat_BGRA, + eTextureFormat_BGRA_Opaque +}; + +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, +}; + +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, + FONTFLAG_BITMAP = 0x800 +}; + +class ISurface : public IAppSystem +{ +public: + virtual void Shutdown() = 0; + virtual void RunFrame() = 0; + virtual VPANEL GetEmbeddedPanel() = 0; + virtual void SetEmbeddedPanel(VPANEL pPanel) = 0; + virtual void PushMakeCurrent(VPANEL panel, bool useInsets) = 0; + virtual void PopMakeCurrent(VPANEL panel) = 0; + virtual void DrawSetColor(int r, int g, int b, int a) = 0; + virtual void DrawSetColor(Color_t 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_t 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; + virtual IHTML* CreateHTMLWindow(IHTMLEvents* events, VPANEL context) = 0; + virtual void PaintHTMLWindow(IHTML* htmlwin) = 0; + virtual void DeleteHTMLWindow(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 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; + 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; + virtual bool SupportsFeature(SurfaceFeature_e feature) = 0; + virtual void RestrictPaintToSinglePanel(VPANEL panel) = 0; + 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; + virtual void SetTopLevelFocus(VPANEL panel) = 0; + virtual HFont CreateFont() = 0; + 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; + virtual bool AddCustomFontFile(const char* fontName, const char* fontFileName) = 0; + 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; + virtual VPANEL GetNotifyPanel() = 0; + virtual void SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char* text) = 0; + virtual void PlaySound(const char* fileName) = 0; + 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; + virtual void GetWorkspaceBounds(int& x, int& y, int& wide, int& tall) = 0; + virtual void GetAbsoluteWindowBounds(int& x, int& y, int& wide, int& tall) = 0; + 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; + 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; + 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; + virtual bool DrawGetUnicodeCharRenderInfo(wchar_t ch, CharRenderInfo& info) = 0; + virtual void DrawRenderCharFromInfo(const CharRenderInfo& info) = 0; + virtual void DrawSetAlphaMultiplier(float alpha) = 0; + virtual float DrawGetAlphaMultiplier() = 0; + virtual void SetAllowHTMLJavaScript(bool state) = 0; + virtual void OnScreenSizeChanged(int nOldWidth, int nOldHeight) = 0; + virtual HCursor CreateCursorFromFile(char const* curOrAniFile, char const* pPathID = 0) = 0; + virtual IVguiMatInfo* DrawGetTextureMatInfoFactory(int id) = 0; + virtual void PaintTraverseEx(VPANEL panel, bool paintPopups = false) = 0; + virtual float GetZPos() const = 0; + 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; + virtual bool AddBitmapFontFile(const char* fontFileName) = 0; + virtual void SetBitmapFontName(const char* pName, const char* pFontFilename) = 0; + 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; + 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; + virtual bool ForceScreenPosOffset(bool bState, int x, int y) = 0; + virtual void OffsetAbsPos(int& x, int& y) = 0; + 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; + virtual void SetFullscreenViewport(int x, int y, int w, int h) = 0; + virtual void GetFullscreenViewport(int& x, int& y, int& w, int& h) = 0; + virtual void PushFullscreenViewport() = 0; + virtual void PopFullscreenViewport() = 0; + virtual void SetSoftwareCursor(bool bUseSoftwareCursor) = 0; + virtual void PaintSoftwareCursor() = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IVguiMatInfo.h b/Amalgam/src/SDK/Definitions/Misc/IVguiMatInfo.h new file mode 100644 index 0000000..ddfb7dd --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IVguiMatInfo.h @@ -0,0 +1,10 @@ +#pragma once +#include "IVguiMatInfoVar.h" + +class IVguiMatInfo +{ +public: + virtual ~IVguiMatInfo() {} + virtual IVguiMatInfoVar* FindVarFactory(const char* varName, bool* found) = 0; + virtual int GetNumAnimationFrames() = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/IVguiMatInfoVar.h b/Amalgam/src/SDK/Definitions/Misc/IVguiMatInfoVar.h new file mode 100644 index 0000000..4ecc86e --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/IVguiMatInfoVar.h @@ -0,0 +1,9 @@ +#pragma once + +class IVguiMatInfoVar +{ +public: + virtual ~IVguiMatInfoVar() {} + virtual int GetIntValue(void) const = 0; + virtual void SetIntValue(int val) = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/ImageFormat.h b/Amalgam/src/SDK/Definitions/Misc/ImageFormat.h new file mode 100644 index 0000000..ce7eb6e --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/ImageFormat.h @@ -0,0 +1,204 @@ +#pragma once + +enum NormalDecodeMode_t +{ + NORMAL_DECODE_NONE = 0 +}; + +//typedef enum _D3DFORMAT D3DFORMAT; + +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, + IMAGE_FORMAT_RGB323232F, + IMAGE_FORMAT_RGBA32323232F, + IMAGE_FORMAT_NV_DST16, + IMAGE_FORMAT_NV_DST24, + IMAGE_FORMAT_NV_INTZ, + IMAGE_FORMAT_NV_RAWZ, + IMAGE_FORMAT_ATI_DST16, + IMAGE_FORMAT_ATI_DST24, + IMAGE_FORMAT_NV_NULL, + IMAGE_FORMAT_ATI2N, + IMAGE_FORMAT_ATI1N, + IMAGE_FORMAT_DXT1_RUNTIME, + IMAGE_FORMAT_DXT5_RUNTIME, + NUM_IMAGE_FORMATS +}; + +struct BGRA8888_t +{ + unsigned char b = 0; + unsigned char g = 0; + unsigned char r = 0; + unsigned char a = 0; + + inline BGRA8888_t& operator=(const BGRA8888_t& in) + { + *(unsigned int*)this = *(unsigned int*)∈ + return *this; + } +}; + +struct BGRX8888_t +{ + unsigned char b = 0; + unsigned char g = 0; + unsigned char r = 0; + unsigned char x = 0; + + inline BGRX8888_t& operator=(const BGRX8888_t& in) + { + *(unsigned int*)this = *(unsigned int*)∈ + return *this; + } +}; + +struct RGBA8888_t +{ + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + unsigned char a = 0; +}; + +struct RGB888_t +{ + unsigned char r = 0; + unsigned char g = 0; + unsigned char b = 0; + + 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 = 0; + unsigned char g = 0; + unsigned char r = 0; + + inline BGR888_t& operator=(const BGRA8888_t& in) + { + r = in.r; + g = in.g; + b = in.b; + return *this; + } +}; + +struct BGR565_t +{ + unsigned short b : 5; + unsigned short g : 6; + 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; + } +}; + +struct BGRA5551_t +{ + unsigned short b : 5; + unsigned short g : 5; + 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; + unsigned short g : 4; + 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; + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/InputEnums.h b/Amalgam/src/SDK/Definitions/Misc/InputEnums.h new file mode 100644 index 0000000..cb81e36 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/InputEnums.h @@ -0,0 +1,144 @@ +#pragma once + +#define MAX_STEAM_CONTROLLERS 8 + +enum +{ + MAX_JOYSTICKS = 1, + MOUSE_BUTTON_COUNT = 5, + MAX_NOVINT_DEVICES = 2 +}; + +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 +}; + +enum +{ + MS_WM_XBUTTONDOWN = 0x020B, + MS_WM_XBUTTONUP = 0x020C, + MS_WM_XBUTTONDBLCLK = 0x020D, + MS_MK_BUTTON4 = 0x0020, + MS_MK_BUTTON5 = 0x0040 +}; + +enum InputEventType_t +{ + IE_ButtonPressed = 0, + IE_ButtonReleased, + IE_ButtonDoubleClicked, + IE_AnalogValueChanged, + IE_FirstSystemEvent = 100, + IE_Quit = IE_FirstSystemEvent, + IE_ControllerInserted, + IE_ControllerUnplugged, + IE_FirstVguiEvent = 1000, + IE_FirstAppEvent = 2000 +}; + +struct InputEvent_t +{ + int m_nType = 0; + int m_nTick = 0; + int m_nData = 0; + int m_nData2 = 0; + int m_nData3 = 0; +}; + +typedef enum +{ + SK_NULL, + SK_BUTTON_A, + SK_BUTTON_B, + SK_BUTTON_X, + SK_BUTTON_Y, + SK_BUTTON_UP, + SK_BUTTON_RIGHT, + SK_BUTTON_DOWN, + SK_BUTTON_LEFT, + SK_BUTTON_LEFT_BUMPER, + SK_BUTTON_RIGHT_BUMPER, + SK_BUTTON_LEFT_TRIGGER, + SK_BUTTON_RIGHT_TRIGGER, + SK_BUTTON_LEFT_GRIP, + SK_BUTTON_RIGHT_GRIP, + SK_BUTTON_LPAD_TOUCH, + SK_BUTTON_RPAD_TOUCH, + SK_BUTTON_LPAD_CLICK, + SK_BUTTON_RPAD_CLICK, + SK_BUTTON_LPAD_UP, + SK_BUTTON_LPAD_RIGHT, + SK_BUTTON_LPAD_DOWN, + SK_BUTTON_LPAD_LEFT, + SK_BUTTON_RPAD_UP, + SK_BUTTON_RPAD_RIGHT, + SK_BUTTON_RPAD_DOWN, + SK_BUTTON_RPAD_LEFT, + SK_BUTTON_SELECT, + SK_BUTTON_START, + SK_BUTTON_STEAM, + SK_BUTTON_INACTIVE_START, + SK_VBUTTON_F1, + SK_VBUTTON_F2, + SK_VBUTTON_F3, + SK_VBUTTON_F4, + SK_VBUTTON_F5, + SK_VBUTTON_F6, + SK_VBUTTON_F7, + SK_VBUTTON_F8, + SK_VBUTTON_F9, + SK_VBUTTON_F10, + SK_VBUTTON_F11, + SK_VBUTTON_F12, + SK_MAX_KEYS +} sKey_t; + +enum ESteamPadAxis +{ + LEFTPAD_AXIS_X, + LEFTPAD_AXIS_Y, + RIGHTPAD_AXIS_X, + RIGHTPAD_AXIS_Y, + LEFT_TRIGGER_AXIS, + RIGHT_TRIGGER_AXIS, + GYRO_AXIS_PITCH, + GYRO_AXIS_ROLL, + GYRO_AXIS_YAW, + MAX_STEAMPADAXIS = GYRO_AXIS_YAW +}; + +enum +{ + LASTINPUT_KBMOUSE = 0, + LASTINPUT_CONTROLLER = 1, + LASTINPUT_STEAMCONTROLLER = 2 +}; + +enum GameActionSet_t +{ + GAME_ACTION_SET_NONE = -1, + GAME_ACTION_SET_MENUCONTROLS = 0, + GAME_ACTION_SET_FPSCONTROLS, + GAME_ACTION_SET_IN_GAME_HUD, + GAME_ACTION_SET_SPECTATOR +}; + +enum GameActionSetFlags_t +{ + GAME_ACTION_SET_FLAGS_NONE = 0, + GAME_ACTION_SET_FLAGS_TAUNTING = (1 << 0) +}; + +enum JoystickType_t +{ + INPUT_TYPE_GENERIC_JOYSTICK = 0, + INPUT_TYPE_X360, + INPUT_TYPE_STEAMCONTROLLER +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/KeyCode.h b/Amalgam/src/SDK/Definitions/Misc/KeyCode.h new file mode 100644 index 0000000..64cd4bb --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/KeyCode.h @@ -0,0 +1,4 @@ +#pragma once +#include "ButtonCode.h" + +typedef ButtonCode_t KeyCode; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/LightDesc.h b/Amalgam/src/SDK/Definitions/Misc/LightDesc.h new file mode 100644 index 0000000..9b09df9 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/LightDesc.h @@ -0,0 +1,51 @@ +#pragma once +#include "../Types.h" + +#pragma warning (disable : 26812) + +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 +{ +public: + 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; + float m_ThetaDot; + float m_PhiDot; + unsigned int m_Flags; + float OneOver_ThetaDot_Minus_PhiDot; + float m_RangeSquared; + + 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; + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/LocalFlexController.h b/Amalgam/src/SDK/Definitions/Misc/LocalFlexController.h new file mode 100644 index 0000000..5fa139d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/LocalFlexController.h @@ -0,0 +1,13 @@ +#pragma once + +#pragma warning (disable : 26812) + +enum LocalFlexController_t +{ + DUMMY_FLEX_CONTROLLER = 0x7fffffff +}; + +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; } \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/Modes.h b/Amalgam/src/SDK/Definitions/Misc/Modes.h new file mode 100644 index 0000000..607b87b --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/Modes.h @@ -0,0 +1,9 @@ +#pragma once + +typedef struct vmode_s +{ + int width; + int height; + int bpp; + int refreshRate; +} vmode_t; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/MouseCode.h b/Amalgam/src/SDK/Definitions/Misc/MouseCode.h new file mode 100644 index 0000000..d7f2559 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/MouseCode.h @@ -0,0 +1,4 @@ +#pragma once +#include "ButtonCode.h" + +typedef ButtonCode_t MouseCode; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/NetAdr.h b/Amalgam/src/SDK/Definitions/Misc/NetAdr.h new file mode 100644 index 0000000..4446238 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/NetAdr.h @@ -0,0 +1,17 @@ +#pragma once + +typedef enum +{ + NA_NULL = 0, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, +} netadrtype_t; + +typedef struct netadr_s +{ +public: + netadrtype_t type; + unsigned char ip[4]; + unsigned short port; +} netadr_t; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/String.h b/Amalgam/src/SDK/Definitions/Misc/String.h new file mode 100644 index 0000000..ff90561 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/String.h @@ -0,0 +1,15 @@ +#pragma once + +struct string_t +{ +public: + bool operator!() const { return (pszValue == 0); } + 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; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/Studio.h b/Amalgam/src/SDK/Definitions/Misc/Studio.h new file mode 100644 index 0000000..a212792 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/Studio.h @@ -0,0 +1,1306 @@ +#pragma once +#include "BaseTypes.h" +#include "Datamap.h" +#include "LocalFlexController.h" +#include "../Main/UtlVector.h" +#include "../Types.h" + +#define STUDIO_ENABLE_PERF_COUNTERS +#define STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW 0 +#define STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE 1 + +class IMaterial; +class IMesh; +class IMorph; +struct virtualmodel_t; +struct vertexFileHeader_t; +struct thinModelVertices_t; +struct StripHeader_t; + +#define STUDIO_VERSION 48 + +#define MAXSTUDIOTRIANGLES 65536 +#define MAXSTUDIOVERTS 65536 +#define MAXSTUDIOFLEXVERTS 10000 +#define MAXSTUDIOSKINS 32 +#define MAXSTUDIOBONES 128 +#define MAXSTUDIOFLEXDESC 1024 +#define MAXSTUDIOFLEXCTRL 96 +#define MAXSTUDIOPOSEPARAM 24 +#define MAXSTUDIOBONECTRLS 4 +#define MAXSTUDIOANIMBLOCKS 256 +#define MAXSTUDIOBONEBITS 7 +#define MAX_NUM_BONES_PER_VERT 3 + +#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 +{ + int control; + int axis; + Vector pos[6]; + Quaternion quat[6]; +}; + +struct mstudioquatinterpinfo_t +{ + float inv_tolerance; + Quaternion trigger; + Vector pos; + Quaternion quat; +}; + +struct mstudioquatinterpbone_t +{ + int control; + int numtriggers; + int triggerindex; + inline mstudioquatinterpinfo_t* pTrigger(int i) const { return (mstudioquatinterpinfo_t*)(((byte*)this) + triggerindex) + i; }; +}; + +#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 + +struct mstudiojigglebone_t +{ + int flags; + float length; + float tipMass; + float yawStiffness; + float yawDamping; + float pitchStiffness; + float pitchDamping; + float alongStiffness; + float alongDamping; + float angleLimit; + float minYaw; + float maxYaw; + float yawFriction; + float yawBounce; + float minPitch; + float maxPitch; + float pitchFriction; + float pitchBounce; + float baseMass; + float baseStiffness; + float baseDamping; + float baseMinLeft; + float baseMaxLeft; + float baseLeftFriction; + float baseMinUp; + float baseMaxUp; + float baseUpFriction; + float baseMinForward; + float baseMaxForward; + float baseForwardFriction; + float boingImpactSpeed; + float boingImpactAngle; + float boingDampingRate; + float boingFrequency; + float boingAmplitude; +}; + +struct mstudioaimatbone_t +{ + int parent; + int aim; + Vector aimvector; + Vector upvector; + Vector basepos; +}; + +struct mstudiobone_t +{ + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + int parent; + int bonecontroller[6]; + Vector pos; + Quaternion quat; + RadianEuler rot; + Vector posscale; + Vector rotscale; + matrix3x4 poseToBone; + Quaternion qAlignment; + int flags; + int proctype; + int procindex; + mutable int physicsbone; + inline void* pProcedure() const { if (procindex == 0) return NULL; else return (void*)(((byte*)this) + procindex); }; + int surfacepropidx; + inline char* const pszSurfaceProp(void) const { return ((char*)this) + surfacepropidx; } + int contents; + int unused[8]; +}; + +struct mstudiolinearbone_t +{ + int numbones; + int flagsindex; + inline int flags(int i) const { return *((int*)(((byte*)this) + flagsindex) + i); }; + inline int* pflags(int i) { return ((int*)(((byte*)this) + flagsindex) + i); }; + int parentindex; + inline int parent(int i) const { return *((int*)(((byte*)this) + parentindex) + i); }; + int posindex; + inline Vector pos(int i) const { return *((Vector*)(((byte*)this) + posindex) + i); }; + int quatindex; + inline Quaternion quat(int i) const { return *((Quaternion*)(((byte*)this) + quatindex) + i); }; + int rotindex; + inline RadianEuler rot(int i) const { return *((RadianEuler*)(((byte*)this) + rotindex) + i); }; + int posetoboneindex; + inline matrix3x4* poseToBone(int i) const { return ((matrix3x4*)(((byte*)this) + posetoboneindex) + i); }; + int posscaleindex; + inline Vector posscale(int i) const { return *((Vector*)(((byte*)this) + posscaleindex) + i); }; + int rotscaleindex; + inline Vector rotscale(int i) const { return *((Vector*)(((byte*)this) + rotscaleindex) + i); }; + int qalignmentindex; + inline Quaternion qalignment(int i) const { return *((Quaternion*)(((byte*)this) + qalignmentindex) + i); }; + int unused[6]; +}; + +enum StudioBoneFlexComponent_t +{ + STUDIO_BONE_FLEX_INVALID = -1, + STUDIO_BONE_FLEX_TX = 0, + STUDIO_BONE_FLEX_TY = 1, + STUDIO_BONE_FLEX_TZ = 2 +}; + +struct mstudioboneflexdrivercontrol_t +{ + int m_nBoneComponent; + int m_nFlexControllerIndex; + float m_flMin; + float m_flMax; +}; + +struct mstudioboneflexdriver_t +{ + int m_nBoneIndex; + int m_nControlCount; + int m_nControlIndex; + + inline mstudioboneflexdrivercontrol_t* pBoneFlexDriverControl(int i) const + { + return (mstudioboneflexdrivercontrol_t*)(((byte*)this) + m_nControlIndex) + i; + } + + int unused[3]; +}; + +#define BONE_CALCULATE_MASK 0x1F +#define BONE_PHYSICALLY_SIMULATED 0x01 +#define BONE_PHYSICS_PROCEDURAL 0x02 +#define BONE_ALWAYS_PROCEDURAL 0x04 +#define BONE_SCREEN_ALIGN_SPHERE 0x08 +#define BONE_SCREEN_ALIGN_CYLINDER 0x10 +#define BONE_USED_MASK 0x0007FF00 +#define BONE_USED_BY_ANYTHING 0x0007FF00 +#define BONE_USED_BY_HITBOX 0x00000100 +#define BONE_USED_BY_ATTACHMENT 0x00000200 +#define BONE_USED_BY_VERTEX_MASK 0x0003FC00 +#define BONE_USED_BY_VERTEX_LOD0 0x00000400 +#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 +#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 +#define BONE_HAS_SAVEFRAME_POS 0x00200000 +#define BONE_HAS_SAVEFRAME_ROT 0x00400000 + +struct mstudiobonecontroller_t +{ + int bone; + int type; + float start; + float end; + int rest; + int inputfield; + int unused[8]; +}; + +struct mstudiobbox_t +{ + int bone; + int group; + Vector bbmin; + Vector bbmax; + int szhitboxnameindex; + Vec3 angle; + float m_radius; + uint8_t _padding[0x10]; + + const char* pszHitboxName() + { + if (szhitboxnameindex == 0) + return ""; + + return ((const char*)this) + szhitboxnameindex; + } +}; + +struct mstudiomodelgroup_t +{ + int szlabelindex; + inline char* const pszLabel(void) const { return ((char*)this) + szlabelindex; } + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } +}; + +struct mstudiomodelgrouplookup_t +{ + int modelgroup; + int indexwithingroup; +}; + +struct mstudioevent_t +{ + float cycle; + int event; + int type; + inline const char* pszOptions(void) const { return options; } + char options[64]; + int szeventindex; + inline char* const pszEventName(void) const { return ((char*)this) + szeventindex; } +}; + +#define ATTACHMENT_FLAG_WORLD_ALIGN 0x10000 + +struct mstudioattachment_t +{ + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + unsigned int flags; + int localbone; + matrix3x4 local; + 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 +{ + Vector pos; + Quaternion q; +}; + +union mstudioanimvalue_t; + +struct mstudiocompressedikerror_t +{ + 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; }; +}; + +struct mstudioikrule_t +{ + int index; + int type; + int chain; + int bone; + int slot; + 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; + float peak; + float tail; + float end; + float unused3; + float contact; + float drop; + float top; + int unused6; + int unused7; + int unused8; + int szattachmentindex; + inline char* const pszAttachment(void) const { return ((char*)this) + szattachmentindex; } + int unused[7]; +}; + +struct mstudioiklock_t +{ + int chain; + float flPosWeight; + float flLocalQWeight; + int flags; + int unused[4]; +}; + + +struct mstudiolocalhierarchy_t +{ + int iBone; + int iNewParent; + float start; + float peak; + float tail; + float end; + int iStart; + int localanimindex; + inline mstudiocompressedikerror_t* pLocalAnim() const { return (mstudiocompressedikerror_t*)(((byte*)this) + localanimindex); }; + int unused[4]; +}; + +union mstudioanimvalue_t +{ + struct + { + byte valid; + byte total; + } num; + short value; +}; + +struct mstudioanim_valueptr_t +{ + 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 +#define STUDIO_ANIM_RAWROT 0x02 +#define STUDIO_ANIM_ANIMPOS 0x04 +#define STUDIO_ANIM_ANIMROT 0x08 +#define STUDIO_ANIM_DELTA 0x10 +#define STUDIO_ANIM_RAWROT2 0x20 + +struct mstudioanim_t +{ + byte bone; + byte flags; + 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); }; + short nextoffset; + inline mstudioanim_t* pNext(void) const { if (nextoffset != 0) return (mstudioanim_t*)(((byte*)this) + nextoffset); else return NULL; }; +}; + +struct mstudiomovement_t +{ + int endframe; + int motionflags; + float v0; + float v1; + float angle; + Vector vector; + Vector position; +}; + +struct studiohdr_t; + +struct mstudioanimblock_t +{ + int datastart; + int dataend; +}; + +struct mstudioanimsections_t +{ + int animblock; + int animindex; +}; + +struct mstudioanimdesc_t +{ + int baseptr; + inline studiohdr_t* pStudiohdr(void) const { return (studiohdr_t*)(((byte*)this) + baseptr); } + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + float fps; + int flags; + int numframes; + int nummovements; + int movementindex; + inline mstudiomovement_t* const pMovement(int i) const { return (mstudiomovement_t*)(((byte*)this) + movementindex) + i; }; + int unused1[6]; + int animblock; + int animindex; + int numikrules; + int ikruleindex; + int animblockikruleindex; + int numlocalhierarchy; + int localhierarchyindex; + int sectionindex; + int sectionframes; + inline mstudioanimsections_t* const pSection(int i) const { return (mstudioanimsections_t*)(((byte*)this) + sectionindex) + i; } + short zeroframespan; + short zeroframecount; + int zeroframeindex; + byte* pZeroFrameData() const { if (zeroframeindex) return (((byte*)this) + zeroframeindex); else return NULL; }; + mutable float zeroframestalltime; +}; + +struct mstudioikrule_t; + +struct mstudioautolayer_t +{ + short iSequence; + short iPose; + int flags; + float start; + float peak; + float tail; + float end; +}; + +struct mstudioactivitymodifier_t +{ + int sznameindex; + inline char* pszName() { return (sznameindex) ? (char*)(((byte*)this) + sznameindex) : NULL; } +}; + +struct mstudioseqdesc_t +{ + int baseptr; + inline studiohdr_t* pStudiohdr(void) const { return (studiohdr_t*)(((byte*)this) + baseptr); } + int szlabelindex; + inline char* const pszLabel(void) const { return ((char*)this) + szlabelindex; } + int szactivitynameindex; + inline char* const pszActivityName(void) const { return ((char*)this) + szactivitynameindex; } + int flags; + int activity; + int actweight; + int numevents; + int eventindex; + inline mstudioevent_t* pEvent(int i) const { return (mstudioevent_t*)(((byte*)this) + eventindex) + i; }; + Vector bbmin; + Vector bbmax; + int numblends; + 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; + int groupsize[2]; + int paramindex[2]; + float paramstart[2]; + float paramend[2]; + int paramparent; + float fadeintime; + float fadeouttime; + int localentrynode; + int localexitnode; + int nodeflags; + float entryphase; + float exitphase; + float lastframe; + int nextseq; + int pose; + int numikrules; + int numautolayers; + int autolayerindex; + inline mstudioautolayer_t* pAutolayer(int i) const { 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)); }; + 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 { return (mstudioiklock_t*)(((byte*)this) + iklockindex) + i; }; + int keyvalueindex; + int keyvaluesize; + inline const char* KeyValueText(void) const { return keyvaluesize != 0 ? ((char*)this) + keyvalueindex : NULL; } + int cycleposeindex; + int activitymodifierindex; + int numactivitymodifiers; + inline mstudioactivitymodifier_t* pActivityModifier(int i) const { return activitymodifierindex != 0 ? (mstudioactivitymodifier_t*)(((byte*)this) + activitymodifierindex) + i : NULL; }; + int unused[5]; +}; + +struct mstudioposeparamdesc_t +{ + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + int flags; + float start; + float end; + float loop; +}; + +struct mstudioflexdesc_t +{ + int szFACSindex; + inline char* const pszFACS(void) const { return ((char*)this) + szFACSindex; } +}; + +struct mstudioflexcontroller_t +{ + int sztypeindex; + inline char* const pszType(void) const { return ((char*)this) + sztypeindex; } + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + mutable int localToGlobal; + float min; + float max; +}; + +enum FlexControllerRemapType_t +{ + FLEXCONTROLLER_REMAP_PASSTHRU = 0, + FLEXCONTROLLER_REMAP_2WAY, + FLEXCONTROLLER_REMAP_NWAY, + FLEXCONTROLLER_REMAP_EYELID +}; + +class CStudioHdr; +struct mstudioflexcontrollerui_t +{ + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + + int szindex0; + int szindex1; + int szindex2; + + inline const mstudioflexcontroller_t* pController(void) const + { + return !stereo ? (mstudioflexcontroller_t*)((char*)this + szindex0) : NULL; + } + inline char* const pszControllerName(void) const { return !stereo ? pController()->pszName() : NULL; } + + inline const mstudioflexcontroller_t* pLeftController(void) const + { + return stereo ? (mstudioflexcontroller_t*)((char*)this + szindex0) : NULL; + } + inline char* const pszLeftName(void) const { return stereo ? pLeftController()->pszName() : NULL; } + + inline const mstudioflexcontroller_t* pRightController(void) const + { + return stereo ? (mstudioflexcontroller_t*)((char*)this + szindex1) : NULL; + } + + inline char* const pszRightName(void) const { return stereo ? pRightController()->pszName() : NULL; } + + inline const mstudioflexcontroller_t* pNWayValueController(void) const + { + return remaptype == FLEXCONTROLLER_REMAP_NWAY ? (mstudioflexcontroller_t*)((char*)this + szindex2) : NULL; + } + inline char* const pszNWayValueName(void) const { return remaptype == FLEXCONTROLLER_REMAP_NWAY ? pNWayValueController()->pszName() : NULL; } + inline int Count() const { return (stereo ? 2 : 1) + (remaptype == FLEXCONTROLLER_REMAP_NWAY ? 1 : 0); } + unsigned char remaptype; + bool stereo; + byte unused[2]; +}; + +struct mstudiovertanim_t +{ + unsigned short index; + byte speed; + byte side; + + /*union + { + short delta[3]; + float16 flDelta[3]; + }; + + union + { + short ndelta[3]; + float16 flNDelta[3]; + };*/ +}; + +struct mstudiovertanim_wrinkle_t : public mstudiovertanim_t +{ + short wrinkledelta; +}; + +enum StudioVertAnimType_t +{ + STUDIO_VERT_ANIM_NORMAL = 0, + STUDIO_VERT_ANIM_WRINKLE +}; + +struct mstudioflex_t +{ + int flexdesc; + float target0; + float target1; + float target2; + float target3; + int numverts; + int vertindex; + inline mstudiovertanim_t* pVertanim(int i) const { return (mstudiovertanim_t*)(((byte*)this) + vertindex) + i; }; + inline mstudiovertanim_wrinkle_t* pVertanimWrinkle(int i) const { 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; + unsigned char vertanimtype; + unsigned char unusedchar[3]; + int unused[6]; +}; + +struct mstudioflexop_t +{ + int op; + union + { + int index; + float value; + } d; +}; + +struct mstudioflexrule_t +{ + int flex; + int numops; + int opindex; + inline mstudioflexop_t* iFlexOp(int i) const { return (mstudioflexop_t*)(((byte*)this) + opindex) + i; }; +}; + +struct mstudioboneweight_t +{ + float weight[MAX_NUM_BONES_PER_VERT]; + char bone[MAX_NUM_BONES_PER_VERT]; + byte numbones; +}; + +struct mstudiovertex_t +{ + mstudioboneweight_t m_BoneWeights; + Vector m_vecPosition; + Vector m_vecNormal; + Vector2D m_vecTexCoord; +}; + +struct mstudiotexture_t +{ + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + int flags; + int used; + int unused1; + IMaterial* material; + void* clientmaterial; + int unused[10]; +}; + +struct mstudioeyeball_t +{ + int sznameindex; + inline char* const 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]; + int lowerflexdesc[3]; + float uppertarget[3]; + float lowertarget[3]; + int upperlidflexdesc; + int lowerlidflexdesc; + int unused[4]; + bool m_bNonFACS; + char unused3[3]; + int unused4[7]; +}; + +struct mstudioiklink_t +{ + int bone; + Vector kneeDir; + Vector unused0; +}; + +struct mstudioikchain_t +{ + int sznameindex; + inline char* const 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; }; +}; + +struct mstudioiface_t +{ + unsigned short a, b, c; +}; + +struct mstudiomodel_t; + +struct mstudio_modelvertexdata_t +{ + void* pVertexData; + void* pTangentData; +}; + +struct mstudio_meshvertexdata_t +{ + mstudio_modelvertexdata_t* modelvertexdata; + int numLODVertexes[MAX_NUM_LODS]; +}; + +struct mstudiomesh_t +{ + int material; + int modelindex; + int numvertices; + int vertexoffset; + int numflexes; + int flexindex; + inline mstudioflex_t* pFlex(int i) const { return (mstudioflex_t*)(((byte*)this) + flexindex) + i; }; + int materialtype; + int materialparam; + int meshid; + Vector center; + mstudio_meshvertexdata_t vertexdata; + int unused[8]; +}; + +struct mstudiomodel_t +{ + 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; }; + int numvertices; + int vertexindex; + int tangentsindex; + 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]; +}; + +enum studiomeshgroupflags_t +{ + MESHGROUP_IS_FLEXED = 0x1, + MESHGROUP_IS_HWSKINNED = 0x2, + MESHGROUP_IS_DELTA_FLEXED = 0x4 +}; + +struct studiomeshgroup_t +{ + IMesh* m_pMesh; + int m_NumStrips; + int m_Flags; + StripHeader_t* m_pStripData; + unsigned short* m_pGroupIndexToMeshIndex; + int m_NumVertices; + int* m_pUniqueTris; + 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]]; } +}; + +struct studiomeshdata_t +{ + int m_NumGroup; + studiomeshgroup_t* m_pMeshGroup; +}; + +struct studioloddata_t +{ + studiomeshdata_t* m_pMeshData; + float m_SwitchPoint; + int numMaterials; + IMaterial** ppMaterials; + int* pMaterialFlags; + int* m_pHWMorphDecalBoneRemap; + int m_nDecalBoneCount; +}; + +struct studiohwdata_t +{ + int m_RootLOD; + 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; } +}; + +struct mstudiobodyparts_t +{ + int sznameindex; + inline char* const pszName(void) const { return ((char*)this) + sznameindex; } + int nummodels; + int base; + int modelindex; + inline mstudiomodel_t* pModel(int i) const { return (mstudiomodel_t*)(((byte*)this) + modelindex) + i; }; +}; + + +struct mstudiomouth_t +{ + int bone; + Vector forward; + int flexdesc; +}; + +struct mstudiohitboxset_t +{ + int sznameindex; + inline char* const 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; }; +}; + +struct mstudiosrcbonetransform_t +{ + int sznameindex; + inline const char* pszName(void) const { return ((char*)this) + sznameindex; } + matrix3x4 pretransform; + matrix3x4 posttransform; +}; + +class virtualgroup_t +{ +public: + virtualgroup_t(void) { cache = NULL; }; + void* cache; + CUtlVector< int > boneMap; + CUtlVector< int > masterBone; + CUtlVector< int > masterSeq; + CUtlVector< int > masterAnim; + CUtlVector< int > masterAttachment; + CUtlVector< int > masterPose; + CUtlVector< int > masterNode; +}; + +struct virtualsequence_t +{ + int flags; + int activity; + int group; + int index; +}; + +struct virtualgeneric_t +{ + int group; + int index; +}; + +struct virtualmodel_t; +struct thinModelVertices_t; + +#define MODEL_VERTEX_FILE_ID (('V'<<24)+('S'<<16)+('D'<<8)+'I') +#define MODEL_VERTEX_FILE_VERSION 4 +#define MODEL_VERTEX_FILE_THIN_ID (('V'<<24)+('C'<<16)+('D'<<8)+'I') + +struct vertexFileHeader_t +{ + int id; + int version; + int checksum; + int numLODs; + int numLODVertexes[MAX_NUM_LODS]; + int numFixups; + int fixupTableStart; + int vertexDataStart; + int tangentDataStart; + +public: + const mstudiovertex_t* GetVertexData() const + { + if ((id == MODEL_VERTEX_FILE_ID) && (vertexDataStart != 0)) + return (mstudiovertex_t*)(vertexDataStart + (byte*)this); + else + return NULL; + } + + const Vector4D* GetTangentData() const + { + if ((id == MODEL_VERTEX_FILE_ID) && (tangentDataStart != 0)) + return (Vector4D*)(tangentDataStart + (byte*)this); + else + return NULL; + } + + const thinModelVertices_t* GetThinVertexData() const + { + if ((id == MODEL_VERTEX_FILE_THIN_ID) && (vertexDataStart != 0)) + return (thinModelVertices_t*)(vertexDataStart + (byte*)this); + else + return NULL; + } +}; + +struct vertexFileFixup_t +{ + int lod; + int sourceVertexID; + int numVertexes; +}; + +#define STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX 0x00000001 +#define STUDIOHDR_FLAGS_USES_ENV_CUBEMAP 0x00000002 +#define STUDIOHDR_FLAGS_FORCE_OPAQUE 0x00000004 +#define STUDIOHDR_FLAGS_TRANSLUCENT_TWOPASS 0x00000008 +#define STUDIOHDR_FLAGS_STATIC_PROP 0x00000010 +#define STUDIOHDR_FLAGS_USES_FB_TEXTURE 0x00000020 +#define STUDIOHDR_FLAGS_HASSHADOWLOD 0x00000040 +#define STUDIOHDR_FLAGS_USES_BUMPMAPPING 0x00000080 +#define STUDIOHDR_FLAGS_USE_SHADOWLOD_MATERIALS 0x00000100 +#define STUDIOHDR_FLAGS_OBSOLETE 0x00000200 +#define STUDIOHDR_FLAGS_UNUSED 0x00000400 +#define STUDIOHDR_FLAGS_NO_FORCED_FADE 0x00000800 +#define STUDIOHDR_FLAGS_FORCE_PHONEME_CROSSFADE 0x00001000 +#define STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT 0x00002000 +#define STUDIOHDR_FLAGS_FLEXES_CONVERTED 0x00004000 +#define STUDIOHDR_FLAGS_BUILT_IN_PREVIEW_MODE 0x00008000 +#define STUDIOHDR_FLAGS_AMBIENT_BOOST 0x00010000 +#define STUDIOHDR_FLAGS_DO_NOT_CAST_SHADOWS 0x00020000 +#define STUDIOHDR_FLAGS_CAST_TEXTURE_SHADOWS 0x00040000 +#define STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE 0x00200000 + +struct studiohdr2_t +{ + 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; } + 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 { return (mstudioboneflexdriver_t*)(((byte*)this) + m_nBoneFlexDriverIndex) + i; } + int reserved[56]; +}; + +struct studiohdr_t +{ + int id; + int version; + int checksum; + inline const char* pszName(void) const { if (studiohdr2index && pStudioHdr2()->pszName()) return pStudioHdr2()->pszName(); else return name; } + char name[64]; + int length; + Vector eyeposition; + Vector illumposition; + Vector hull_min; + Vector hull_max; + Vector view_bbmin; + Vector view_bbmax; + int flags; + int numbones; + int boneindex; + inline mstudiobone_t* pBone(int i) const { return (mstudiobone_t*)(((byte*)this) + boneindex) + i; }; + int numbonecontrollers; + int bonecontrollerindex; + inline mstudiobonecontroller_t* pBonecontroller(int i) const { return (mstudiobonecontroller_t*)(((byte*)this) + bonecontrollerindex) + i; }; + int numhitboxsets; + int hitboxsetindex; + + mstudiohitboxset_t* pHitboxSet(int i) const + { + return (mstudiohitboxset_t*)(((byte*)this) + hitboxsetindex) + i; + }; + + inline mstudiobbox_t* pHitbox(int i, int set) const + { + mstudiohitboxset_t const* s = pHitboxSet(set); + if (!s) + return NULL; + + return s->pHitbox(i); + }; + + inline int iHitboxCount(int set) const + { + mstudiohitboxset_t const* s = pHitboxSet(set); + if (!s) + return 0; + + return s->numhitboxes; + }; + + int numlocalanim; + int localanimindex; + inline mstudioanimdesc_t* pLocalAnimdesc(int i) const { if (i < 0 || i >= numlocalanim) i = 0; return (mstudioanimdesc_t*)(((byte*)this) + localanimindex) + i; }; + int numlocalseq; + int localseqindex; + inline mstudioseqdesc_t* pLocalSeqdesc(int i) const { if (i < 0 || i >= numlocalseq) i = 0; return (mstudioseqdesc_t*)(((byte*)this) + localseqindex) + i; }; + int activitylistversion; + int eventsindexed; + int numtextures; + int textureindex; + inline mstudiotexture_t* pTexture(int i) const { return (mstudiotexture_t*)(((byte*)this) + textureindex) + i; }; + int numcdtextures; + int cdtextureindex; + inline char* pCdtexture(int i) const { return (((char*)this) + *((int*)(((byte*)this) + cdtextureindex) + i)); }; + 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; }; + int numlocalattachments; + int localattachmentindex; + inline mstudioattachment_t* pLocalAttachment(int i) const { return (mstudioattachment_t*)(((byte*)this) + localattachmentindex) + i; }; + int numlocalnodes; + int localnodeindex; + int localnodenameindex; + inline char* pszLocalNodeName(int iNode) const { return (((char*)this) + *((int*)(((byte*)this) + localnodenameindex) + iNode)); } + inline byte* pLocalTransition(int i) const { return (byte*)(((byte*)this) + localnodeindex) + i; }; + int numflexdesc; + int flexdescindex; + inline mstudioflexdesc_t* pFlexdesc(int i) const { return (mstudioflexdesc_t*)(((byte*)this) + flexdescindex) + i; }; + int numflexcontrollers; + int flexcontrollerindex; + inline mstudioflexcontroller_t* pFlexcontroller(LocalFlexController_t i) const { return (mstudioflexcontroller_t*)(((byte*)this) + flexcontrollerindex) + i; }; + int numflexrules; + int flexruleindex; + inline mstudioflexrule_t* pFlexRule(int i) const { return (mstudioflexrule_t*)(((byte*)this) + flexruleindex) + i; }; + int numikchains; + int ikchainindex; + inline mstudioikchain_t* pIKChain(int i) const { return (mstudioikchain_t*)(((byte*)this) + ikchainindex) + i; }; + int nummouths; + int mouthindex; + inline mstudiomouth_t* pMouth(int i) const { return (mstudiomouth_t*)(((byte*)this) + mouthindex) + i; }; + int numlocalposeparameters; + int localposeparamindex; + inline mstudioposeparamdesc_t* pLocalPoseParameter(int i) const { return (mstudioposeparamdesc_t*)(((byte*)this) + localposeparamindex) + i; }; + int surfacepropindex; + inline char* const pszSurfaceProp(void) const { return ((char*)this) + surfacepropindex; } + 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 { return (mstudioiklock_t*)(((byte*)this) + localikautoplaylockindex) + i; }; + float mass; + int contents; + int numincludemodels; + int includemodelindex; + inline mstudiomodelgroup_t* pModelGroup(int i) const { return (mstudiomodelgroup_t*)(((byte*)this) + includemodelindex) + i; }; + void* virtualModel; + int szanimblocknameindex; + inline char* const pszAnimBlockName(void) const { return ((char*)this) + szanimblocknameindex; } + int numanimblocks; + int animblockindex; + inline mstudioanimblock_t* pAnimBlock(int i) const { return (mstudioanimblock_t*)(((byte*)this) + animblockindex) + i; }; + void* animblockModel; + int bonetablebynameindex; + inline const byte* GetBoneTableSortedByName() const { return (byte*)this + bonetablebynameindex; } + void* pVertexBase; + void* pIndexBase; + byte constdirectionallightdot; + byte rootLOD; + byte numAllowedRootLODs; + byte unused[1]; + int unused4; + int numflexcontrollerui; + int flexcontrolleruiindex; + mstudioflexcontrollerui_t* pFlexControllerUI(int i) const { 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]; + int studiohdr2index; + studiohdr2_t* pStudioHdr2() const { return (studiohdr2_t*)(((byte*)this) + studiohdr2index); } + int NumSrcBoneTransforms() const { return studiohdr2index ? pStudioHdr2()->numsrcbonetransform : 0; } + const mstudiosrcbonetransform_t* SrcBoneTransform(int i) const { 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; } + 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 { return studiohdr2index ? pStudioHdr2()->pBoneFlexDriver(i) : NULL; } + int unused2[1]; +}; + +class IDataCache; +class IMDLCache; +class CStudioHdr; + +struct flexweight_t +{ + int key; + float weight; + float influence; +}; + +struct flexsetting_t +{ + int nameindex; + + inline char* pszName(void) const + { + return (char*)(((byte*)this) + nameindex); + } + + int obsolete1; + int numsettings; + int index; + int obsolete2; + int settingindex; +}; + +struct flexsettinghdr_t +{ + 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; + 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); + } + + 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); }; +}; + +#define STUDIO_CONST 1 +#define STUDIO_FETCH1 2 +#define STUDIO_FETCH2 3 +#define STUDIO_ADD 4 +#define STUDIO_SUB 5 +#define STUDIO_MUL 6 +#define STUDIO_DIV 7 +#define STUDIO_NEG 8 +#define STUDIO_EXP 9 +#define STUDIO_OPEN 10 +#define STUDIO_CLOSE 11 +#define STUDIO_COMMA 12 +#define STUDIO_MAX 13 +#define STUDIO_MIN 14 +#define STUDIO_2WAY_0 15 +#define STUDIO_2WAY_1 16 +#define STUDIO_NWAY 17 +#define STUDIO_COMBO 18 +#define STUDIO_DOMINATE 19 +#define STUDIO_DME_LOWER_EYELID 20 +#define STUDIO_DME_UPPER_EYELID 21 +#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 +#define STUDIO_LOOPING 0x0001 +#define STUDIO_SNAP 0x0002 +#define STUDIO_DELTA 0x0004 +#define STUDIO_AUTOPLAY 0x0008 +#define STUDIO_POST 0x0010 +#define STUDIO_ALLZEROS 0x0020 +#define STUDIO_CYCLEPOSE 0x0080 +#define STUDIO_REALTIME 0x0100 +#define STUDIO_LOCAL 0x0200 +#define STUDIO_HIDDEN 0x0400 +#define STUDIO_OVERRIDE 0x0800 +#define STUDIO_ACTIVITY 0x1000 +#define STUDIO_EVENT 0x2000 +#define STUDIO_WORLD 0x4000 +#define STUDIO_AL_POST 0x0010 +#define STUDIO_AL_SPLINE 0x0040 +#define STUDIO_AL_XFADE 0x0080 +#define STUDIO_AL_NOBLEND 0x0200 +#define STUDIO_AL_LOCAL 0x1000 +#define STUDIO_AL_POSE 0x4000 \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/TextureGroupNames.h b/Amalgam/src/SDK/Definitions/Misc/TextureGroupNames.h new file mode 100644 index 0000000..b3e6c66 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/TextureGroupNames.h @@ -0,0 +1,30 @@ +#pragma once + +#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" +#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" +#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" \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/VCollide.h b/Amalgam/src/SDK/Definitions/Misc/VCollide.h new file mode 100644 index 0000000..d2a79cf --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/VCollide.h @@ -0,0 +1,12 @@ +#pragma once + +class CPhysCollide; + +struct vcollide_t +{ + unsigned short solidCount : 15; + unsigned short isPacked : 1; + unsigned short descSize; + CPhysCollide** solids; + char* pKeyValues; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/VGUI.h b/Amalgam/src/SDK/Definitions/Misc/VGUI.h new file mode 100644 index 0000000..044071c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/VGUI.h @@ -0,0 +1,11 @@ +#pragma once + +typedef unsigned int VPANEL; +typedef unsigned long HScheme; +typedef unsigned long HTexture; +typedef unsigned long HCursor; +typedef unsigned long HPanel; +typedef unsigned long HFont; + +const HPanel INVALID_PANEL = 0xffffffff; +const HFont INVALID_FONT = 0; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/VPlane.h b/Amalgam/src/SDK/Definitions/Misc/VPlane.h new file mode 100644 index 0000000..74ce5b6 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/VPlane.h @@ -0,0 +1,18 @@ +#pragma once +#include "BaseTypes.h" +#include "../Types.h" + +typedef int SideType; + +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + +#define VP_EPSILON 0.01f + +class VPlane +{ +public: + Vector m_Normal; + vec_t m_Dist; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/VTF.h b/Amalgam/src/SDK/Definitions/Misc/VTF.h new file mode 100644 index 0000000..d7d7e72 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/VTF.h @@ -0,0 +1,164 @@ +#pragma once +#include "BaseTypes.h" +#include "ImageFormat.h" + +class CUtlBuffer; +struct Rect_t; +class IFileSystem; + +enum CompiledVtfFlags +{ + 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, + TEXTUREFLAGS_ONEBITALPHA = 0x00001000, + TEXTUREFLAGS_EIGHTBITALPHA = 0x00002000, + 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, + TEXTUREFLAGS_SSBUMP = 0x08000000, + TEXTUREFLAGS_UNUSED_10000000 = 0x10000000, + TEXTUREFLAGS_BORDER = 0x20000000, + TEXTUREFLAGS_STREAMABLE_COARSE = 0x40000000, + TEXTUREFLAGS_STREAMABLE_FINE = 0x80000000, + TEXTUREFLAGS_STREAMABLE = (TEXTUREFLAGS_STREAMABLE_COARSE | TEXTUREFLAGS_STREAMABLE_FINE) +}; + +enum VersionedVtfFlags +{ + VERSIONED_VTF_FLAGS_MASK_7_3 = ~0xD1780400 +}; + + +struct VtfProcessingOptions +{ + uint32 cbSize; + + enum Flags0 + { + OPT_DECAY_R = 0x00000001, + OPT_DECAY_G = 0x00000002, + OPT_DECAY_B = 0x00000004, + OPT_DECAY_A = 0x00000008, + OPT_DECAY_EXP_R = 0x00000010, + OPT_DECAY_EXP_G = 0x00000020, + OPT_DECAY_EXP_B = 0x00000040, + OPT_DECAY_EXP_A = 0x00000080, + OPT_NOCOMPRESS = 0x00000100, + OPT_NORMAL_DUDV = 0x00000200, + OPT_FILTER_NICE = 0x00000400, + OPT_SET_ALPHA_ONEOVERMIP = 0x00001000, + OPT_PREMULT_COLOR_ONEOVERMIP = 0x00002000, + OPT_MIP_ALPHATEST = 0x00004000 + }; + + uint32 flags0; + uint8 clrDecayGoal[4]; + uint8 numNotDecayMips[4]; + float fDecayExponentBase[4]; +}; + +enum CubeMapFaceIndex_t +{ + CUBEMAP_FACE_RIGHT = 0, + CUBEMAP_FACE_LEFT, + CUBEMAP_FACE_BACK, + CUBEMAP_FACE_FRONT, + CUBEMAP_FACE_UP, + CUBEMAP_FACE_DOWN, + CUBEMAP_FACE_SPHEREMAP, + CUBEMAP_FACE_COUNT +}; + +enum LookDir_t +{ + LOOK_DOWN_X = 0, + LOOK_DOWN_NEGX, + LOOK_DOWN_Y, + LOOK_DOWN_NEGY, + LOOK_DOWN_Z, + LOOK_DOWN_NEGZ +}; + +#define STREAMING_START_MIPMAP 3 +#define IMAGE_FORMAT_DEFAULT ((ImageFormat)-2) + +class IVTFTexture +{ +public: + virtual ~IVTFTexture() {} + virtual bool Init(int nWidth, int nHeight, int nDepth, ImageFormat fmt, int nFlags, int iFrameCount, int nForceMipCount = -1) = 0; + virtual void SetBumpScale(float flScale) = 0; + virtual void SetReflectivity(const Vector& vecReflectivity) = 0; + virtual void InitLowResImage(int nWidth, int nHeight, ImageFormat fmt) = 0; + virtual void* SetResourceData(uint32 eType, void const* pData, size_t nDataSize) = 0; + virtual void* GetResourceData(uint32 eType, size_t* pDataSize) const = 0; + virtual bool HasResourceEntry(uint32 eType) const = 0; + virtual unsigned int GetResourceTypes(uint32* arrTypesBuffer, int numTypesBufferElems) const = 0; + virtual bool Unserialize(CUtlBuffer& buf, bool bHeaderOnly = false, int nSkipMipLevels = 0) = 0; + virtual bool Serialize(CUtlBuffer& buf) = 0; + 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; + virtual int Width() const = 0; + virtual int Height() const = 0; + virtual int Depth() const = 0; + virtual int MipCount() const = 0; + virtual int RowSizeInBytes(int nMipLevel) const = 0; + 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; + virtual const Vector& Reflectivity() const = 0; + virtual bool IsCubeMap() const = 0; + virtual bool IsNormalMap() const = 0; + virtual bool IsVolumeTexture() const = 0; + virtual void ComputeMipLevelDimensions(int iMipLevel, int* pMipWidth, int* pMipHeight, int* pMipDepth) const = 0; + virtual int ComputeMipSize(int iMipLevel) const = 0; + virtual void ComputeMipLevelSubRect(Rect_t* pSrcRect, int nMipLevel, Rect_t* pSubRect) const = 0; + virtual int ComputeFaceSize(int iStartingMipLevel = 0) const = 0; + virtual int ComputeTotalSize() const = 0; + virtual unsigned char* ImageData() = 0; + virtual unsigned char* ImageData(int iFrame, int iFace, int iMipLevel) = 0; + virtual unsigned char* ImageData(int iFrame, int iFace, int iMipLevel, int x, int y, int z = 0) = 0; + virtual unsigned char* LowResImageData() = 0; + virtual void ConvertImageFormat(ImageFormat fmt, bool bNormalToDUDV) = 0; + virtual void GenerateSpheremap(LookDir_t lookDir = LOOK_DOWN_Z) = 0; + virtual void GenerateHemisphereMap(unsigned char* pSphereMapBitsRGBA, int targetWidth, int targetHeight, LookDir_t lookDir, int iFrame) = 0; + virtual void FixCubemapFaceOrientation() = 0; + virtual void GenerateMipmaps() = 0; + virtual void PutOneOverMipLevelInAlpha() = 0; + virtual void ComputeReflectivity() = 0; + virtual void ComputeAlphaFlags() = 0; + virtual bool ConstructLowResImage() = 0; + virtual void PostProcess(bool bGenerateSpheremap, LookDir_t lookDir = LOOK_DOWN_Z, bool bAllowFixCubemapOrientation = true) = 0; + virtual void MatchCubeMapBorders(int iStage, ImageFormat finalFormat, bool bSkybox) = 0; + virtual void SetAlphaTestThreshholds(float flBase, float flHighFreq) = 0; + virtual void SetPostProcessingSettings(VtfProcessingOptions const* pOptions) = 0; + virtual bool UnserializeEx(CUtlBuffer& buf, bool bHeaderOnly = false, int nForceFlags = 0, int nSkipMipLevels = 0) = 0; + virtual void GetMipmapRange(int* pOutFinest, int* pOutCoarsest) = 0; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/bitbuf.cpp b/Amalgam/src/SDK/Definitions/Misc/bitbuf.cpp new file mode 100644 index 0000000..bff8fea --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/bitbuf.cpp @@ -0,0 +1,1504 @@ +#include "bitbuf.h" + +#include "../Types.h" + +inline void Q_memcpy(void* dest, const void* src, int count) +{ + int i; + if (((std::uintptr_t(dest) | std::uintptr_t(src) | count) & 3) == 0) + { + count >>= 2; + for (i = 0; i < count; i++) + static_cast(dest)[i] = ((int*)src)[i]; + } + else + { + for (i = 0; i < count; i++) + static_cast(dest)[i] = ((char*)src)[i]; + } +} + +void bf_write::StartWriting(void* pData, int nBytes, int iStartBit, int nBits) +{ + //using fn = int(__thiscall *)(bf_write *, void *, int, int, int); + //static fn FN = reinterpret_cast(g_Pattern.Find(_(L"engine.dll"), _(L"55 8B EC 8B 45 08 8B 55 0C 83 E2 FC 89 01 8B 45 14"))); + //return FN(this, pData, nBytes, iStartBit, nBits); + if (!(nBytes % 4 == 0)) + return; + + if (!((std::uintptr_t(pData) & 3) == 0)) + return; + + nBytes &= ~3; + + m_pData = (unsigned long*)pData; + m_nDataBytes = nBytes; + + if (nBits == -1) + m_nDataBits = nBytes << 3; + else if (nBits <= nBytes * 8) + m_nDataBits = nBits; + + m_iCurBit = iStartBit; + m_bOverflow = false; +} + +#include "bitbuf.h" +#include + +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// 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" + +#define COORD_INTEGER_BITS 14 +#define COORD_FRACTIONAL_BITS 5 +#define COORD_DENOMINATOR (1<<(COORD_FRACTIONAL_BITS)) +#define COORD_RESOLUTION (1.0/(COORD_DENOMINATOR)) + +// Special threshold for networking multiplayer origins +#define COORD_INTEGER_BITS_MP 11 +#define COORD_FRACTIONAL_BITS_MP_LOWPRECISION 3 +#define COORD_DENOMINATOR_LOWPRECISION (1<<(COORD_FRACTIONAL_BITS_MP_LOWPRECISION)) +#define COORD_RESOLUTION_LOWPRECISION (1.0/(COORD_DENOMINATOR_LOWPRECISION)) + +#define NORMAL_FRACTIONAL_BITS 11 +#define NORMAL_DENOMINATOR ( (1<<(NORMAL_FRACTIONAL_BITS)) - 1 ) +#define NORMAL_RESOLUTION (1.0/(NORMAL_DENOMINATOR)) + +// this is limited by the network fractional bits used for coords +// because net coords will be only be accurate to 5 bits fractional +// Standard collision test epsilon +// 1/32nd inch collision epsilon + + +#define FAST_BIT_SCAN 1 +#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; +} + +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 << littleBit); + } +}; +static CBitWriteMasksInit g_BitWriteMasksInit; + + +// ---------------------------------------------------------------------------------------- // +// bf_write +// ---------------------------------------------------------------------------------------- // + +bf_write::bf_write() +{ + m_pData = NULL; + m_nDataBytes = 0; + m_nDataBits = -1; // set to -1 so we generate overflow on any operation + m_iCurBit = 0; + m_bOverflow = false; + m_bAssertOnOverflow = true; + m_pDebugName = NULL; +} + +bf_write::bf_write(const char* pDebugName, void* pData, int nBytes, int nBits) +{ + m_bAssertOnOverflow = true; + m_pDebugName = pDebugName; + StartWriting(pData, nBytes, 0, nBits); +} + +bf_write::bf_write(void* pData, int nBytes, int nBits) +{ + m_bAssertOnOverflow = true; + m_pDebugName = NULL; + StartWriting(pData, nBytes, 0, nBits); +} + + +void bf_write::Reset() +{ + m_iCurBit = 0; + m_bOverflow = false; +} + + +void bf_write::SetAssertOnOverflow(bool bAssert) +{ + m_bAssertOnOverflow = bAssert; +} + + +const char* bf_write::GetDebugName() +{ + return m_pDebugName; +} + + +void bf_write::SetDebugName(const char* pDebugName) +{ + m_pDebugName = pDebugName; +} + + +void bf_write::SeekToBit(int bitPos) +{ + m_iCurBit = bitPos; +} + + +// Sign bit comes first +void bf_write::WriteSBitLong(int data, int numbits) +{ + // Force the sign-extension bit to be correct even in the case of overflow. + int nValue = data; + int nPreserveBits = (0x7FFFFFFF >> (32 - numbits)); + int nSignExtension = (nValue >> 31) & ~nPreserveBits; + nValue &= nPreserveBits; + nValue |= nSignExtension; + + nullAssert(nValue == data, "WriteSBitLong: 0x%08x does not fit in %d bits", data, numbits); + + WriteUBitLong(nValue, numbits, false); +} + +void bf_write::WriteVarInt32(uint32_t 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_t* target = ((uint8_t*)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_t 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_t* target = ((uint8_t*)m_pData) + (m_iCurBit >> 3); + + // Splitting into 32-bit pieces gives better performance on 32-bit + // processors. + uint32_t part0 = static_cast(data); + uint32_t part1 = static_cast(data >> 28); + uint32_t 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; + } + } + + nullAssert(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_t data) +{ + WriteVarInt32(bitbuf::ZigZagEncode32(data)); +} + +void bf_write::WriteSignedVarInt64(int64_t data) +{ + WriteVarInt64(bitbuf::ZigZagEncode64(data)); +} + +int bf_write::ByteSizeVarInt32(uint32_t data) +{ + int size = 1; + while (data > 0x7F) + { + size++; + data >>= 7; + } + return size; +} + +int bf_write::ByteSizeVarInt64(uint64_t data) +{ + int size = 1; + while (data > 0x7F) + { + size++; + data >>= 7; + } + return size; +} + +//int bf_write::ByteSizeSignedVarInt32(int32_t data) +//{ +// return ByteSizeVarInt32(bitbuf::ZigZagEncode32(data)); +//} +// +//int bf_write::ByteSizeSignedVarInt64(int64_t 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 ((std::uintptr_t(pOut) & 3) != 0 && nBitsLeft >= 8) + { + + WriteUBitLong(*pOut, 8, false); + ++pOut; + nBitsLeft -= 8; + } + + if ((nBitsLeft >= 32) && (m_iCurBit & 7) == 0) + { + // current bit is char 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 (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 = (int)fabsf(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 = (int)fabsf(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 Vec3& 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 Vec3& 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 Vec3& fa) +{ + // FIXME: + Vec3 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_t val) +{ + unsigned int* pLongs = (unsigned int*)&val; + + // Insert the two DWORDS according to network endian + const short endianIndex = 0x0100; + char* idx = (char*)&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. + nullAssert(((size_t)pData & 3) == 0); + + m_pData = (unsigned long*)pData; + m_nDataBytes = nBytes; + + if (nBits == -1) + { + m_nDataBits = m_nDataBytes << 3; + } + else + { + nullAssert(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) + { + nullAssert(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; + } + + // 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. + nullAssert(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, int(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.0 / 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_t bf_read::ReadVarInt32() +{ + uint32_t result = 0; + int count = 0; + uint32_t b; + + do + { + if (count == bitbuf::kMaxVarint32Bytes) + { + return result; + } + b = ReadUBitLong(8); + result |= (b & 0x7F) << (7 * count); + ++count; + } while (b & 0x80); + + return result; +} + +uint64_t bf_read::ReadVarInt64() +{ + uint64_t result = 0; + int count = 0; + uint64_t 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_t bf_read::ReadSignedVarInt32() +{ + uint32_t value = ReadVarInt32(); + return bitbuf::ZigZagDecode32(value); +} + +int64_t bf_read::ReadSignedVarInt64() +{ + uint32_t value = 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 = intval + ((float)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 (bits & 1) ? -intval : intval; + } + return 0.f; + } + + static const float mul_table[4] = + { + 1.f / (1 << COORD_FRACTIONAL_BITS), + -1.f / (1 << COORD_FRACTIONAL_BITS), + 1.f / (1 << COORD_FRACTIONAL_BITS_MP_LOWPRECISION), + -1.f / (1 << COORD_FRACTIONAL_BITS_MP_LOWPRECISION) + }; + //equivalent to: float multiply = mul_table[ ((flags & SIGN) ? 1 : 0) + bLowPrecision*2 ]; + float multiply = *(float*)((uintptr_t)&mul_table[0] + (flags & 4) + bLowPrecision * 8); + + static const unsigned char numbits_table[8] = + { + COORD_FRACTIONAL_BITS, + COORD_FRACTIONAL_BITS, + COORD_FRACTIONAL_BITS + COORD_INTEGER_BITS, + COORD_FRACTIONAL_BITS + COORD_INTEGER_BITS_MP, + COORD_FRACTIONAL_BITS_MP_LOWPRECISION, + COORD_FRACTIONAL_BITS_MP_LOWPRECISION, + COORD_FRACTIONAL_BITS_MP_LOWPRECISION + COORD_INTEGER_BITS, + COORD_FRACTIONAL_BITS_MP_LOWPRECISION + COORD_INTEGER_BITS_MP + }; + unsigned int bits = ReadUBitLong(numbits_table[(flags & (INBOUNDS | INTVAL)) + bLowPrecision * 4]); + + if (flags & INTVAL) + { + // Shuffle the bits to remap the integer portion from [0,N] to [1,N+1] + // and then paste in front of the fractional parts so we only need one + // int-to-float conversion. + + unsigned int fracbitsMP = bits >> COORD_INTEGER_BITS_MP; + unsigned int fracbits = bits >> COORD_INTEGER_BITS; + + unsigned int intmaskMP = ((1 << COORD_INTEGER_BITS_MP) - 1); + unsigned int intmask = ((1 << COORD_INTEGER_BITS) - 1); + + unsigned int selectNotMP = (flags & INBOUNDS) - 1; + + fracbits -= fracbitsMP; + fracbits &= selectNotMP; + fracbits += fracbitsMP; + + intmask -= intmaskMP; + intmask &= selectNotMP; + intmask += intmaskMP; + + unsigned int intpart = (bits & intmask) + 1; + unsigned int intbitsLow = intpart << COORD_FRACTIONAL_BITS_MP_LOWPRECISION; + unsigned int intbits = intpart << COORD_FRACTIONAL_BITS; + unsigned int selectNotLow = (unsigned int)bLowPrecision - 1; + + intbits -= intbitsLow; + intbits &= selectNotLow; + intbits += intbitsLow; + + bits = fracbits | intbits; + } + + return (int)bits * multiply; +} + +unsigned int bf_read::ReadBitCoordBits(void) +{ +#if defined( BB_PROFILING ) + VPROF("bf_read::ReadBitCoordBits"); +#endif + + unsigned int flags = ReadUBitLong(2); + if (flags == 0) + return 0; + + static const int numbits_table[3] = + { + COORD_INTEGER_BITS + 1, + COORD_FRACTIONAL_BITS + 1, + COORD_INTEGER_BITS + COORD_FRACTIONAL_BITS + 1 + }; + return ReadUBitLong(numbits_table[flags - 1]) * 4 + flags; +} + +unsigned int bf_read::ReadBitCoordMPBits(bool bIntegral, bool bLowPrecision) +{ +#if defined( BB_PROFILING ) + VPROF("bf_read::ReadBitCoordMPBits"); +#endif + + unsigned int flags = ReadUBitLong(2); + enum { INBOUNDS = 1, INTVAL = 2 }; + int numbits = 0; + + if (bIntegral) + { + if (flags & INTVAL) + { + numbits = (flags & INBOUNDS) ? (1 + COORD_INTEGER_BITS_MP) : (1 + COORD_INTEGER_BITS); + } + else + { + return flags; // no extra bits + } + } + else + { + static const unsigned char numbits_table[8] = + { + 1 + COORD_FRACTIONAL_BITS, + 1 + COORD_FRACTIONAL_BITS, + 1 + COORD_FRACTIONAL_BITS + COORD_INTEGER_BITS, + 1 + COORD_FRACTIONAL_BITS + COORD_INTEGER_BITS_MP, + 1 + COORD_FRACTIONAL_BITS_MP_LOWPRECISION, + 1 + COORD_FRACTIONAL_BITS_MP_LOWPRECISION, + 1 + COORD_FRACTIONAL_BITS_MP_LOWPRECISION + COORD_INTEGER_BITS, + 1 + COORD_FRACTIONAL_BITS_MP_LOWPRECISION + COORD_INTEGER_BITS_MP + }; + numbits = numbits_table[flags + bLowPrecision * 4]; + } + + return flags + ReadUBitLong(numbits) * 4; +} + +void bf_read::ReadBitVec3Coord(Vec3& fa) +{ + int xflag, yflag, zflag; + + // This Vector3 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 = Vec3(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 bf_read::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 bf_read::ReadBitVec3Normal(Vec3& 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 bf_read::ReadBitAngles(Vec3& fa) +{ + Vec3 tmp; + ReadBitVec3Coord(tmp); + //fa(tmp.x, tmp.y, tmp.z); +} + +int64_t bf_read::ReadLongLong() +{ + int64_t retval; + unsigned int* pLongs = (unsigned int*)&retval; + + // Read the two DWORDs according to network endian + const short endianIndex = 0x0100; + char* idx = (char*)&endianIndex; + pLongs[*idx++] = ReadUBitLong(sizeof(long) << 3); + pLongs[*idx] = ReadUBitLong(sizeof(long) << 3); + + return retval; +} + +float bf_read::ReadFloat() +{ + float ret; + nullAssert(sizeof(ret) == 4); + ReadBits(&ret, 32); + + // Swap the float, since ReadBits reads raw data + LittleFloat(&ret, &ret); + return ret; +} + +bool bf_read::ReadBytes(void* pOut, int nBytes) +{ + ReadBits(pOut, nBytes << 3); + return !IsOverflowed(); +} + +bool bf_read::ReadString(char* pStr, int maxLen, bool bLine, int* pOutNumChars) +{ + nullAssert(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. + nullAssert(iChar < maxLen); + pStr[iChar] = 0; + + if (pOutNumChars) + *pOutNumChars = iChar; + + return !IsOverflowed() && !bTooSmall; +} + + +char* bf_read::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; +} + +void bf_read::ExciseBits(int startbit, int bitstoremove) +{ + int endbit = startbit + bitstoremove; + int remaining_to_end = m_nDataBits - endbit; + + bf_write temp; + temp.StartWriting((void*)m_pData, m_nDataBits << 3, startbit); + + Seek(endbit); + + for (int i = 0; i < remaining_to_end; i++) + { + temp.WriteOneBit(ReadOneBit()); + } + + Seek(startbit); + + m_nDataBits -= bitstoremove; + m_nDataBytes = m_nDataBits >> 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]); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/bitbuf.h b/Amalgam/src/SDK/Definitions/Misc/bitbuf.h new file mode 100644 index 0000000..0ce0ce1 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/bitbuf.h @@ -0,0 +1,805 @@ +#pragma once + +#pragma warning (disable : 4244) +#pragma warning (disable : 4002) +class Vec3; + +#include +#include + +#define nullAssert assert + +#if _DEBUG +#define BITBUF_INLINE inline +#else +#define BITBUF_INLINE FORCEINLINE +#endif + +#define RESTRICT + +//----------------------------------------------------------------------------- +// 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); + +#define BITS_PER_INT 32 + +//----------------------------------------------------------------------------- +// Helpers. +//----------------------------------------------------------------------------- +template +inline T WordSwapC(T w) +{ + uint16_t temp; + + temp = ((*((uint16_t*)&w) & 0xff00) >> 8); + temp |= ((*((uint16_t*)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template +inline T DWordSwapC(T dw) +{ + uint32_t temp; + + temp = *((uint32_t*)&dw) >> 24; + temp |= ((*((uint32_t*)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32_t*)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32_t*)&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_t * below is unsafe and may have wrong results + // or even crash. + //PLAT_COMPILE_TIME_nullAssert(sizeof(dw) == sizeof(uint64_t)); + + uint64_t temp; + + temp = *((uint64_t*)&dw) >> 56; + temp |= ((*((uint64_t*)&dw) & 0x00FF000000000000ull) >> 40); + temp |= ((*((uint64_t*)&dw) & 0x0000FF0000000000ull) >> 24); + temp |= ((*((uint64_t*)&dw) & 0x000000FF00000000ull) >> 8); + temp |= ((*((uint64_t*)&dw) & 0x00000000FF000000ull) << 8); + temp |= ((*((uint64_t*)&dw) & 0x0000000000FF0000ull) << 24); + temp |= ((*((uint64_t*)&dw) & 0x000000000000FF00ull) << 40); + temp |= ((*((uint64_t*)&dw) & 0x00000000000000FFull) << 56); + + return *((T*)&temp); +} + +inline int BitByte(int bits) +{ + // return PAD_NUMBER( bits, 8 ) >> 3; + return (bits + 7) >> 3; +} + +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; } + + + +#define WordSwap WordSwapC +#define DWordSwap DWordSwapC +#define QWordSwap QWordSwapC + + +#define SafeSwapFloat( pOut, pIn ) (*((unsigned int*)pOut) = DWordSwap( *((unsigned int*)pIn) )) +inline short BigShort(short val) { int test = 1; return (*(char*)&test == 1) ? WordSwap(val) : val; } +inline uint16_t BigWord(uint16_t 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_t BigDWord(uint32_t 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_t LittleWord(uint16_t 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_t LittleDWord(uint32_t val) { int test = 1; return (*(char*)&test == 1) ? val : DWordSwap(val); } +inline uint64_t LittleQWord(uint64_t val) { int test = 1; return (*(char*)&test == 1) ? val : QWordSwap(val); } +inline short SwapShort(short val) { return WordSwap(val); } +inline uint16_t SwapWord(uint16_t val) { return WordSwap(val); } +inline long SwapLong(long val) { return DWordSwap(val); } +inline uint32_t SwapDWord(uint32_t 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); } + + +#define FORCEINLINE __forceinline + +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); +} + + + +//----------------------------------------------------------------------------- +// 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_t -> uint32_t + // ------------------------- + // 0 -> 0 + // -1 -> 1 + // 1 -> 2 + // -2 -> 3 + // ... -> ... + // 2147483647 -> 4294967294 + // -2147483648 -> 4294967295 + // + // >> encode >> + // << decode << + + inline uint32_t ZigZagEncode32(int32_t n) + { + // Note: the right-shift must be arithmetic + return(n << 1) ^ (n >> 31); + } + + inline int32_t ZigZagDecode32(uint32_t n) + { + return(n >> 1) ^ -static_cast(n & 1); + } + + inline uint64_t ZigZagEncode64(int64_t n) + { + // Note: the right-shift must be arithmetic + return(n << 1) ^ (n >> 63); + } + + inline int64_t ZigZagDecode64(uint64_t n) + { + return(n >> 1) ^ -static_cast(n & 1); + } + + const int kMaxVarintBytes = 10; + const int kMaxVarint32Bytes = 5; +} + +class bf_write +{ +public: + bf_write(); + bf_write(void* pData, int nBytes, int nMaxBits = -1); + bf_write(const char* pDebugName, void* pData, int nBytes, int nMaxBits = -1); + void StartWriting(void* pData, int nBytes, int iStartBit = 0, int nMaxBits = -1); + void Reset(); + unsigned char* GetBasePointer() { return (unsigned char*)m_pData; } + void SetAssertOnOverflow(bool bAssert); + const char* GetDebugName(); + void SetDebugName(const char* pDebugName); + void SeekToBit(int bitPos); + void WriteOneBit(int nValue); + void WriteOneBitNoCheck(int nValue); + void WriteOneBitAt(int iBit, int nValue); + void WriteUBitLong(unsigned int data, int numbits, bool bCheckRange = true); + void WriteSBitLong(int data, int numbits); + void WriteBitLong(unsigned int data, int numbits, bool bSigned); + bool WriteBits(const void* pIn, int nBits); + void WriteUBitVar(unsigned int data); + void WriteVarInt32(uint32_t data); + void WriteVarInt64(uint64_t data); + void WriteSignedVarInt32(int32_t data); + void WriteSignedVarInt64(int64_t data); + int ByteSizeVarInt32(uint32_t data); + int ByteSizeVarInt64(uint64_t data); + int ByteSizeSignedVarInt32(int32_t data); + int ByteSizeSignedVarInt64(int64_t data); + 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 Vec3& fa); + void WriteBitNormal(float f); + void WriteBitVec3Normal(const Vec3& fa); + void WriteBitAngles(const Vec3& fa); + void WriteChar(int val); + void WriteByte(int val); + void WriteShort(int val); + void WriteWord(int val); + void WriteLong(long val); + void WriteLongLong(int64_t val); + void WriteFloat(float val); + bool WriteBytes(const void* pBuf, int nBytes); + bool WriteString(const char* pStr); + int GetNumBytesWritten() const; + int GetNumBitsWritten() const; + int GetMaxNumBits(); + int GetNumBitsLeft(); + int GetNumBytesLeft(); + unsigned char* GetData(); + const unsigned char* GetData() const; + bool CheckForOverflow(int nBits); + inline bool IsOverflowed() const { return m_bOverflow; } + void SetOverflowFlag(); + +public: + unsigned long* m_pData; + int m_nDataBytes; + int m_nDataBits; + int m_iCurBit; + 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) + { + nullAssert(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 +} + +BITBUF_INLINE void bf_write::WriteUBitLong(unsigned int curData, int numbits, bool bCheckRange) RESTRICT +{ +#ifdef _DEBUG + // Make sure it doesn't overflow. + if (bCheckRange && numbits < 32) + { + if (curData >= (unsigned long)(1 << numbits)) + { + CallErrorHandler(BITBUFERROR_VALUE_OUT_OF_RANGE, GetDebugName()); + } + } + nullAssert(numbits >= 0 && numbits <= 32); +#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. + nullAssert((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) +{ + long intVal; + + nullAssert(sizeof(long) == sizeof(float)); + nullAssert(sizeof(float) == 4); + + intVal = *((long*)&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]; +}; + + +class bf_read +{ +public: + bf_read(); + bf_read(const void* pData, int nBytes, int nBits = -1); + bf_read(const char* pDebugName, const void* pData, int nBytes, int nBits = -1); + void StartReading(const void* pData, int nBytes, int iStartBit = 0, int nBits = -1); + void Reset(); + void SetAssertOnOverflow(bool bAssert); + const char* GetDebugName() const { return m_pDebugName; } + void SetDebugName(const char* pName); + void ExciseBits(int startbit, int bitstoremove); + 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: + const unsigned long* GetBasePointer() { return m_pData; } + BITBUF_INLINE int TotalBytesAvailable(void) const + { + return m_nDataBytes; + } + void ReadBits(void* pOut, int nBits); + int ReadBitsClamped_ptr(void* pOut, size_t outSizeBytes, size_t nBits); + 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); + unsigned int ReadUBitVar(); + unsigned int ReadUBitVarInternal(int encodingType); + uint32_t ReadVarInt32(); + uint64_t ReadVarInt64(); + int32_t ReadSignedVarInt32(); + int64_t ReadSignedVarInt64(); + unsigned int ReadBitLong(int numbits, bool bSigned); + float ReadBitCoord(); + float ReadBitCoordMP(bool bIntegral, bool bLowPrecision); + float ReadBitFloat(); + float ReadBitNormal(); + void ReadBitVec3Coord(Vec3& fa); + void ReadBitVec3Normal(Vec3& fa); + void ReadBitAngles(Vec3& fa); + unsigned int ReadBitCoordBits(); + unsigned int ReadBitCoordMPBits(bool bIntegral, bool bLowPrecision); + 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_t ReadLongLong(); + float ReadFloat(); + bool ReadBytes(void* pOut, int nBytes); + bool ReadString(char* pStr, int bufLen, bool bLine = false, int* pOutNumChars = NULL); + char* ReadAndAllocateString(bool* pOverflow = 0); + int CompareBits(bf_read* RESTRICT other, int bits) RESTRICT; + int CompareBitsAt(int offset, bf_read* RESTRICT other, int otherOffset, int bits) RESTRICT; + int GetNumBytesLeft(); + int GetNumBytesRead(); + int GetNumBitsLeft(); + int GetNumBitsRead() const; + 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. + void SetOverflowFlag(); +public: + unsigned long* m_pData; + int m_nDataBytes; + int m_nDataBits; + int m_iCurBit; + bool m_bOverflow; + 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_t 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 +{ + nullAssert(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)); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/dt_common.h b/Amalgam/src/SDK/Definitions/Misc/dt_common.h new file mode 100644 index 0000000..11a897a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/dt_common.h @@ -0,0 +1,191 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#pragma warning (push) +#pragma warning (disable : 26495) + +#pragma once + +//#include +#include + +// 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_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; + +typedef enum +{ + DPT_Int = 0, + DPT_Float, + DPT_Vector, + DPT_VectorXY, + 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 + DPT_NUMSendPropTypes +} SendPropType; + +#pragma warning (push) +#pragma warning (disable : 26812) + +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: + sprintf_s(text, sizeof(text), "%i", m_Int); + break; + case DPT_Float: + sprintf_s(text, sizeof(text), "%.3f", m_Float); + break; + case DPT_Vector: + sprintf_s(text, sizeof(text), "(%.3f,%.3f,%.3f)", + m_Vector[0], m_Vector[1], m_Vector[2]); + 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: + sprintf_s(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: + sprintf_s(text, sizeof(text), "Array"); + break; + case DPT_DataTable: + sprintf_s(text, sizeof(text), "DataTable"); + break; + default: + sprintf_s(text, sizeof(text), "DVariant type %i unknown", m_Type); + break; + } + + return text; + } + + union + { + float m_Float; + long m_Int; + 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 + }; + SendPropType m_Type; +}; + +#pragma warning (pop) + +// 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; +} + + +#pragma warning (pop) \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Misc/dt_recv.h b/Amalgam/src/SDK/Definitions/Misc/dt_recv.h new file mode 100644 index 0000000..e258b7c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/dt_recv.h @@ -0,0 +1,533 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef DATATABLE_RECV_H +#define DATATABLE_RECV_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "dt_common.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; +}; +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_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); + +// 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 +); + +// 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 \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/NullInterfaces.cpp b/Amalgam/src/SDK/Definitions/NullInterfaces.cpp new file mode 100644 index 0000000..c63b425 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/NullInterfaces.cpp @@ -0,0 +1,38 @@ +#include "Interfaces.h" + +#include "../../Utils/Assert/Assert.h" + +#define Validate(x) AssertCustom(x, std::format("H::Interfaces.Initialize() Failed to initialize {}", #x).c_str()) + +MAKE_SIGNATURE(Get_TFPartyClient, "client.dll", "48 8B 05 ? ? ? ? C3 CC CC CC CC CC CC CC CC 48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56", 0x0); +MAKE_SIGNATURE(Get_SteamNetworkingUtils, "client.dll", "40 53 48 83 EC ? 48 8B D9 48 8D 15 ? ? ? ? 33 C9 FF 15 ? ? ? ? 33 C9", 0x0); + +void CNullInterfaces::Initialize() +{ + I::TFPartyClient = S::Get_TFPartyClient.As()(); + Validate(I::TFPartyClient); + + const HSteamPipe hsNewPipe = I::SteamClient->CreateSteamPipe(); + Validate(hsNewPipe); + + const HSteamPipe hsNewUser = I::SteamClient->ConnectToGlobalUser(hsNewPipe); + Validate(hsNewUser); + + I::SteamFriends = I::SteamClient->GetISteamFriends(hsNewUser, hsNewPipe, STEAMFRIENDS_INTERFACE_VERSION); + Validate(I::SteamFriends); + + I::SteamUtils = I::SteamClient->GetISteamUtils(hsNewUser, STEAMUTILS_INTERFACE_VERSION); + Validate(I::SteamUtils); + + I::SteamApps = I::SteamClient->GetISteamApps(hsNewUser, hsNewPipe, STEAMAPPS_INTERFACE_VERSION); + Validate(I::SteamApps); + + I::SteamUserStats = I::SteamClient->GetISteamUserStats(hsNewUser, hsNewPipe, STEAMUSERSTATS_INTERFACE_VERSION); + Validate(I::SteamUserStats); + + I::SteamUser = I::SteamClient->GetISteamUser(hsNewUser, hsNewPipe, STEAMUSER_INTERFACE_VERSION); + Validate(I::SteamUser); + + S::Get_SteamNetworkingUtils.As()(&I::SteamNetworkingUtils); + Validate(I::SteamNetworkingUtils); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamAppList.h b/Amalgam/src/SDK/Definitions/Steam/ISteamAppList.h new file mode 100644 index 0000000..eeff3db --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamAppList.h @@ -0,0 +1,68 @@ +//====== 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" + +//----------------------------------------------------------------------------- +// 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 (not downloaded yet) +//--------------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN(SteamAppInstalled_t, k_iSteamAppListCallbacks + 1) +STEAM_CALLBACK_MEMBER(0, AppId_t, m_nAppID) // ID of the app that installs +STEAM_CALLBACK_MEMBER(1, int, m_iInstallFolderIndex) // library folder the app is installed +STEAM_CALLBACK_END(2) + + +//--------------------------------------------------------------------------------- +// 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_MEMBER(1, int, m_iInstallFolderIndex) // library folder the app was installed +STEAM_CALLBACK_END(2) + + +#pragma pack( pop ) +#endif // ISTEAMAPPLIST_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamAppTicket.h b/Amalgam/src/SDK/Definitions/Steam/ISteamAppTicket.h new file mode 100644 index 0000000..21fb9e1 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/ISteamApps.h b/Amalgam/src/SDK/Definitions/Steam/ISteamApps.h new file mode 100644 index 0000000..881138b --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamApps.h @@ -0,0 +1,192 @@ +//====== 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; + + // check if game is a timed trial with limited playtime + virtual bool BIsTimedTrial( uint32* punSecondsAllowed, uint32* punSecondsPlayed ) = 0; + + // set current DLC AppID being played (or 0 if none). Allows Steam to track usage of major DLC extensions + virtual bool SetDlcContext( AppId_t nAppID ) = 0; +}; + +#define STEAMAPPS_INTERFACE_VERSION "STEAMAPPS_INTERFACE_VERSION008" + +// Global interface accessor +inline ISteamApps *SteamApps(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamApps *, SteamApps, 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: 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; // +}; + + +//----------------------------------------------------------------------------- +// Purpose: called for games in Timed Trial mode +//----------------------------------------------------------------------------- +struct TimedTrialStatus_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 30 }; + AppId_t m_unAppID; // appID + bool m_bIsOffline; // if true, time allowed / played refers to offline time, not total time + uint32 m_unSecondsAllowed; // how many seconds the app can be played in total + uint32 m_unSecondsPlayed; // how many seconds the app was already played +}; + +#pragma pack( pop ) +#endif // ISTEAMAPPS_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamClient.h b/Amalgam/src/SDK/Definitions/Steam/ISteamClient.h new file mode 100644 index 0000000..0e4d0d8 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamClient.h @@ -0,0 +1,179 @@ +//====== 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( const SteamIPAddress_t &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; + + STEAM_PRIVATE_API( virtual void DestroyAllInterfaces() = 0; ) + +}; +#define STEAMCLIENT_INTERFACE_VERSION "SteamClient020" + +#ifndef STEAM_API_EXPORTS + +// Global ISteamClient interface accessor +inline ISteamClient *SteamClient(); +STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamClient *, SteamClient, SteamInternal_CreateInterface( STEAMCLIENT_INTERFACE_VERSION ), "global", 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/Amalgam/src/SDK/Definitions/Steam/ISteamController.h b/Amalgam/src/SDK/Definitions/Steam/ISteamController.h new file mode 100644 index 0000000..4f90132 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamController.h @@ -0,0 +1,727 @@ +//====== 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 24 + +#define STEAM_CONTROLLER_MAX_DIGITAL_ACTIONS 256 + +#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 + +// 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, + + // Added in SDK 1.51 + k_EControllerActionOrigin_PS5_X, + k_EControllerActionOrigin_PS5_Circle, + k_EControllerActionOrigin_PS5_Triangle, + k_EControllerActionOrigin_PS5_Square, + k_EControllerActionOrigin_PS5_LeftBumper, + k_EControllerActionOrigin_PS5_RightBumper, + k_EControllerActionOrigin_PS5_Option, //Start + k_EControllerActionOrigin_PS5_Create, //Back + k_EControllerActionOrigin_PS5_Mute, + k_EControllerActionOrigin_PS5_LeftPad_Touch, + k_EControllerActionOrigin_PS5_LeftPad_Swipe, + k_EControllerActionOrigin_PS5_LeftPad_Click, + k_EControllerActionOrigin_PS5_LeftPad_DPadNorth, + k_EControllerActionOrigin_PS5_LeftPad_DPadSouth, + k_EControllerActionOrigin_PS5_LeftPad_DPadWest, + k_EControllerActionOrigin_PS5_LeftPad_DPadEast, + k_EControllerActionOrigin_PS5_RightPad_Touch, + k_EControllerActionOrigin_PS5_RightPad_Swipe, + k_EControllerActionOrigin_PS5_RightPad_Click, + k_EControllerActionOrigin_PS5_RightPad_DPadNorth, + k_EControllerActionOrigin_PS5_RightPad_DPadSouth, + k_EControllerActionOrigin_PS5_RightPad_DPadWest, + k_EControllerActionOrigin_PS5_RightPad_DPadEast, + k_EControllerActionOrigin_PS5_CenterPad_Touch, + k_EControllerActionOrigin_PS5_CenterPad_Swipe, + k_EControllerActionOrigin_PS5_CenterPad_Click, + k_EControllerActionOrigin_PS5_CenterPad_DPadNorth, + k_EControllerActionOrigin_PS5_CenterPad_DPadSouth, + k_EControllerActionOrigin_PS5_CenterPad_DPadWest, + k_EControllerActionOrigin_PS5_CenterPad_DPadEast, + k_EControllerActionOrigin_PS5_LeftTrigger_Pull, + k_EControllerActionOrigin_PS5_LeftTrigger_Click, + k_EControllerActionOrigin_PS5_RightTrigger_Pull, + k_EControllerActionOrigin_PS5_RightTrigger_Click, + k_EControllerActionOrigin_PS5_LeftStick_Move, + k_EControllerActionOrigin_PS5_LeftStick_Click, + k_EControllerActionOrigin_PS5_LeftStick_DPadNorth, + k_EControllerActionOrigin_PS5_LeftStick_DPadSouth, + k_EControllerActionOrigin_PS5_LeftStick_DPadWest, + k_EControllerActionOrigin_PS5_LeftStick_DPadEast, + k_EControllerActionOrigin_PS5_RightStick_Move, + k_EControllerActionOrigin_PS5_RightStick_Click, + k_EControllerActionOrigin_PS5_RightStick_DPadNorth, + k_EControllerActionOrigin_PS5_RightStick_DPadSouth, + k_EControllerActionOrigin_PS5_RightStick_DPadWest, + k_EControllerActionOrigin_PS5_RightStick_DPadEast, + k_EControllerActionOrigin_PS5_DPad_Move, + k_EControllerActionOrigin_PS5_DPad_North, + k_EControllerActionOrigin_PS5_DPad_South, + k_EControllerActionOrigin_PS5_DPad_West, + k_EControllerActionOrigin_PS5_DPad_East, + k_EControllerActionOrigin_PS5_Gyro_Move, + k_EControllerActionOrigin_PS5_Gyro_Pitch, + k_EControllerActionOrigin_PS5_Gyro_Yaw, + k_EControllerActionOrigin_PS5_Gyro_Roll, + + k_EControllerActionOrigin_XBoxOne_LeftGrip_Lower, + k_EControllerActionOrigin_XBoxOne_LeftGrip_Upper, + k_EControllerActionOrigin_XBoxOne_RightGrip_Lower, + k_EControllerActionOrigin_XBoxOne_RightGrip_Upper, + k_EControllerActionOrigin_XBoxOne_Share, + + // Added in SDK 1.53 + k_EControllerActionOrigin_SteamDeck_A, + k_EControllerActionOrigin_SteamDeck_B, + k_EControllerActionOrigin_SteamDeck_X, + k_EControllerActionOrigin_SteamDeck_Y, + k_EControllerActionOrigin_SteamDeck_L1, + k_EControllerActionOrigin_SteamDeck_R1, + k_EControllerActionOrigin_SteamDeck_Menu, + k_EControllerActionOrigin_SteamDeck_View, + k_EControllerActionOrigin_SteamDeck_LeftPad_Touch, + k_EControllerActionOrigin_SteamDeck_LeftPad_Swipe, + k_EControllerActionOrigin_SteamDeck_LeftPad_Click, + k_EControllerActionOrigin_SteamDeck_LeftPad_DPadNorth, + k_EControllerActionOrigin_SteamDeck_LeftPad_DPadSouth, + k_EControllerActionOrigin_SteamDeck_LeftPad_DPadWest, + k_EControllerActionOrigin_SteamDeck_LeftPad_DPadEast, + k_EControllerActionOrigin_SteamDeck_RightPad_Touch, + k_EControllerActionOrigin_SteamDeck_RightPad_Swipe, + k_EControllerActionOrigin_SteamDeck_RightPad_Click, + k_EControllerActionOrigin_SteamDeck_RightPad_DPadNorth, + k_EControllerActionOrigin_SteamDeck_RightPad_DPadSouth, + k_EControllerActionOrigin_SteamDeck_RightPad_DPadWest, + k_EControllerActionOrigin_SteamDeck_RightPad_DPadEast, + k_EControllerActionOrigin_SteamDeck_L2_SoftPull, + k_EControllerActionOrigin_SteamDeck_L2, + k_EControllerActionOrigin_SteamDeck_R2_SoftPull, + k_EControllerActionOrigin_SteamDeck_R2, + k_EControllerActionOrigin_SteamDeck_LeftStick_Move, + k_EControllerActionOrigin_SteamDeck_L3, + k_EControllerActionOrigin_SteamDeck_LeftStick_DPadNorth, + k_EControllerActionOrigin_SteamDeck_LeftStick_DPadSouth, + k_EControllerActionOrigin_SteamDeck_LeftStick_DPadWest, + k_EControllerActionOrigin_SteamDeck_LeftStick_DPadEast, + k_EControllerActionOrigin_SteamDeck_LeftStick_Touch, + k_EControllerActionOrigin_SteamDeck_RightStick_Move, + k_EControllerActionOrigin_SteamDeck_R3, + k_EControllerActionOrigin_SteamDeck_RightStick_DPadNorth, + k_EControllerActionOrigin_SteamDeck_RightStick_DPadSouth, + k_EControllerActionOrigin_SteamDeck_RightStick_DPadWest, + k_EControllerActionOrigin_SteamDeck_RightStick_DPadEast, + k_EControllerActionOrigin_SteamDeck_RightStick_Touch, + k_EControllerActionOrigin_SteamDeck_L4, + k_EControllerActionOrigin_SteamDeck_R4, + k_EControllerActionOrigin_SteamDeck_L5, + k_EControllerActionOrigin_SteamDeck_R5, + k_EControllerActionOrigin_SteamDeck_DPad_Move, + k_EControllerActionOrigin_SteamDeck_DPad_North, + k_EControllerActionOrigin_SteamDeck_DPad_South, + k_EControllerActionOrigin_SteamDeck_DPad_West, + k_EControllerActionOrigin_SteamDeck_DPad_East, + k_EControllerActionOrigin_SteamDeck_Gyro_Move, + k_EControllerActionOrigin_SteamDeck_Gyro_Pitch, + k_EControllerActionOrigin_SteamDeck_Gyro_Yaw, + k_EControllerActionOrigin_SteamDeck_Gyro_Roll, + k_EControllerActionOrigin_SteamDeck_Reserved1, + k_EControllerActionOrigin_SteamDeck_Reserved2, + k_EControllerActionOrigin_SteamDeck_Reserved3, + k_EControllerActionOrigin_SteamDeck_Reserved4, + k_EControllerActionOrigin_SteamDeck_Reserved5, + k_EControllerActionOrigin_SteamDeck_Reserved6, + k_EControllerActionOrigin_SteamDeck_Reserved7, + k_EControllerActionOrigin_SteamDeck_Reserved8, + k_EControllerActionOrigin_SteamDeck_Reserved9, + k_EControllerActionOrigin_SteamDeck_Reserved10, + k_EControllerActionOrigin_SteamDeck_Reserved11, + k_EControllerActionOrigin_SteamDeck_Reserved12, + k_EControllerActionOrigin_SteamDeck_Reserved13, + k_EControllerActionOrigin_SteamDeck_Reserved14, + k_EControllerActionOrigin_SteamDeck_Reserved15, + k_EControllerActionOrigin_SteamDeck_Reserved16, + k_EControllerActionOrigin_SteamDeck_Reserved17, + k_EControllerActionOrigin_SteamDeck_Reserved18, + k_EControllerActionOrigin_SteamDeck_Reserved19, + k_EControllerActionOrigin_SteamDeck_Reserved20, + + k_EControllerActionOrigin_Switch_JoyConButton_N, // With a Horizontal JoyCon this will be Y or what would be Dpad Right when vertical + k_EControllerActionOrigin_Switch_JoyConButton_E, // X + k_EControllerActionOrigin_Switch_JoyConButton_S, // A + k_EControllerActionOrigin_Switch_JoyConButton_W, // B + + k_EControllerActionOrigin_PS5_LeftGrip, + k_EControllerActionOrigin_PS5_RightGrip, + k_EControllerActionOrigin_PS5_LeftFn, + k_EControllerActionOrigin_PS5_RightFn, + + 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_PS5Controller, // Added in SDK 151 + 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 +#define ControllerMotionDataV2_t InputMotionDataV2_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 available 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 - unlike EControllerActionOrigin which update with Steam and may return unrecognized values + // ESteamInputType will remain static and only return valid values from your SDK version + 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 "SteamController008" + +// Global interface accessor +inline ISteamController *SteamController(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamController *, SteamController, STEAMCONTROLLER_INTERFACE_VERSION ); + +#endif // ISTEAMCONTROLLER_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamDualSense.h b/Amalgam/src/SDK/Definitions/Steam/ISteamDualSense.h new file mode 100644 index 0000000..5acc857 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamDualSense.h @@ -0,0 +1,169 @@ +/* SIE CONFIDENTIAL + * $PSLibId$ + * Copyright (C) 2019 Sony Interactive Entertainment Inc. + * All Rights Reserved. + */ + + +#ifndef _SCE_PAD_TRIGGER_EFFECT_H +#define _SCE_PAD_TRIGGER_EFFECT_H + + +#define SCE_PAD_TRIGGER_EFFECT_TRIGGER_MASK_L2 0x01 +#define SCE_PAD_TRIGGER_EFFECT_TRIGGER_MASK_R2 0x02 + +#define SCE_PAD_TRIGGER_EFFECT_PARAM_INDEX_FOR_L2 0 +#define SCE_PAD_TRIGGER_EFFECT_PARAM_INDEX_FOR_R2 1 + +#define SCE_PAD_TRIGGER_EFFECT_TRIGGER_NUM 2 + +/* Definition of control point num */ +#define SCE_PAD_TRIGGER_EFFECT_CONTROL_POINT_NUM 10 + +typedef enum ScePadTriggerEffectMode{ + SCE_PAD_TRIGGER_EFFECT_MODE_OFF, + SCE_PAD_TRIGGER_EFFECT_MODE_FEEDBACK, + SCE_PAD_TRIGGER_EFFECT_MODE_WEAPON, + SCE_PAD_TRIGGER_EFFECT_MODE_VIBRATION, + SCE_PAD_TRIGGER_EFFECT_MODE_MULTIPLE_POSITION_FEEDBACK, + SCE_PAD_TRIGGER_EFFECT_MODE_SLOPE_FEEDBACK, + SCE_PAD_TRIGGER_EFFECT_MODE_MULTIPLE_POSITION_VIBRATION, +} ScePadTriggerEffectMode; + +/** + *E + * @brief parameter for setting the trigger effect to off mode. + * Off Mode: Stop trigger effect. + **/ +typedef struct ScePadTriggerEffectOffParam{ + uint8_t padding[48]; +} ScePadTriggerEffectOffParam; + +/** + *E + * @brief parameter for setting the trigger effect to Feedback mode. + * Feedback Mode: The motor arm pushes back trigger. + * Trigger obtains stiffness at specified position. + **/ +typedef struct ScePadTriggerEffectFeedbackParam{ + uint8_t position; /*E position where the strength of target trigger start changing(0~9). */ + uint8_t strength; /*E strength that the motor arm pushes back target trigger(0~8 (0: Same as Off mode)). */ + uint8_t padding[46]; +} ScePadTriggerEffectFeedbackParam; + +/** + *E + * @brief parameter for setting the trigger effect to Weapon mode. + * Weapon Mode: Emulate weapon like gun trigger. + **/ +typedef struct ScePadTriggerEffectWeaponParam{ + uint8_t startPosition; /*E position where the stiffness of trigger start changing(2~7). */ + uint8_t endPosition; /*E position where the stiffness of trigger finish changing(startPosition+1~8). */ + uint8_t strength; /*E strength of gun trigger(0~8 (0: Same as Off mode)). */ + uint8_t padding[45]; +} ScePadTriggerEffectWeaponParam; + +/** + *E + * @brief parameter for setting the trigger effect to Vibration mode. + * Vibration Mode: Vibrates motor arm around specified position. + **/ +typedef struct ScePadTriggerEffectVibrationParam{ + uint8_t position; /*E position where the motor arm start vibrating(0~9). */ + uint8_t amplitude; /*E vibration amplitude(0~8 (0: Same as Off mode)). */ + uint8_t frequency; /*E vibration frequency(0~255[Hz] (0: Same as Off mode)). */ + uint8_t padding[45]; +} ScePadTriggerEffectVibrationParam; + +/** + *E + * @brief parameter for setting the trigger effect to ScePadTriggerEffectMultiplePositionFeedbackParam mode. + * Multi Position Feedback Mode: The motor arm pushes back trigger. + * Trigger obtains specified stiffness at each control point. + **/ +typedef struct ScePadTriggerEffectMultiplePositionFeedbackParam{ + uint8_t strength[SCE_PAD_TRIGGER_EFFECT_CONTROL_POINT_NUM]; /*E strength that the motor arm pushes back target trigger at position(0~8 (0: Same as Off mode)). + * strength[0] means strength of motor arm at position0. + * strength[1] means strength of motor arm at position1. + * ... + * */ + uint8_t padding[38]; +} ScePadTriggerEffectMultiplePositionFeedbackParam; + +/** + *E + * @brief parameter for setting the trigger effect to Feedback3 mode. + * Slope Feedback Mode: The motor arm pushes back trigger between two spedified control points. + * Stiffness of the trigger is changing depending on the set place. + **/ +typedef struct ScePadTriggerEffectSlopeFeedbackParam{ + + uint8_t startPosition; /*E position where the strength of target trigger start changing(0~endPosition). */ + uint8_t endPosition; /*E position where the strength of target trigger finish changing(startPosition+1~9). */ + uint8_t startStrength; /*E strength when trigger's position is startPosition(1~8) */ + uint8_t endStrength; /*E strength when trigger's position is endPosition(1~8) */ + uint8_t padding[44]; +} ScePadTriggerEffectSlopeFeedbackParam; + +/** + *E + * @brief parameter for setting the trigger effect to Vibration2 mode. + * Multi Position Vibration Mode: Vibrates motor arm around specified control point. + * Trigger vibrates specified amplitude at each control point. + **/ +typedef struct ScePadTriggerEffectMultiplePositionVibrationParam{ + uint8_t frequency; /*E vibration frequency(0~255 (0: Same as Off mode)) */ + uint8_t amplitude[SCE_PAD_TRIGGER_EFFECT_CONTROL_POINT_NUM]; /*E vibration amplitude at position(0~8 (0: Same as Off mode)). + * amplitude[0] means amplitude of vibration at position0. + * amplitude[1] means amplitude of vibration at position1. + * ... + * */ + uint8_t padding[37]; +} ScePadTriggerEffectMultiplePositionVibrationParam; + +/** + *E + * @brief parameter for setting the trigger effect mode. + **/ +typedef union ScePadTriggerEffectCommandData{ + ScePadTriggerEffectOffParam offParam; + ScePadTriggerEffectFeedbackParam feedbackParam; + ScePadTriggerEffectWeaponParam weaponParam; + ScePadTriggerEffectVibrationParam vibrationParam; + ScePadTriggerEffectMultiplePositionFeedbackParam multiplePositionFeedbackParam; + ScePadTriggerEffectSlopeFeedbackParam slopeFeedbackParam; + ScePadTriggerEffectMultiplePositionVibrationParam multiplePositionVibrationParam; +} ScePadTriggerEffectCommandData; + +/** + *E + * @brief parameter for setting the trigger effect. + **/ +typedef struct ScePadTriggerEffectCommand{ + ScePadTriggerEffectMode mode; + uint8_t padding[4]; + ScePadTriggerEffectCommandData commandData; +} ScePadTriggerEffectCommand; + +/** + *E + * @brief parameter for the scePadSetTriggerEffect function. + **/ +typedef struct ScePadTriggerEffectParam{ + + uint8_t triggerMask; /*E Set trigger mask to activate trigger effect commands. + * SCE_PAD_TRIGGER_EFFECT_TRIGGER_MASK_L2 : 0x01 + * SCE_PAD_TRIGGER_EFFECT_TRIGGER_MASK_R2 : 0x02 + * */ + uint8_t padding[7]; + + ScePadTriggerEffectCommand command[SCE_PAD_TRIGGER_EFFECT_TRIGGER_NUM]; /*E command[SCE_PAD_TRIGGER_EFFECT_PARAM_INDEX_FOR_L2] is for L2 trigger setting + * and param[SCE_PAD_TRIGGER_EFFECT_PARAM_INDEX_FOR_R2] is for R2 trgger setting. + * */ +} ScePadTriggerEffectParam; + +#if defined(__cplusplus) && __cplusplus >= 201103L +static_assert( sizeof( ScePadTriggerEffectParam ) == 120, "ScePadTriggerEffectParam has incorrect size" ); +#endif + +#endif /* _SCE_PAD_TRIGGER_EFFECT_H */ diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamFriends.h b/Amalgam/src/SDK/Definitions/Steam/ISteamFriends.h new file mode 100644 index 0000000..a2b0100 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamFriends.h @@ -0,0 +1,752 @@ +//====== 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) +}; + +// 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: See GetProfileItemPropertyString and GetProfileItemPropertyUint +//----------------------------------------------------------------------------- +enum ECommunityProfileItemType +{ + k_ECommunityProfileItemType_AnimatedAvatar = 0, + k_ECommunityProfileItemType_AvatarFrame = 1, + k_ECommunityProfileItemType_ProfileModifier = 2, + k_ECommunityProfileItemType_ProfileBackground = 3, + k_ECommunityProfileItemType_MiniProfileBackground = 4, +}; +enum ECommunityProfileItemProperty +{ + k_ECommunityProfileItemProperty_ImageSmall = 0, // string + k_ECommunityProfileItemProperty_ImageLarge = 1, // string + k_ECommunityProfileItemProperty_InternalName = 2, // string + k_ECommunityProfileItemProperty_Title = 3, // string + k_ECommunityProfileItemProperty_Description = 4, // string + k_ECommunityProfileItemProperty_AppID = 5, // uint32 + k_ECommunityProfileItemProperty_TypeID = 6, // uint32 + k_ECommunityProfileItemProperty_Class = 7, // uint32 + k_ECommunityProfileItemProperty_MovieWebM = 8, // string + k_ECommunityProfileItemProperty_MovieMP4 = 9, // string + k_ECommunityProfileItemProperty_MovieWebMSmall = 10, // string + k_ECommunityProfileItemProperty_MovieMP4Small = 11, // string +}; + +//----------------------------------------------------------------------------- +// 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 + STEAM_CALL_RESULT( DownloadClanActivityCountsResult_t ) + 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 five 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 + // "steam_display" - Names a rich presence localization token that will be displayed in the viewing user's selected language + // in the Steam client UI. For more info: https://partner.steamgames.com/doc/api/ISteamFriends#richpresencelocalization + // "steam_player_group" - When set, indicates to the Steam client that the player is a member of a particular group. Players in the same group + // may be organized together in various places in the Steam UI. + // "steam_player_group_size" - When set, indicates the total number of players in the steam_player_group. The Steam client may use this number to + // display additional information about a group when all of the members are not part of a user's friends list. + // 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 your game so that it is passed on the command line instead. This is a deprecated path; ask us if you really need this.) + 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; + + // activates game overlay to open the remote play together invite dialog. Invitations will be sent for remote play together + virtual void ActivateGameOverlayRemotePlayTogetherInviteDialog( CSteamID steamIDLobby ) = 0; + + // Call this before calling ActivateGameOverlayToWebPage() to have the Steam Overlay Browser block navigations + // to your specified protocol (scheme) uris and instead dispatch a OverlayBrowserProtocolNavigation_t callback to your game. + // ActivateGameOverlayToWebPage() must have been called with k_EActivateGameOverlayToWebPageMode_Modal + virtual bool RegisterProtocolInOverlayBrowser( const char *pchProtocol ) = 0; + + // Activates the game overlay to open an invite dialog that will send the provided Rich Presence connect string to selected friends + virtual void ActivateGameOverlayInviteDialogConnectString( const char *pchConnectString ) = 0; + + // Steam Community items equipped by a user on their profile + // You can register for EquippedProfileItemsChanged_t to know when a friend has changed their equipped profile items + STEAM_CALL_RESULT( EquippedProfileItems_t ) + virtual SteamAPICall_t RequestEquippedProfileItems( CSteamID steamID ) = 0; + virtual bool BHasEquippedProfileItem( CSteamID steamID, ECommunityProfileItemType itemType ) = 0; + virtual const char *GetProfileItemPropertyString( CSteamID steamID, ECommunityProfileItemType itemType, ECommunityProfileItemProperty prop ) = 0; + virtual uint32 GetProfileItemPropertyUint( CSteamID steamID, ECommunityProfileItemType itemType, ECommunityProfileItemProperty prop ) = 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 + bool m_bUserInitiated; // true if the user asked for the overlay to be activated/deactivated + AppId_t m_nAppID; // the appID of the game (should always be the current game) +}; + + +//----------------------------------------------------------------------------- +// 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 }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Dispatched when an overlay browser instance is navigated to a protocol/scheme registered by RegisterProtocolInOverlayBrowser() +//----------------------------------------------------------------------------- +struct OverlayBrowserProtocolNavigation_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 49 }; + char rgchURI[ 1024 ]; +}; + +//----------------------------------------------------------------------------- +// Purpose: A user's equipped profile items have changed +//----------------------------------------------------------------------------- +struct EquippedProfileItemsChanged_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 50 }; + CSteamID m_steamID; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +struct EquippedProfileItems_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 51 }; + EResult m_eResult; + CSteamID m_steamID; + bool m_bHasAnimatedAvatar; + bool m_bHasAvatarFrame; + bool m_bHasProfileModifier; + bool m_bHasProfileBackground; + bool m_bHasMiniProfileBackground; +}; + +#pragma pack( pop ) + +#endif // ISTEAMFRIENDS_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamGameCoordinator.h b/Amalgam/src/SDK/Definitions/Steam/ISteamGameCoordinator.h new file mode 100644 index 0000000..44796dc --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/ISteamGameServer.h b/Amalgam/src/SDK/Definitions/Steam/ISteamGameServer.h new file mode 100644 index 0000000..689f17d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamGameServer.h @@ -0,0 +1,394 @@ +//====== 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" + +//----------------------------------------------------------------------------- +// 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 + STEAM_PRIVATE_API( 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_cbMaxGameServerMapName + 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 port to advertise. The default value is zero, meaning the + /// service is not used. If your server receives any info requests on the LAN, + /// this is the value that will be placed into the reply for such local queries. + /// + /// This is also the value that will be advertised by the master server. + /// The only exception is if your server is using a FakeIP. Then then the second + /// fake port number (index 1) assigned to your server will be listed on the master + /// server as the spectator port, if you set this value to any nonzero value. + /// + /// This function merely controls the values that are advertised -- it's up to you to + /// configure the server to actually listen on this port and handle any spectator traffic + 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 + /// + /// @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; + + /// Indicate whether you wish to be listed on the master server list + /// and/or respond to server browser / LAN discovery packets. + /// The server starts with this value set to false. You should set all + /// relevant server parameters before enabling advertisement on the server. + /// + /// (This function used to be named EnableHeartbeats, so if you are wondering + /// where that function went, it's right here. It does the same thing as before, + /// the old name was just confusing.) + virtual void SetAdvertiseServerActive( bool bActive ) = 0; + +// +// Player list management / authentication. +// + + // Retrieve ticket to be sent to the entity who wishes to authenticate you ( using BeginAuthSession API ). + // pcbTicket retrieves the length of the actual ticket. + // SteamNetworkingIdentity is an optional parameter to hold the public IP address of the entity you are connecting to + // if an IP address is passed Steam will only allow the ticket to be used by an entity with that IP address + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, const SteamNetworkingIdentity *pSnid ) = 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 SteamIPAddress_t GetPublicIP() = 0; + +// Server browser related query packet processing for shared socket mode. These are used +// when you pass STEAMGAMESERVER_QUERY_PORT_SHARED as the query port to SteamGameServer_Init. +// IP address and port are 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; + +// +// Server clan association +// + + // 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; + + + + + // 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) + // + // DEPRECATED! This function will be removed from the SDK in an upcoming version. + // Please migrate to BeginAuthSession and related functions. + virtual bool SendUserConnectAndAuthenticate_DEPRECATED( 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 EndAuthSession() + // 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. + // + // DEPRECATED! This function will be removed from the SDK in an upcoming version. + // Please migrate to BeginAuthSession and related functions. + virtual void SendUserDisconnect_DEPRECATED( 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; + +// Deprecated functions. These will be removed in a future version of the SDK. +// If you really need these, please contact us and help us understand what you are +// using them for. + + STEAM_PRIVATE_API( + virtual void SetMasterServerHeartbeatInterval_DEPRECATED( int iHeartbeatInterval ) = 0; + virtual void ForceMasterServerHeartbeat_DEPRECATED() = 0; + ) +}; + +#define STEAMGAMESERVER_INTERFACE_VERSION "SteamGameServer015" + +// Global accessor +inline ISteamGameServer *SteamGameServer(); +STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamGameServer *, SteamGameServer, STEAMGAMESERVER_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 + + +// 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/Amalgam/src/SDK/Definitions/Steam/ISteamGameServerStats.h b/Amalgam/src/SDK/Definitions/Steam/ISteamGameServerStats.h new file mode 100644 index 0000000..029512b --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamGameServerStats.h @@ -0,0 +1,114 @@ +//====== 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() + STEAM_FLAT_NAME( GetUserStatInt32 ) + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + + STEAM_FLAT_NAME( GetUserStatFloat ) + 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 + + STEAM_FLAT_NAME( SetUserStatInt32 ) + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, int32 nData ) = 0; + + STEAM_FLAT_NAME( SetUserStatFloat ) + 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/Amalgam/src/SDK/Definitions/Steam/ISteamHTMLSurface.h b/Amalgam/src/SDK/Definitions/Steam/ISteamHTMLSurface.h new file mode 100644 index 0000000..593134d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamHTMLSurface.h @@ -0,0 +1,479 @@ +//====== 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 + 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/Amalgam/src/SDK/Definitions/Steam/ISteamHTTP.h b/Amalgam/src/SDK/Definitions/Steam/ISteamHTTP.h new file mode 100644 index 0000000..cdaa310 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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_iSteamHTTPCallbacks + 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_iSteamHTTPCallbacks + 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_iSteamHTTPCallbacks + 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/Amalgam/src/SDK/Definitions/Steam/ISteamInput.h b/Amalgam/src/SDK/Definitions/Steam/ISteamInput.h new file mode 100644 index 0000000..c7be1a2 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamInput.h @@ -0,0 +1,1034 @@ +//====== 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 24 + +#define STEAM_INPUT_MAX_DIGITAL_ACTIONS 256 + +#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 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_LeftGrip_Lower, + k_EInputActionOrigin_XBoxOne_LeftGrip_Upper, + k_EInputActionOrigin_XBoxOne_RightGrip_Lower, + k_EInputActionOrigin_XBoxOne_RightGrip_Upper, + k_EInputActionOrigin_XBoxOne_Share, // Xbox Series X controllers only + 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_JoyConButton_N, // With a Horizontal JoyCon this will be Y or what would be Dpad Right when vertical + k_EInputActionOrigin_Switch_JoyConButton_E, // X + k_EInputActionOrigin_Switch_JoyConButton_S, // A + k_EInputActionOrigin_Switch_JoyConButton_W, // B + k_EInputActionOrigin_Switch_Reserved15, + k_EInputActionOrigin_Switch_Reserved16, + k_EInputActionOrigin_Switch_Reserved17, + k_EInputActionOrigin_Switch_Reserved18, + k_EInputActionOrigin_Switch_Reserved19, + k_EInputActionOrigin_Switch_Reserved20, + + // Added in SDK 1.51 + k_EInputActionOrigin_PS5_X, + k_EInputActionOrigin_PS5_Circle, + k_EInputActionOrigin_PS5_Triangle, + k_EInputActionOrigin_PS5_Square, + k_EInputActionOrigin_PS5_LeftBumper, + k_EInputActionOrigin_PS5_RightBumper, + k_EInputActionOrigin_PS5_Option, //Start + k_EInputActionOrigin_PS5_Create, //Back + k_EInputActionOrigin_PS5_Mute, + k_EInputActionOrigin_PS5_LeftPad_Touch, + k_EInputActionOrigin_PS5_LeftPad_Swipe, + k_EInputActionOrigin_PS5_LeftPad_Click, + k_EInputActionOrigin_PS5_LeftPad_DPadNorth, + k_EInputActionOrigin_PS5_LeftPad_DPadSouth, + k_EInputActionOrigin_PS5_LeftPad_DPadWest, + k_EInputActionOrigin_PS5_LeftPad_DPadEast, + k_EInputActionOrigin_PS5_RightPad_Touch, + k_EInputActionOrigin_PS5_RightPad_Swipe, + k_EInputActionOrigin_PS5_RightPad_Click, + k_EInputActionOrigin_PS5_RightPad_DPadNorth, + k_EInputActionOrigin_PS5_RightPad_DPadSouth, + k_EInputActionOrigin_PS5_RightPad_DPadWest, + k_EInputActionOrigin_PS5_RightPad_DPadEast, + k_EInputActionOrigin_PS5_CenterPad_Touch, + k_EInputActionOrigin_PS5_CenterPad_Swipe, + k_EInputActionOrigin_PS5_CenterPad_Click, + k_EInputActionOrigin_PS5_CenterPad_DPadNorth, + k_EInputActionOrigin_PS5_CenterPad_DPadSouth, + k_EInputActionOrigin_PS5_CenterPad_DPadWest, + k_EInputActionOrigin_PS5_CenterPad_DPadEast, + k_EInputActionOrigin_PS5_LeftTrigger_Pull, + k_EInputActionOrigin_PS5_LeftTrigger_Click, + k_EInputActionOrigin_PS5_RightTrigger_Pull, + k_EInputActionOrigin_PS5_RightTrigger_Click, + k_EInputActionOrigin_PS5_LeftStick_Move, + k_EInputActionOrigin_PS5_LeftStick_Click, + k_EInputActionOrigin_PS5_LeftStick_DPadNorth, + k_EInputActionOrigin_PS5_LeftStick_DPadSouth, + k_EInputActionOrigin_PS5_LeftStick_DPadWest, + k_EInputActionOrigin_PS5_LeftStick_DPadEast, + k_EInputActionOrigin_PS5_RightStick_Move, + k_EInputActionOrigin_PS5_RightStick_Click, + k_EInputActionOrigin_PS5_RightStick_DPadNorth, + k_EInputActionOrigin_PS5_RightStick_DPadSouth, + k_EInputActionOrigin_PS5_RightStick_DPadWest, + k_EInputActionOrigin_PS5_RightStick_DPadEast, + k_EInputActionOrigin_PS5_DPad_North, + k_EInputActionOrigin_PS5_DPad_South, + k_EInputActionOrigin_PS5_DPad_West, + k_EInputActionOrigin_PS5_DPad_East, + k_EInputActionOrigin_PS5_Gyro_Move, + k_EInputActionOrigin_PS5_Gyro_Pitch, + k_EInputActionOrigin_PS5_Gyro_Yaw, + k_EInputActionOrigin_PS5_Gyro_Roll, + k_EInputActionOrigin_PS5_DPad_Move, + k_EInputActionOrigin_PS5_LeftGrip, + k_EInputActionOrigin_PS5_RightGrip, + k_EInputActionOrigin_PS5_LeftFn, + k_EInputActionOrigin_PS5_RightFn, + k_EInputActionOrigin_PS5_Reserved5, + k_EInputActionOrigin_PS5_Reserved6, + k_EInputActionOrigin_PS5_Reserved7, + k_EInputActionOrigin_PS5_Reserved8, + k_EInputActionOrigin_PS5_Reserved9, + k_EInputActionOrigin_PS5_Reserved10, + k_EInputActionOrigin_PS5_Reserved11, + k_EInputActionOrigin_PS5_Reserved12, + k_EInputActionOrigin_PS5_Reserved13, + k_EInputActionOrigin_PS5_Reserved14, + k_EInputActionOrigin_PS5_Reserved15, + k_EInputActionOrigin_PS5_Reserved16, + k_EInputActionOrigin_PS5_Reserved17, + k_EInputActionOrigin_PS5_Reserved18, + k_EInputActionOrigin_PS5_Reserved19, + k_EInputActionOrigin_PS5_Reserved20, + + // Added in SDK 1.53 + k_EInputActionOrigin_SteamDeck_A, + k_EInputActionOrigin_SteamDeck_B, + k_EInputActionOrigin_SteamDeck_X, + k_EInputActionOrigin_SteamDeck_Y, + k_EInputActionOrigin_SteamDeck_L1, + k_EInputActionOrigin_SteamDeck_R1, + k_EInputActionOrigin_SteamDeck_Menu, + k_EInputActionOrigin_SteamDeck_View, + k_EInputActionOrigin_SteamDeck_LeftPad_Touch, + k_EInputActionOrigin_SteamDeck_LeftPad_Swipe, + k_EInputActionOrigin_SteamDeck_LeftPad_Click, + k_EInputActionOrigin_SteamDeck_LeftPad_DPadNorth, + k_EInputActionOrigin_SteamDeck_LeftPad_DPadSouth, + k_EInputActionOrigin_SteamDeck_LeftPad_DPadWest, + k_EInputActionOrigin_SteamDeck_LeftPad_DPadEast, + k_EInputActionOrigin_SteamDeck_RightPad_Touch, + k_EInputActionOrigin_SteamDeck_RightPad_Swipe, + k_EInputActionOrigin_SteamDeck_RightPad_Click, + k_EInputActionOrigin_SteamDeck_RightPad_DPadNorth, + k_EInputActionOrigin_SteamDeck_RightPad_DPadSouth, + k_EInputActionOrigin_SteamDeck_RightPad_DPadWest, + k_EInputActionOrigin_SteamDeck_RightPad_DPadEast, + k_EInputActionOrigin_SteamDeck_L2_SoftPull, + k_EInputActionOrigin_SteamDeck_L2, + k_EInputActionOrigin_SteamDeck_R2_SoftPull, + k_EInputActionOrigin_SteamDeck_R2, + k_EInputActionOrigin_SteamDeck_LeftStick_Move, + k_EInputActionOrigin_SteamDeck_L3, + k_EInputActionOrigin_SteamDeck_LeftStick_DPadNorth, + k_EInputActionOrigin_SteamDeck_LeftStick_DPadSouth, + k_EInputActionOrigin_SteamDeck_LeftStick_DPadWest, + k_EInputActionOrigin_SteamDeck_LeftStick_DPadEast, + k_EInputActionOrigin_SteamDeck_LeftStick_Touch, + k_EInputActionOrigin_SteamDeck_RightStick_Move, + k_EInputActionOrigin_SteamDeck_R3, + k_EInputActionOrigin_SteamDeck_RightStick_DPadNorth, + k_EInputActionOrigin_SteamDeck_RightStick_DPadSouth, + k_EInputActionOrigin_SteamDeck_RightStick_DPadWest, + k_EInputActionOrigin_SteamDeck_RightStick_DPadEast, + k_EInputActionOrigin_SteamDeck_RightStick_Touch, + k_EInputActionOrigin_SteamDeck_L4, + k_EInputActionOrigin_SteamDeck_R4, + k_EInputActionOrigin_SteamDeck_L5, + k_EInputActionOrigin_SteamDeck_R5, + k_EInputActionOrigin_SteamDeck_DPad_Move, + k_EInputActionOrigin_SteamDeck_DPad_North, + k_EInputActionOrigin_SteamDeck_DPad_South, + k_EInputActionOrigin_SteamDeck_DPad_West, + k_EInputActionOrigin_SteamDeck_DPad_East, + k_EInputActionOrigin_SteamDeck_Gyro_Move, + k_EInputActionOrigin_SteamDeck_Gyro_Pitch, + k_EInputActionOrigin_SteamDeck_Gyro_Yaw, + k_EInputActionOrigin_SteamDeck_Gyro_Roll, + k_EInputActionOrigin_SteamDeck_Reserved1, + k_EInputActionOrigin_SteamDeck_Reserved2, + k_EInputActionOrigin_SteamDeck_Reserved3, + k_EInputActionOrigin_SteamDeck_Reserved4, + k_EInputActionOrigin_SteamDeck_Reserved5, + k_EInputActionOrigin_SteamDeck_Reserved6, + k_EInputActionOrigin_SteamDeck_Reserved7, + k_EInputActionOrigin_SteamDeck_Reserved8, + k_EInputActionOrigin_SteamDeck_Reserved9, + k_EInputActionOrigin_SteamDeck_Reserved10, + k_EInputActionOrigin_SteamDeck_Reserved11, + k_EInputActionOrigin_SteamDeck_Reserved12, + k_EInputActionOrigin_SteamDeck_Reserved13, + k_EInputActionOrigin_SteamDeck_Reserved14, + k_EInputActionOrigin_SteamDeck_Reserved15, + k_EInputActionOrigin_SteamDeck_Reserved16, + k_EInputActionOrigin_SteamDeck_Reserved17, + k_EInputActionOrigin_SteamDeck_Reserved18, + k_EInputActionOrigin_SteamDeck_Reserved19, + k_EInputActionOrigin_SteamDeck_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 EControllerHapticLocation +{ + k_EControllerHapticLocation_Left = ( 1 << k_ESteamControllerPad_Left ), + k_EControllerHapticLocation_Right = ( 1 << k_ESteamControllerPad_Right ), + k_EControllerHapticLocation_Both = ( 1 << k_ESteamControllerPad_Left | 1 << k_ESteamControllerPad_Right ), +}; + +enum EControllerHapticType +{ + k_EControllerHapticType_Off, + k_EControllerHapticType_Tick, + k_EControllerHapticType_Click, +}; + +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_PS5Controller, // Added in SDK 151 + k_ESteamInputType_SteamDeckController, // Added in SDK 153 + k_ESteamInputType_Count, + k_ESteamInputType_MaximumPossibleValue = 255, +}; + +// Individual values are used by the GetSessionInputConfigurationSettings bitmask +enum ESteamInputConfigurationEnableType +{ + k_ESteamInputConfigurationEnableType_None = 0x0000, + k_ESteamInputConfigurationEnableType_Playstation = 0x0001, + k_ESteamInputConfigurationEnableType_Xbox = 0x0002, + k_ESteamInputConfigurationEnableType_Generic = 0x0004, + k_ESteamInputConfigurationEnableType_Switch = 0x0008, +}; + +// 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 +}; + +// These values are passed into GetGlyphPNGForActionOrigin +enum ESteamInputGlyphSize +{ + k_ESteamInputGlyphSize_Small, // 32x32 pixels + k_ESteamInputGlyphSize_Medium, // 128x128 pixels + k_ESteamInputGlyphSize_Large, // 256x256 pixels + k_ESteamInputGlyphSize_Count, +}; + +enum ESteamInputGlyphStyle +{ + // Base-styles - cannot mix + ESteamInputGlyphStyle_Knockout = 0x0, // Face buttons will have colored labels/outlines on a knocked out background + // Rest of inputs will have white detail/borders on a knocked out background + ESteamInputGlyphStyle_Light = 0x1, // Black detail/borders on a white background + ESteamInputGlyphStyle_Dark = 0x2, // White detail/borders on a black background + + // Modifiers + // Default ABXY/PS equivalent glyphs have a solid fill w/ color matching the physical buttons on the device + ESteamInputGlyphStyle_NeutralColorABXY = 0x10, // ABXY Buttons will match the base style color instead of their normal associated color + ESteamInputGlyphStyle_SolidABXY = 0x20, // ABXY Buttons will have a solid fill +}; + +enum ESteamInputActionEventType +{ + ESteamInputActionEventType_DigitalAction, + ESteamInputActionEventType_AnalogAction, +}; + +// 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 toward average + float rotQuatX; + float rotQuatY; + float rotQuatZ; + float rotQuatW; + + // Positional acceleration + float posAccelX; + float posAccelY; + float posAccelZ; + + // Angular velocity + float rotVelX; + float rotVelY; + float rotVelZ; +}; + + +struct InputMotionDataV2_t +{ + // + // Gyro post processing: + // + + // Drift Corrected Quaternion is calculated after steam input controller calibration values have been applied. + // Rawest _useful_ version of a quaternion. + // Most camera implementations should use this by comparing last rotation against current rotation, and applying the difference to the in game camera (plus your own sensitivity tweaks) + // It is worth viewing + float driftCorrectedQuatX; + float driftCorrectedQuatY; + float driftCorrectedQuatZ; + float driftCorrectedQuatW; + + // Sensor fusion corrects using accelerometer, and "average forward over time" for "forward". + // This can "ouija" your aim, so it's not so appropriate for camera controls (sensor fusion was originally made for racing game steering ) + // Same result as from old InputMotionData_t::rotQuatX/Y/Z/W + float sensorFusionQuatX; + float sensorFusionQuatY; + float sensorFusionQuatZ; + float sensorFusionQuatW; + + // Deferred Sensor fusion quaternion with deferred correction + // Reduces perception of "ouija" effect by only applying correction when the controller is below "low noise" thresholds, + // while the controller rotates fast - never when the user is attempting precision aim. + float deferredSensorFusionQuatX; + float deferredSensorFusionQuatY; + float deferredSensorFusionQuatZ; + float deferredSensorFusionQuatW; + + // Same as accel but values are calibrated such that 1 unit = 1G. + // X = Right + // Y = Forward out through the joystick USB port. + // Z = Up through the joystick axis. + float gravityX; + float gravityY; + float gravityZ; + + // + // Same as rotVel values in GetMotionData but values are calibrated to degrees per second. + // Local Space (controller relative) + // X = Pitch = left to right axis + // Y = Roll = axis through charging port + // Z = Yaw = axis through sticks + float degreesPerSecondX; + float degreesPerSecondY; + float degreesPerSecondZ; + +}; + +//----------------------------------------------------------------------------- +// Purpose: when callbacks are enabled this fires each time a controller action +// state changes +//----------------------------------------------------------------------------- +struct SteamInputActionEvent_t +{ + InputHandle_t controllerHandle; + ESteamInputActionEventType eEventType; + struct AnalogAction_t { + InputAnalogActionHandle_t actionHandle; + InputAnalogActionData_t analogActionData; + }; + struct DigitalAction_t { + InputDigitalActionHandle_t actionHandle; + InputDigitalActionData_t digitalActionData; + }; + union { + AnalogAction_t analogAction; + DigitalAction_t digitalAction; + }; +}; + +//----------------------------------------------------------------------------- +// Forward declaration for ScePadTriggerEffectParam, defined in ISteamDualSense.h +//----------------------------------------------------------------------------- +struct ScePadTriggerEffectParam; + +#pragma pack( pop ) + +typedef void ( *SteamInputActionEventCallbackPointer )( SteamInputActionEvent_t * ); + +//----------------------------------------------------------------------------- +// Purpose: Steam Input API +//----------------------------------------------------------------------------- +class ISteamInput +{ +public: + + // Init and Shutdown must be called when starting/ending use of this interface. + // if bExplicitlyCallRunFrame is called then you will need to manually call RunFrame + // each frame, otherwise Steam Input will updated when SteamAPI_RunCallbacks() is called + virtual bool Init( bool bExplicitlyCallRunFrame ) = 0; + virtual bool Shutdown() = 0; + + // Set the absolute path to the Input Action Manifest file containing the in-game actions + // and file paths to the official configurations. Used in games that bundle Steam Input + // configurations inside of the game depot instead of using the Steam Workshop + virtual bool SetInputActionManifestFilePath( const char *pchInputActionManifestAbsolutePath ) = 0; + + // Synchronize API state with the latest Steam Input action data available. This + // is performed automatically by SteamAPI_RunCallbacks, but for the absolute lowest + // possible latency, you call this directly before reading controller state. + // Note: This must be called from somewhere before GetConnectedControllers will + // return any handles + virtual void RunFrame( bool bReservedValue = true ) = 0; + + // Waits on an IPC event from Steam sent when there is new data to be fetched from + // the data drop. Returns true when data was recievied before the timeout expires. + // Useful for games with a dedicated input thread + virtual bool BWaitForData( bool bWaitForever, uint32 unTimeout ) = 0; + + // Returns true if new data has been received since the last time action data was accessed + // via GetDigitalActionData or GetAnalogActionData. The game will still need to call + // SteamInput()->RunFrame() or SteamAPI_RunCallbacks() before this to update the data stream + virtual bool BNewDataAvailable() = 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; + + //----------------------------------------------------------------------------- + // CALLBACKS + //----------------------------------------------------------------------------- + + // Controller configuration loaded - these callbacks will always fire if you have + // a handler. Note: this is called within either SteamInput()->RunFrame or by SteamAPI_RunCallbacks + STEAM_CALL_BACK( SteamInputConfigurationLoaded_t ) + + // Enable SteamInputDeviceConnected_t and SteamInputDeviceDisconnected_t callbacks. + // Each controller that is already connected will generate a device connected + // callback when you enable them + virtual void EnableDeviceCallbacks() = 0; + + // Controller Connected - provides info about a single newly connected controller + // Note: this is called within either SteamInput()->RunFrame or by SteamAPI_RunCallbacks + STEAM_CALL_BACK( SteamInputDeviceConnected_t ) + + // Controller Disconnected - provides info about a single disconnected controller + // Note: this is called within either SteamInput()->RunFrame or by SteamAPI_RunCallbacks + STEAM_CALL_BACK( SteamInputDeviceDisconnected_t ) + + // Controllers using Gamepad emulation (XInput, DirectInput, etc) will be seated in the order that + // input is sent by the device. This callback will fire on first input for each device and when the + // a user has manually changed the order via the Steam overlay. This also has the device type info + // so that you can change out glyph sets without making additional API calls + STEAM_CALL_BACK( SteamInputGamepadSlotChange_t ) + + // Enable SteamInputActionEvent_t callbacks. Directly calls your callback function + // for lower latency than standard Steam callbacks. Supports one callback at a time. + // Note: this is called within either SteamInput()->RunFrame or by SteamAPI_RunCallbacks + virtual void EnableActionEventCallbacks( SteamInputActionEventCallbackPointer pCallback ) = 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 InputActionSetHandle_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; + + // Returns a localized string (from Steam's language setting) for the user-facing action name corresponding to the specified handle + virtual const char *GetStringForDigitalActionName( InputDigitalActionHandle_t eActionHandle ) = 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 a PNG file for the provided origin's glyph. + virtual const char *GetGlyphPNGForActionOrigin( EInputActionOrigin eOrigin, ESteamInputGlyphSize eSize, uint32 unFlags ) = 0; + + // Get a local path to a SVG file for the provided origin's glyph. + virtual const char *GetGlyphSVGForActionOrigin( EInputActionOrigin eOrigin, uint32 unFlags ) = 0; + + // Get a local path to an older, Big Picture Mode-style PNG file for a particular origin + virtual const char *GetGlyphForActionOrigin_Legacy( EInputActionOrigin eOrigin ) = 0; + + // Returns a localized string (from Steam's language setting) for the specified origin. + virtual const char *GetStringForActionOrigin( EInputActionOrigin eOrigin ) = 0; + + // Returns a localized string (from Steam's language setting) for the user-facing action name corresponding to the specified handle + virtual const char *GetStringForAnalogActionName( InputAnalogActionHandle_t eActionHandle ) = 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; + + // Trigger a vibration event on supported controllers including Xbox trigger impulse rumble - Steam will translate these commands into haptic pulses for Steam Controllers + virtual void TriggerVibrationExtended( InputHandle_t inputHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed, unsigned short usLeftTriggerSpeed, unsigned short usRightTriggerSpeed ) = 0; + + // Send a haptic pulse, works on Steam Deck and Steam Controller devices + virtual void TriggerSimpleHapticEvent( InputHandle_t inputHandle, EControllerHapticLocation eHapticLocation, uint8 nIntensity, char nGainDB, uint8 nOtherIntensity, char nOtherGainDB ) = 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 Legacy_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 Legacy_TriggerRepeatedHapticPulse( InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ) = 0; + + //----------------------------------------------------------------------------- + // Utility functions available 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 - unlike EInputActionOrigin which update with Steam and may return unrecognized values + // ESteamInputType will remain static and only return valid values from your SDK version + 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; + + // Get a bitmask of the Steam Input Configuration types opted in for the current session. Returns ESteamInputConfigurationEnableType values. + // Note: user can override the settings from the Steamworks Partner site so the returned values may not exactly match your default configuration + virtual uint16 GetSessionInputConfigurationSettings() = 0; + + // Set the trigger effect for a DualSense controller + virtual void SetDualSenseTriggerEffect( InputHandle_t inputHandle, const ScePadTriggerEffectParam *pParam ) = 0; +}; + +#define STEAMINPUT_INTERFACE_VERSION "SteamInput006" + +// Global interface accessor +inline ISteamInput *SteamInput(); +STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamInput *, SteamInput, STEAMINPUT_INTERFACE_VERSION ); + +#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 new controller has been connected, will fire once +// per controller if multiple new controllers connect in the same frame +//----------------------------------------------------------------------------- +struct SteamInputDeviceConnected_t +{ + enum { k_iCallback = k_iSteamControllerCallbacks + 1 }; + InputHandle_t m_ulConnectedDeviceHandle; // Handle for device +}; + +//----------------------------------------------------------------------------- +// Purpose: called when a new controller has been connected, will fire once +// per controller if multiple new controllers connect in the same frame +//----------------------------------------------------------------------------- +struct SteamInputDeviceDisconnected_t +{ + enum { k_iCallback = k_iSteamControllerCallbacks + 2 }; + InputHandle_t m_ulDisconnectedDeviceHandle; // Handle for device +}; + +//----------------------------------------------------------------------------- +// Purpose: called when a controller configuration has been loaded, will fire once +// per controller per focus change for Steam Input enabled controllers +//----------------------------------------------------------------------------- +struct SteamInputConfigurationLoaded_t +{ + enum { k_iCallback = k_iSteamControllerCallbacks + 3 }; + AppId_t m_unAppID; + InputHandle_t m_ulDeviceHandle; // Handle for device + CSteamID m_ulMappingCreator; // May differ from local user when using + // an unmodified community or official config + uint32 m_unMajorRevision; // Binding revision from In-game Action File. + // Same value as queried by GetDeviceBindingRevision + uint32 m_unMinorRevision; + bool m_bUsesSteamInputAPI; // Does the configuration contain any Analog/Digital actions? + bool m_bUsesGamepadAPI; // Does the configuration contain any Xinput bindings? +}; + +//----------------------------------------------------------------------------- +// Purpose: called when controller gamepad slots change - on Linux/macOS these +// slots are shared for all running apps. +//----------------------------------------------------------------------------- +struct SteamInputGamepadSlotChange_t +{ + enum { k_iCallback = k_iSteamControllerCallbacks + 4 }; + AppId_t m_unAppID; + InputHandle_t m_ulDeviceHandle; // Handle for device + ESteamInputType m_eDeviceType; // Type of device + int m_nOldGamepadSlot; // Previous GamepadSlot - can be -1 controller doesn't uses gamepad bindings + int m_nNewGamepadSlot; // New Gamepad Slot - can be -1 controller doesn't uses gamepad bindings +}; + +#pragma pack( pop ) + +#endif // ISTEAMINPUT_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamInventory.h b/Amalgam/src/SDK/Definitions/Steam/ISteamInventory.h new file mode 100644 index 0000000..f40ef71 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamInventory.h @@ -0,0 +1,435 @@ +//====== 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 + 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. + 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. + 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. + virtual bool CheckResultSteamID( SteamInventoryResult_t resultHandle, CSteamID steamIDExpected ) = 0; + + // 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. + 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. + 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. + 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. + 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. + 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. + 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. + 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 + + STEAM_FLAT_NAME( SetPropertyString ) + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, const char *pchPropertyValue ) = 0; + + STEAM_FLAT_NAME( SetPropertyBool ) + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, bool bValue ) = 0; + + STEAM_FLAT_NAME( SetPropertyInt64 ) + virtual bool SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, int64 nValue ) = 0; + + STEAM_FLAT_NAME( SetPropertyFloat ) + 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; + + virtual bool InspectItem( SteamInventoryResult_t *pResultHandle, const char *pchItemToken ) = 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_iSteamInventoryCallbacks + 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_iSteamInventoryCallbacks + 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_iSteamInventoryCallbacks + 2 }; +}; + +// Returned +struct SteamInventoryEligiblePromoItemDefIDs_t +{ + enum { k_iCallback = k_iSteamInventoryCallbacks + 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_iSteamInventoryCallbacks + 4 }; + EResult m_result; + uint64 m_ulOrderID; + uint64 m_ulTransID; +}; + + +// Triggered from RequestPrices +struct SteamInventoryRequestPricesResult_t +{ + enum { k_iCallback = k_iSteamInventoryCallbacks + 5 }; + EResult m_result; + char m_rgchCurrency[4]; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMCONTROLLER_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamMatchmaking.h b/Amalgam/src/SDK/Definitions/Steam/ISteamMatchmaking.h new file mode 100644 index 0000000..0b6bc86 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamMatchmaking.h @@ -0,0 +1,1087 @@ +//====== 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 +}; +#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/Amalgam/src/SDK/Definitions/Steam/ISteamMusic.h b/Amalgam/src/SDK/Definitions/Steam/ISteamMusic.h new file mode 100644 index 0000000..e777166 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/ISteamMusicRemote.h b/Amalgam/src/SDK/Definitions/Steam/ISteamMusicRemote.h new file mode 100644 index 0000000..03395c6 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/ISteamNetworking.h b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworking.h new file mode 100644 index 0000000..6255f57 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworking.h @@ -0,0 +1,343 @@ +//====== 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_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running + 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 + + // The following error codes were removed and will never be sent. + // For privacy reasons, there is no reply if the user is offline or playing another game. + k_EP2PSessionErrorNotRunningApp_DELETED = 1, + k_EP2PSessionErrorDestinationNotLoggedIn_DELETED = 3, + + 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 +// +// NOTE: This interface is deprecated and may be removed in a future release of +/// the Steamworks SDK. Please see ISteamNetworkingSockets and +/// ISteamNetworkingMessages +//----------------------------------------------------------------------------- +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 + // + // These APIs are deprecated, and may be removed in a future version of the Steamworks + // SDK. See ISteamNetworkingMessages. + + // 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 + // + // NOTE: This function is deprecated and may be removed in a future version of the SDK. For + // security purposes, we may decide to relay the traffic to certain peers, even if you pass false + // to this function, to prevent revealing the client's IP address top another peer. + 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. + // + // These APIs are deprecated, and may be removed in a future version of the Steamworks + // SDK. See ISteamNetworkingSockets. + // + //////////////////////////////////////////////////////////////////////////////////////////// + + + // 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, SteamIPAddress_t 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( SteamIPAddress_t 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, SteamIPAddress_t *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, SteamIPAddress_t *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 "SteamNetworking006" + +// 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/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingMessages.h b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingMessages.h new file mode 100644 index 0000000..c1c4756 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingMessages.h @@ -0,0 +1,198 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== + +#ifndef ISTEAMNETWORKINGMESSAGES +#define ISTEAMNETWORKINGMESSAGES +#pragma once + +#include "SteamNetworkingTypes.h" +#include "Steam_API_Common.h" + +//----------------------------------------------------------------------------- +/// The non-connection-oriented interface to send and receive messages +/// (whether they be "clients" or "servers"). +/// +/// ISteamNetworkingSockets is connection-oriented (like TCP), meaning you +/// need to listen and connect, and then you send messages using a connection +/// handle. ISteamNetworkingMessages is more like UDP, in that you can just send +/// messages to arbitrary peers at any time. The underlying connections are +/// established implicitly. +/// +/// Under the hood ISteamNetworkingMessages works on top of the ISteamNetworkingSockets +/// code, so you get the same routing and messaging efficiency. The difference is +/// mainly in your responsibility to explicitly establish a connection and +/// the type of feedback you get about the state of the connection. Both +/// interfaces can do "P2P" communications, and both support both unreliable +/// and reliable messages, fragmentation and reassembly. +/// +/// The primary purpose of this interface is to be "like UDP", so that UDP-based code +/// can be ported easily to take advantage of relayed connections. If you find +/// yourself needing more low level information or control, or to be able to better +/// handle failure, then you probably need to use ISteamNetworkingSockets directly. +/// Also, note that if your main goal is to obtain a connection between two peers +/// without concerning yourself with assigning roles of "client" and "server", +/// you may find the symmetric connection mode of ISteamNetworkingSockets useful. +/// (See k_ESteamNetworkingConfig_SymmetricConnect.) +/// +class ISteamNetworkingMessages +{ +public: + /// Sends a message to the specified host. If we don't already have a session with that user, + /// a session is implicitly created. There might be some handshaking that needs to happen + /// before we can actually begin sending message data. If this handshaking fails and we can't + /// get through, an error will be posted via the callback SteamNetworkingMessagesSessionFailed_t. + /// There is no notification when the operation succeeds. (You should have the peer send a reply + /// for this purpose.) + /// + /// Sending a message to a host will also implicitly accept any incoming connection from that host. + /// + /// nSendFlags is a bitmask of k_nSteamNetworkingSend_xxx options + /// + /// nRemoteChannel is a routing number you can use to help route message to different systems. + /// You'll have to call ReceiveMessagesOnChannel() 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 + /// connection, saving on resources. If you don't need this feature, use 0. + /// Otherwise, small integers are the most efficient. + /// + /// It is guaranteed that reliable messages to the same host on the same channel + /// will be be received by the remote host (if they are received at all) exactly once, + /// and in the same order that they were sent. + /// + /// NO other order guarantees exist! In particular, unreliable messages may be dropped, + /// received out of order with respect to each other and with respect to reliable data, + /// or may be received multiple times. Messages on different channels are *not* guaranteed + /// to be received in the order they were sent. + /// + /// A note for those familiar with TCP/IP ports, or converting an existing codebase that + /// opened multiple sockets: You might notice that there is only one channel, and with + /// TCP/IP each endpoint has a port number. You can think of the channel number as the + /// *destination* port. If you need each message to also include a "source port" (so the + /// recipient can route the reply), then just put that in your message. That is essentially + /// how UDP works! + /// + /// Returns: + /// - k_EREsultOK on success. + /// - k_EResultNoConnection, if the session has failed or was closed by the peer and + /// k_nSteamNetworkingSend_AutoRestartBrokenSession was not specified. (You can + /// use GetSessionConnectionInfo to get the details.) In order to acknowledge the + /// broken session and start a new one, you must call CloseSessionWithUser, or you may + /// repeat the call with k_nSteamNetworkingSend_AutoRestartBrokenSession. See + /// k_nSteamNetworkingSend_AutoRestartBrokenSession for more details. + /// - See ISteamNetworkingSockets::SendMessageToConnection for more possible return values + virtual EResult SendMessageToUser( const SteamNetworkingIdentity &identityRemote, const void *pubData, uint32 cubData, int nSendFlags, int nRemoteChannel ) = 0; + + /// Reads the next message that has been sent from another user via SendMessageToUser() on the given channel. + /// Returns number of messages returned into your list. (0 if no message are available on that channel.) + /// + /// When you're done with the message object(s), make sure and call SteamNetworkingMessage_t::Release()! + virtual int ReceiveMessagesOnChannel( int nLocalChannel, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + /// Call this in response to a SteamNetworkingMessagesSessionRequest_t callback. + /// SteamNetworkingMessagesSessionRequest_t are posted when a user tries to send you a message, + /// and you haven't tried to talk to them first. If you don't want to talk to them, just ignore + /// the request. If the user continues to send you messages, SteamNetworkingMessagesSessionRequest_t + /// callbacks will continue to be posted periodically. + /// + /// Returns false if there is no session with the user pending or otherwise. If there is an + /// existing active session, this function will return true, even if it is not pending. + /// + /// Calling SendMessageToUser() will implicitly accepts any pending session request to that user. + virtual bool AcceptSessionWithUser( const SteamNetworkingIdentity &identityRemote ) = 0; + + /// Call this when you're done talking to a user to immediately free up resources under-the-hood. + /// If the remote user tries to send data to you again, another SteamNetworkingMessagesSessionRequest_t + /// callback will be posted. + /// + /// Note that sessions that go unused for a few minutes are automatically timed out. + virtual bool CloseSessionWithUser( const SteamNetworkingIdentity &identityRemote ) = 0; + + /// Call this when you're done talking to a user on a specific channel. Once all + /// open channels to a user have been closed, the open session to the user will be + /// closed, and any new data from this user will trigger a + /// SteamSteamNetworkingMessagesSessionRequest_t callback + virtual bool CloseChannelWithUser( const SteamNetworkingIdentity &identityRemote, int nLocalChannel ) = 0; + + /// Returns information about the latest state of a connection, if any, with the given peer. + /// Primarily intended for debugging purposes, but can also be used to get more detailed + /// failure information. (See SendMessageToUser and k_nSteamNetworkingSend_AutoRestartBrokenSession.) + /// + /// Returns the value of SteamNetConnectionInfo_t::m_eState, or k_ESteamNetworkingConnectionState_None + /// if no connection exists with specified peer. You may pass nullptr for either parameter if + /// you do not need the corresponding details. Note that sessions time out after a while, + /// so if a connection fails, or SendMessageToUser returns k_EResultNoConnection, you cannot wait + /// indefinitely to obtain the reason for failure. + virtual ESteamNetworkingConnectionState GetSessionConnectionInfo( const SteamNetworkingIdentity &identityRemote, SteamNetConnectionInfo_t *pConnectionInfo, SteamNetConnectionRealTimeStatus_t *pQuickStatus ) = 0; +}; +#define STEAMNETWORKINGMESSAGES_INTERFACE_VERSION "SteamNetworkingMessages002" + +// +// Callbacks +// + +#pragma pack( push, 1 ) + +/// Posted when a remote host is sending us a message, and we do not already have a session with them +struct SteamNetworkingMessagesSessionRequest_t +{ + enum { k_iCallback = k_iSteamNetworkingMessagesCallbacks + 1 }; + SteamNetworkingIdentity m_identityRemote; // user who wants to talk to us +}; + +/// Posted when we fail to establish a connection, or we detect that communications +/// have been disrupted it an unusual way. There is no notification when a peer proactively +/// closes the session. ("Closed by peer" is not a concept of UDP-style communications, and +/// SteamNetworkingMessages is primarily intended to make porting UDP code easy.) +/// +/// Remember: callbacks are asynchronous. See notes on SendMessageToUser, +/// and k_nSteamNetworkingSend_AutoRestartBrokenSession in particular. +/// +/// Also, if a session times out due to inactivity, no callbacks will be posted. The only +/// way to detect that this is happening is that querying the session state may return +/// none, connecting, and findingroute again. +struct SteamNetworkingMessagesSessionFailed_t +{ + enum { k_iCallback = k_iSteamNetworkingMessagesCallbacks + 2 }; + + /// Detailed info about the session that failed. + /// SteamNetConnectionInfo_t::m_identityRemote indicates who this session + /// was with. + SteamNetConnectionInfo_t m_info; +}; + +#pragma pack(pop) + +// Global accessors + +// Using standalone lib +#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB + + static_assert( STEAMNETWORKINGMESSAGES_INTERFACE_VERSION[25] == '2', "Version mismatch" ); + + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingMessages *SteamNetworkingMessages_LibV2(); + inline ISteamNetworkingMessages *SteamNetworkingMessages_Lib() { return SteamNetworkingMessages_LibV2(); } + + // If running in context of steam, we also define a gameserver instance. + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingMessages *SteamGameServerNetworkingMessages_LibV2(); + inline ISteamNetworkingMessages *SteamGameServerNetworkingMessages_Lib() { return SteamGameServerNetworkingMessages_LibV2(); } + + #ifndef STEAMNETWORKINGSOCKETS_STEAMAPI + inline ISteamNetworkingMessages *SteamNetworkingMessages() { return SteamNetworkingMessages_LibV2(); } + inline ISteamNetworkingMessages *SteamGameServerNetworkingMessages() { return SteamGameServerNetworkingMessages_LibV2(); } + #endif +#endif + +// Using Steamworks SDK +#ifdef STEAMNETWORKINGSOCKETS_STEAMAPI + + // Steamworks SDK + STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworkingMessages *, SteamNetworkingMessages_SteamAPI, STEAMNETWORKINGMESSAGES_INTERFACE_VERSION ); + STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworkingMessages *, SteamGameServerNetworkingMessages_SteamAPI, STEAMNETWORKINGMESSAGES_INTERFACE_VERSION ); + + #ifndef STEAMNETWORKINGSOCKETS_STANDALONELIB + inline ISteamNetworkingMessages *SteamNetworkingMessages() { return SteamNetworkingMessages_SteamAPI(); } + inline ISteamNetworkingMessages *SteamGameServerNetworkingMessages() { return SteamGameServerNetworkingMessages_SteamAPI(); } + #endif +#endif + +#endif // ISTEAMNETWORKINGMESSAGES diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingSockets.h b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingSockets.h new file mode 100644 index 0000000..75223d7 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingSockets.h @@ -0,0 +1,1031 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== + +#ifndef ISTEAMNETWORKINGSOCKETS +#define ISTEAMNETWORKINGSOCKETS +#pragma once + +#include "SteamNetworkingTypes.h" +#include "Steam_API_Common.h" + +struct SteamNetAuthenticationStatus_t; +struct SteamNetworkingFakeIPResult_t; +class ISteamNetworkingConnectionSignaling; +class ISteamNetworkingSignalingRecvContext; +class ISteamNetworkingFakeUDPPort; + +//----------------------------------------------------------------------------- +/// Lower level networking API. +/// +/// - Connection-oriented API (like TCP, not UDP). When sending and receiving +/// messages, a connection handle is used. (For a UDP-style interface, where +/// the peer is identified by their address with each send/recv call, see +/// ISteamNetworkingMessages.) The typical pattern is for a "server" to "listen" +/// on a "listen socket." A "client" will "connect" to the server, and the +/// server will "accept" the connection. If you have a symmetric situation +/// where either peer may initiate the connection and server/client roles are +/// not clearly defined, check out k_ESteamNetworkingConfig_SymmetricConnect. +/// - But unlike TCP, it's message-oriented, not stream-oriented. +/// - Mix of reliable and unreliable messages +/// - Fragmentation and reassembly +/// - Supports connectivity over plain UDP +/// - Also supports SDR ("Steam Datagram Relay") connections, which are +/// addressed by the identity of the peer. There is a "P2P" use case and +/// a "hosted dedicated server" use case. +/// +/// Note that neither of the terms "connection" nor "socket" necessarily 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. +/// +/// See also: ISteamNetworkingMessages, the UDP-style interface. This API might be +/// easier to use, especially when porting existing UDP code. +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 will set the IP portion of the address to zero (SteamNetworkingIPAddr::Clear()). + /// This means that you will not bind to any particular local interface (i.e. the same + /// as INADDR_ANY in plain socket code). Furthermore, if possible the socket will be bound + /// in "dual stack" mode, which means that it can accept both IPv4 and IPv6 client connections. + /// If you really do wish to bind a particular interface, then set the local address to the + /// appropriate IPv4 or IPv6 IP. + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + /// + /// 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, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 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. + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Like CreateListenSocketIP, but clients will connect using ConnectP2P. + /// + /// nLocalVirtualPort 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 nLocalVirtualPort 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. + /// + /// If you are listening on a dedicated servers in known data center, + /// then you can listen using this function instead of CreateHostedDedicatedServerListenSocket, + /// to allow clients to connect without a ticket. Any user that owns + /// the app and is signed into Steam will be able to attempt to connect to + /// your server. Also, a connection attempt may require the client to + /// be connected to Steam, which is one more moving part that may fail. When + /// tickets are used, then once a ticket is obtained, a client can connect to + /// your server even if they got disconnected from Steam or Steam is offline. + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamListenSocket CreateListenSocketP2P( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Begin connecting to a peer that is identified using a platform-specific identifier. + /// This uses the default rendezvous service, which depends on the platform and library + /// configuration. (E.g. on Steam, it goes through the steam backend.) + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + /// + /// To use your own signaling service, see: + /// - ConnectP2PCustomSignaling + /// - k_ESteamNetworkingConfig_Callback_CreateConnectionSignaling + virtual HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// 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.) + /// + /// A note about connection configuration options. If you need to set any configuration + /// options that are common to all connections accepted through a particular listen + /// socket, consider setting the options on the listen socket, since such options are + /// inherited automatically. If you really do need to set options that are connection + /// specific, it is safe to set them on the connection before accepting the connection. + 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 -- but see WARNINGS below!!!!) + /// + /// Do you need to set this atomically when the connection is created? + /// See k_ESteamNetworkingConfig_ConnectionUserData. + /// + /// WARNING: Be *very careful* when using the value provided in callbacks structs. + /// Callbacks are queued, and the value that you will receive in your + /// callback is the userdata that was effective at the time the callback + /// was queued. There are subtle race conditions that can hapen if you + /// don't understand this! + /// + /// If any incoming messages for this connection are queued, the userdata + /// field is updated, so that when when you receive messages (e.g. with + /// ReceiveMessagesOnConnection), they will always have the very latest + /// userdata. So the tricky race conditions that can happen with callbacks + /// do not apply to retrieving messages. + /// + /// 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. + /// + /// The pOutMessageNumber is an optional pointer to receive the + /// message number assigned to the message, if sending was successful. + /// + /// 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, int64 *pOutMessageNumber ) = 0; + + /// Send one or more messages without copying the message payload. + /// This is the most efficient way to send messages. To use this + /// function, you must first allocate a message object using + /// ISteamNetworkingUtils::AllocateMessage. (Do not declare one + /// on the stack or allocate your own.) + /// + /// You should fill in the message payload. You can either let + /// it allocate the buffer for you and then fill in the payload, + /// or if you already have a buffer allocated, you can just point + /// m_pData at your buffer and set the callback to the appropriate function + /// to free it. Note that if you use your own buffer, it MUST remain valid + /// until the callback is executed. And also note that your callback can be + /// invoked at any time from any thread (perhaps even before SendMessages + /// returns!), so it MUST be fast and threadsafe. + /// + /// You MUST also fill in: + /// - m_conn - the handle of the connection to send the message to + /// - m_nFlags - bitmask of k_nSteamNetworkingSend_xxx flags. + /// + /// All other fields are currently reserved and should not be modified. + /// + /// The library will take ownership of the message structures. They may + /// be modified or become invalid at any time, so you must not read them + /// after passing them to this function. + /// + /// pOutMessageNumberOrResult is an optional array that will receive, + /// for each message, the message number that was assigned to the message + /// if sending was successful. If sending failed, then a negative EResult + /// value is placed into the array. For example, the array will hold + /// -k_EResultInvalidState if the connection was in an invalid state. + /// See ISteamNetworkingSockets::SendMessageToConnection for possible + /// failure codes. + virtual void SendMessages( int nMessages, SteamNetworkingMessage_t *const *pMessages, int64 *pOutMessageNumberOrResult ) = 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 with respect 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; + + /// 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 + /// and the queue status of each lane. + /// + /// - pStatus may be NULL if the information is not desired. (E.g. you are only interested + /// in the lane information.) + /// - On entry, nLanes specifies the length of the pLanes array. This may be 0 + /// if you do not wish to receive any lane data. It's OK for this to be smaller than + /// the total number of configured lanes. + /// - pLanes points to an array that will receive lane-specific info. It can be NULL + /// if this is not needed. + /// + /// Return value: + /// - k_EResultNoConnection - connection handle is invalid or connection has been closed. + /// - k_EResultInvalidParam - nLanes is bad + virtual EResult GetConnectionRealTimeStatus( HSteamNetConnection hConn, SteamNetConnectionRealTimeStatus_t *pStatus, + int nLanes, SteamNetConnectionRealTimeLaneStatus_t *pLanes ) = 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; + + /// Configure multiple outbound messages streams ("lanes") on a connection, and + /// control head-of-line blocking between them. Messages within a given lane + /// are always sent in the order they are queued, but messages from different + /// lanes may be sent out of order. Each lane has its own message number + /// sequence. The first message sent on each lane will be assigned the number 1. + /// + /// Each lane has a "priority". Lower priority lanes will only be processed + /// when all higher-priority lanes are empty. The magnitudes of the priority + /// values are not relevant, only their sort order. Higher numeric values + /// take priority over lower numeric values. + /// + /// Each lane also is assigned a weight, which controls the approximate proportion + /// of the bandwidth that will be consumed by the lane, relative to other lanes + /// of the same priority. (This is assuming the lane stays busy. An idle lane + /// does not build up "credits" to be be spent once a message is queued.) + /// This value is only meaningful as a proportion, relative to other lanes with + /// the same priority. For lanes with different priorities, the strict priority + /// order will prevail, and their weights relative to each other are not relevant. + /// Thus, if a lane has a unique priority value, the weight value for that lane is + /// not relevant. + /// + /// Example: 3 lanes, with priorities [ 0, 10, 10 ] and weights [ (NA), 20, 5 ]. + /// Messages sent on the first will always be sent first, before messages in the + /// other two lanes. Its weight value is irrelevant, since there are no other + /// lanes with priority=0. The other two lanes will share bandwidth, with the second + /// and third lanes sharing bandwidth using a ratio of approximately 4:1. + /// (The weights [ NA, 4, 1 ] would be equivalent.) + /// + /// Notes: + /// - At the time of this writing, some code has performance cost that is linear + /// in the number of lanes, so keep the number of lanes to an absolute minimum. + /// 3 or so is fine; >8 is a lot. The max number of lanes on Steam is 255, + /// which is a very large number and not recommended! If you are compiling this + /// library from source, see STEAMNETWORKINGSOCKETS_MAX_LANES.) + /// - Lane priority values may be any int. Their absolute value is not relevant, + /// only the order matters. + /// - Weights must be positive, and due to implementation details, they are restricted + /// to 16-bit values. The absolute magnitudes don't matter, just the proportions. + /// - Messages sent on a lane index other than 0 have a small overhead on the wire, + /// so for maximum wire efficiency, lane 0 should be the "most common" lane, regardless + /// of priorities or weights. + /// - A connection has a single lane by default. Calling this function with + /// nNumLanes=1 is legal, but pointless, since the priority and weight values are + /// irrelevant in that case. + /// - You may reconfigure connection lanes at any time, however reducing the number of + /// lanes is not allowed. + /// - Reconfiguring lanes might restart any bandwidth sharing balancing. Usually you + /// will call this function once, near the start of the connection, perhaps after + /// exchanging a few messages. + /// - To assign all lanes the same priority, you may use pLanePriorities=NULL. + /// - If you wish all lanes with the same priority to share bandwidth equally (or + /// if no two lanes have the same priority value, and thus priority values are + /// irrelevant), you may use pLaneWeights=NULL + /// - Priorities and weights determine the order that messages are SENT on the wire. + /// There are NO GUARANTEES on the order that messages are RECEIVED! Due to packet + /// loss, out-of-order delivery, and subtle details of packet serialization, messages + /// might still be received slightly out-of-order! The *only* strong guarantee is that + /// *reliable* messages on the *same lane* will be delivered in the order they are sent. + /// - Each host configures the lanes for the packets they send; the lanes for the flow + /// in one direction are completely unrelated to the lanes in the opposite direction. + /// + /// Return value: + /// - k_EResultNoConnection - bad hConn + /// - k_EResultInvalidParam - Invalid number of lanes, bad weights, or you tried to reduce the number of lanes + /// - k_EResultInvalidState - Connection is already dead, etc + /// + /// See also: + /// SteamNetworkingMessage_t::m_idxLane + virtual EResult ConfigureConnectionLanes( HSteamNetConnection hConn, int nNumLanes, const int *pLanePriorities, const uint16 *pLaneWeights ) = 0; + + // + // Identity and authentication + // + + /// 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; + + // + // Poll groups. A poll group is a set of connections that can be polled efficiently. + // (In our API, to "poll" a connection means to retrieve all pending messages. We + // actually don't have an API to "poll" the connection *state*, like BSD sockets.) + // + + /// Create a new poll group. + /// + /// You should destroy the poll group when you are done using DestroyPollGroup + virtual HSteamNetPollGroup CreatePollGroup() = 0; + + /// Destroy a poll group created with CreatePollGroup(). + /// + /// If there are any connections in the poll group, they are removed from the group, + /// and left in a state where they are not part of any poll group. + /// Returns false if passed an invalid poll group handle. + virtual bool DestroyPollGroup( HSteamNetPollGroup hPollGroup ) = 0; + + /// Assign a connection to a poll group. Note that a connection may only belong to a + /// single poll group. Adding a connection to a poll group implicitly removes it from + /// any other poll group it is in. + /// + /// You can pass k_HSteamNetPollGroup_Invalid to remove a connection from its current + /// poll group without adding it to a new poll group. + /// + /// If there are received messages currently pending on the connection, an attempt + /// is made to add them to the queue of messages for the poll group in approximately + /// the order that would have applied if the connection was already part of the poll + /// group at the time that the messages were received. + /// + /// Returns false if the connection handle is invalid, or if the poll group handle + /// is invalid (and not k_HSteamNetPollGroup_Invalid). + virtual bool SetConnectionPollGroup( HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup ) = 0; + + /// Same as ReceiveMessagesOnConnection, but will return the next messages available + /// on any connection in the poll group. Examine SteamNetworkingMessage_t::m_conn + /// to know which connection. (SteamNetworkingMessage_t::m_nConnUserData might also + /// be useful.) + /// + /// Delivery order of messages among different connections will usually match the + /// order that the last packet was received which completed the message. But this + /// is not a strong guarantee, especially for packets received right as a connection + /// is being assigned to poll group. + /// + /// Delivery order of messages on the same connection is well defined and the + /// same guarantees are present as mentioned in ReceiveMessagesOnConnection. + /// (But the messages are not grouped by connection, so they will not necessarily + /// appear consecutively in the list; they may be interleaved with messages for + /// other connections.) + virtual int ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + // + // Clients connecting to dedicated servers hosted in a data center, + // using tickets issued by your game coordinator. If you are not + // issuing your own tickets to restrict who can attempt to connect + // to your server, then you won't use these functions. + // + + /// 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 nRemoteVirtualPort, 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! If you are not issuing your own tickets, then to connect to a dedicated + /// server via SDR in auto-ticket mode, use ConnectP2P. (The server must be configured to allow + /// this type of connection by listening using CreateListenSocketP2P.) + /// + /// 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 + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 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 environment. + 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. + /// + /// This call MUST be made through the SteamGameServerNetworkingSockets() interface. + /// + /// This function should be used when you are using the ticket generator library + /// to issue your own tickets. Clients connecting to the server on this virtual + /// port will need a ticket, and they must connect using ConnectToHostedDedicatedServer. + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 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; + + + // + // Relayed connections using custom signaling protocol + // + // This is used if you have your own method of sending out-of-band + // signaling / rendezvous messages through a mutually trusted channel. + // + + /// Create a P2P "client" connection that does signaling over a custom + /// rendezvous/signaling channel. + /// + /// pSignaling points to a new object that you create just for this connection. + /// It must stay valid until Release() is called. Once you pass the + /// object to this function, it assumes ownership. Release() will be called + /// from within the function call if the call fails. Furthermore, until Release() + /// is called, you should be prepared for methods to be invoked on your + /// object from any thread! You need to make sure your object is threadsafe! + /// Furthermore, you should make sure that dispatching the methods is done + /// as quickly as possible. + /// + /// This function will immediately construct a connection in the "connecting" + /// state. Soon after (perhaps before this function returns, perhaps in another thread), + /// the connection will begin sending signaling messages by calling + /// ISteamNetworkingConnectionSignaling::SendSignal. + /// + /// When the remote peer accepts the connection (See + /// ISteamNetworkingSignalingRecvContext::OnConnectRequest), + /// it will begin sending signaling messages. When these messages are received, + /// you can pass them to the connection using ReceivedP2PCustomSignal. + /// + /// If you know the identity of the peer that you expect to be on the other end, + /// you can pass their identity to improve debug output or just detect bugs. + /// If you don't know their identity yet, you can pass NULL, and their + /// identity will be established in the connection handshake. + /// + /// If you use this, you probably want to call ISteamNetworkingUtils::InitRelayNetworkAccess() + /// when your app initializes + /// + /// If you need to set any initial config options, pass them here. See + /// SteamNetworkingConfigValue_t for more about why this is preferable to + /// setting the options "immediately" after creation. + virtual HSteamNetConnection ConnectP2PCustomSignaling( ISteamNetworkingConnectionSignaling *pSignaling, const SteamNetworkingIdentity *pPeerIdentity, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// Called when custom signaling has received a message. When your + /// signaling channel receives a message, it should save off whatever + /// routing information was in the envelope into the context object, + /// and then pass the payload to this function. + /// + /// A few different things can happen next, depending on the message: + /// + /// - If the signal is associated with existing connection, it is dealt + /// with immediately. If any replies need to be sent, they will be + /// dispatched using the ISteamNetworkingConnectionSignaling + /// associated with the connection. + /// - If the message represents a connection request (and the request + /// is not redundant for an existing connection), a new connection + /// will be created, and ReceivedConnectRequest will be called on your + /// context object to determine how to proceed. + /// - Otherwise, the message is for a connection that does not + /// exist (anymore). In this case, we *may* call SendRejectionReply + /// on your context object. + /// + /// In any case, we will not save off pContext or access it after this + /// function returns. + /// + /// Returns true if the message was parsed and dispatched without anything + /// unusual or suspicious happening. Returns false if there was some problem + /// with the message that prevented ordinary handling. (Debug output will + /// usually have more information.) + /// + /// If you expect to be using relayed connections, then you probably want + /// to call ISteamNetworkingUtils::InitRelayNetworkAccess() when your app initializes + virtual bool ReceivedP2PCustomSignal( const void *pMsg, int cbMsg, ISteamNetworkingSignalingRecvContext *pContext ) = 0; + + // + // Certificate provision by the application. On Steam, we normally handle all this automatically + // and you will not need to use these advanced functions. + // + + /// 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. (512 bytes is a 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; + + /// Reset the identity associated with this instance. + /// Any open connections are closed. Any previous certificates, etc are discarded. + /// You can pass a specific identity that you want to use, or you can pass NULL, + /// in which case the identity will be invalid until you set it using SetCertificate + /// + /// NOTE: This function is not actually supported on Steam! It is included + /// for use on other platforms where the active user can sign out and + /// a new user can sign in. + virtual void ResetIdentity( const SteamNetworkingIdentity *pIdentity ) = 0; + + // + // Misc + // + + /// Invoke all callback functions queued for this interface. + /// See k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, etc + /// + /// You don't need to call this if you are using Steam's callback dispatch + /// mechanism (SteamAPI_RunCallbacks and SteamGameserver_RunCallbacks). + virtual void RunCallbacks() = 0; + + // + // "FakeIP" system. + // + // A FakeIP is essentially a temporary, arbitrary identifier that + // happens to be a valid IPv4 address. The purpose of this system is to make it + // easy to integrate with existing code that identifies hosts using IPv4 addresses. + // The FakeIP address will never actually be used to send or receive any packets + // on the Internet, it is strictly an identifier. + // + // FakeIP addresses are designed to (hopefully) pass through existing code as + // transparently as possible, while conflicting with "real" addresses that might + // be in use on networks (both the Internet and LANs) in the same code as little + // as possible. At the time this comment is being written, they come from the + // 169.254.0.0/16 range, and the port number will always be >1024. HOWEVER, + // this is subject to change! Do not make assumptions about these addresses, + // or your code might break in the future. In particular, you should use + // functions such as ISteamNetworkingUtils::IsFakeIP to determine if an IP + // address is a "fake" one used by this system. + // + + /// Begin asynchronous process of allocating a fake IPv4 address that other + /// peers can use to contact us via P2P. IP addresses returned by this + /// function are globally unique for a given appid. + /// + /// nNumPorts is the numbers of ports you wish to reserve. This is useful + /// for the same reason that listening on multiple UDP ports is useful for + /// different types of traffic. Because these allocations come from a global + /// namespace, there is a relatively strict limit on the maximum number of + /// ports you may request. (At the time of this writing, the limit is 4.) + /// The Port assignments are *not* guaranteed to have any particular order + /// or relationship! Do *not* assume they are contiguous, even though that + /// may often occur in practice. + /// + /// Returns false if a request was already in progress, true if a new request + /// was started. A SteamNetworkingFakeIPResult_t will be posted when the request + /// completes. + /// + /// For gameservers, you *must* call this after initializing the SDK but before + /// beginning login. Steam needs to know in advance that FakeIP will be used. + /// Everywhere your public IP would normally appear (such as the server browser) will be + /// replaced by the FakeIP, and the fake port at index 0. The request is actually queued + /// until the logon completes, so you must not wait until the allocation completes + /// before logging in. Except for trivial failures that can be detected locally + /// (e.g. invalid parameter), a SteamNetworkingFakeIPResult_t callback (whether success or + /// failure) will not be posted until after we have logged in. Furthermore, it is assumed + /// that FakeIP allocation is essential for your application to function, and so failure + /// will not be reported until *several* retries have been attempted. This process may + /// last several minutes. It is *highly* recommended to treat failure as fatal. + /// + /// To communicate using a connection-oriented (TCP-style) API: + /// - Server creates a listen socket using CreateListenSocketP2PFakeIP + /// - Client connects using ConnectByIPAddress, passing in the FakeIP address. + /// - The connection will behave mostly like a P2P connection. The identities + /// that appear in SteamNetConnectionInfo_t will be the FakeIP identity until + /// we know the real identity. Then it will be the real identity. If the + /// SteamNetConnectionInfo_t::m_addrRemote is valid, it will be a real IPv4 + /// address of a NAT-punched connection. Otherwise, it will not be valid. + /// + /// To communicate using an ad-hoc sendto/recv from (UDP-style) API, + /// use CreateFakeUDPPort. + virtual bool BeginAsyncRequestFakeIP( int nNumPorts ) = 0; + + /// Return info about the FakeIP and port(s) that we have been assigned, + /// if any. idxFirstPort is currently reserved and must be zero. + /// Make sure and check SteamNetworkingFakeIPResult_t::m_eResult + virtual void GetFakeIP( int idxFirstPort, SteamNetworkingFakeIPResult_t *pInfo ) = 0; + + /// Create a listen socket that will listen for P2P connections sent + /// to our FakeIP. A peer can initiate connections to this listen + /// socket by calling ConnectByIPAddress. + /// + /// idxFakePort refers to the *index* of the fake port requested, + /// not the actual port number. For example, pass 0 to refer to the + /// first port in the reservation. You must call this only after calling + /// BeginAsyncRequestFakeIP. However, you do not need to wait for the + /// request to complete before creating the listen socket. + virtual HSteamListenSocket CreateListenSocketP2PFakeIP( int idxFakePort, int nOptions, const SteamNetworkingConfigValue_t *pOptions ) = 0; + + /// If the connection was initiated using the "FakeIP" system, then we + /// we can get an IP address for the remote host. If the remote host had + /// a global FakeIP at the time the connection was established, this + /// function will return that global IP. Otherwise, a FakeIP that is + /// unique locally will be allocated from the local FakeIP address space, + /// and that will be returned. + /// + /// The allocation of local FakeIPs attempts to assign addresses in + /// a consistent manner. If multiple connections are made to the + /// same remote host, they *probably* will return the same FakeIP. + /// However, since the namespace is limited, this cannot be guaranteed. + /// + /// On failure, returns: + /// - k_EResultInvalidParam: invalid connection handle + /// - k_EResultIPNotFound: This connection wasn't made using FakeIP system + virtual EResult GetRemoteFakeIPForConnection( HSteamNetConnection hConn, SteamNetworkingIPAddr *pOutAddr ) = 0; + + /// Get an interface that can be used like a UDP port to send/receive + /// datagrams to a FakeIP address. This is intended to make it easy + /// to port existing UDP-based code to take advantage of SDR. + /// + /// idxFakeServerPort refers to the *index* of the port allocated using + /// BeginAsyncRequestFakeIP and is used to create "server" ports. You may + /// call this before the allocation has completed. However, any attempts + /// to send packets will fail until the allocation has succeeded. When + /// the peer receives packets sent from this interface, the from address + /// of the packet will be the globally-unique FakeIP. If you call this + /// function multiple times and pass the same (nonnegative) fake port index, + /// the same object will be returned, and this object is not reference counted. + /// + /// To create a "client" port (e.g. the equivalent of an ephemeral UDP port) + /// pass -1. In this case, a distinct object will be returned for each call. + /// When the peer receives packets sent from this interface, the peer will + /// assign a FakeIP from its own locally-controlled namespace. + virtual ISteamNetworkingFakeUDPPort *CreateFakeUDPPort( int idxFakeServerPort ) = 0; + +protected: + ~ISteamNetworkingSockets(); // Silence some warnings +}; +#define STEAMNETWORKINGSOCKETS_INTERFACE_VERSION "SteamNetworkingSockets012" + +// Global accessors + +// Using standalone lib +#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB + + static_assert( STEAMNETWORKINGSOCKETS_INTERFACE_VERSION[24] == '2', "Version mismatch" ); + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamNetworkingSockets_LibV12(); + inline ISteamNetworkingSockets *SteamNetworkingSockets_Lib() { return SteamNetworkingSockets_LibV12(); } + + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingSockets *SteamGameServerNetworkingSockets_LibV12(); + inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets_Lib() { return SteamGameServerNetworkingSockets_LibV12(); } + + #ifndef STEAMNETWORKINGSOCKETS_STEAMAPI + inline ISteamNetworkingSockets *SteamNetworkingSockets() { return SteamNetworkingSockets_LibV12(); } + inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets() { return SteamGameServerNetworkingSockets_LibV12(); } + #endif +#endif + +// Using Steamworks SDK +#ifdef STEAMNETWORKINGSOCKETS_STEAMAPI + STEAM_DEFINE_USER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamNetworkingSockets_SteamAPI, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION ); + STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( ISteamNetworkingSockets *, SteamGameServerNetworkingSockets_SteamAPI, STEAMNETWORKINGSOCKETS_INTERFACE_VERSION ); + + #ifndef STEAMNETWORKINGSOCKETS_STANDALONELIB + inline ISteamNetworkingSockets *SteamNetworkingSockets() { return SteamNetworkingSockets_SteamAPI(); } + inline ISteamNetworkingSockets *SteamGameServerNetworkingSockets() { return SteamGameServerNetworkingSockets_SteamAPI(); } + #endif +#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. +/// +/// This callback is posted whenever the state of our readiness changes. +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/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingUtils.h b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingUtils.h new file mode 100644 index 0000000..09f9343 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamNetworkingUtils.h @@ -0,0 +1,500 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Purpose: misc networking utilities +// +//============================================================================= + +#ifndef ISTEAMNETWORKINGUTILS +#define ISTEAMNETWORKINGUTILS +#pragma once + +#include "SteamNetworkingTypes.h" +#include "Steam_API_Common.h" + +struct SteamDatagramRelayAuthTicket; +struct SteamRelayNetworkStatus_t; + +//----------------------------------------------------------------------------- +/// Misc networking utilities for checking the local networking environment +/// and estimating pings. +class ISteamNetworkingUtils +{ +public: + // + // Efficient message sending + // + + /// Allocate and initialize a message object. Usually the reason + /// you call this is to pass it to ISteamNetworkingSockets::SendMessages. + /// The returned object will have all of the relevant fields cleared to zero. + /// + /// Optionally you can also request that this system allocate space to + /// hold the payload itself. If cbAllocateBuffer is nonzero, the system + /// will allocate memory to hold a payload of at least cbAllocateBuffer bytes. + /// m_pData will point to the allocated buffer, m_cbSize will be set to the + /// size, and m_pfnFreeData will be set to the proper function to free up + /// the buffer. + /// + /// If cbAllocateBuffer=0, then no buffer is allocated. m_pData will be NULL, + /// m_cbSize will be zero, and m_pfnFreeData will be NULL. You will need to + /// set each of these. + virtual SteamNetworkingMessage_t *AllocateMessage( int cbAllocateBuffer ) = 0; + + // + // Access to Steam Datagram Relay (SDR) network + // + + // + // Initialization and status check + // + + /// If you know that you are going to be using the relay network (for example, + /// because you anticipate making P2P connections), call this to initialize the + /// relay network. If you do not call this, the initialization will + /// be delayed until the first time you use a feature that requires access + /// to the relay network, which will delay that first access. + /// + /// You can also call this to force a retry if the previous attempt has failed. + /// Performing any action that requires access to the relay network will also + /// trigger a retry, and so calling this function is never strictly necessary, + /// but it can be useful to call it a program launch time, if access to the + /// relay network is anticipated. + /// + /// 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 "game coordinator" 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; + + // + // 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. + /// + /// The value here controls the detail level for most messages. You can control the + /// detail level for various subsystems (perhaps only for certain connections) by + /// adjusting the configuration values k_ESteamNetworkingConfig_LogLevel_Xxxxx. + /// + /// 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. This incurs + /// all of the expense of formatting the messages, which are then discarded. Setting a high + /// priority value (low numeric value) here allows the library to avoid doing this work. + /// + /// 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; + + // + // Fake IP + // + // Useful for interfacing with code that assumes peers are identified using an IPv4 address + // + + /// Return true if an IPv4 address is one that might be used as a "fake" one. + /// This function is fast; it just does some logical tests on the IP and does + /// not need to do any lookup operations. + inline bool IsFakeIPv4( uint32 nIPv4 ) { return GetIPv4FakeIPType( nIPv4 ) > k_ESteamNetworkingFakeIPType_NotFake; } + virtual ESteamNetworkingFakeIPType GetIPv4FakeIPType( uint32 nIPv4 ) = 0; + + /// Get the real identity associated with a given FakeIP. + /// + /// On failure, returns: + /// - k_EResultInvalidParam: the IP is not a FakeIP. + /// - k_EResultNoMatch: we don't recognize that FakeIP and don't know the corresponding identity. + /// + /// FakeIP's used by active connections, or the FakeIPs assigned to local identities, + /// will always work. FakeIPs for recently destroyed connections will continue to + /// return results for a little while, but not forever. At some point, we will forget + /// FakeIPs to save space. It's reasonably safe to assume that you can read back the + /// real identity of a connection very soon after it is destroyed. But do not wait + /// indefinitely. + virtual EResult GetRealIdentityForFakeIP( const SteamNetworkingIPAddr &fakeIP, SteamNetworkingIdentity *pOutRealIdentity ) = 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 SetGlobalConfigValuePtr( ESteamNetworkingConfigValue eValue, void *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 global callbacks. If you do not want to use Steam's callback dispatch mechanism and you + // want to use the same callback on all (or most) listen sockets and connections, then + // simply install these callbacks first thing, and you are good to go. + // See ISteamNetworkingSockets::RunCallbacks + // + bool SetGlobalCallback_SteamNetConnectionStatusChanged( FnSteamNetConnectionStatusChanged fnCallback ); + bool SetGlobalCallback_SteamNetAuthenticationStatusChanged( FnSteamNetAuthenticationStatusChanged fnCallback ); + bool SetGlobalCallback_SteamRelayNetworkStatusChanged( FnSteamRelayNetworkStatusChanged fnCallback ); + bool SetGlobalCallback_FakeIPResult( FnSteamNetworkingFakeIPResult fnCallback ); + bool SetGlobalCallback_MessagesSessionRequest( FnSteamNetworkingMessagesSessionRequest fnCallback ); + bool SetGlobalCallback_MessagesSessionFailed( FnSteamNetworkingMessagesSessionFailed fnCallback ); + + /// 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 setting 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 pointers (e.g. 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; + + /// Set a configuration value, using a struct to pass the value. + /// (This is just a convenience shortcut; see below for the implementation and + /// a little insight into how SteamNetworkingConfigValue_t is used when + /// setting config options during listen socket and connection creation.) + bool SetConfigValueStruct( const SteamNetworkingConfigValue_t &opt, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj ); + + /// 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; + + /// Get info about a configuration value. Returns the name of the value, + /// or NULL if the value doesn't exist. Other output parameters can be NULL + /// if you do not need them. + virtual const char *GetConfigValueInfo( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigDataType *pOutDataType, + ESteamNetworkingConfigScope *pOutScope ) = 0; + + /// Iterate the list of all configuration values in the current environment that it might + /// be possible to display or edit using a generic UI. To get the first iterable value, + /// pass k_ESteamNetworkingConfig_Invalid. Returns k_ESteamNetworkingConfig_Invalid + /// to signal end of list. + /// + /// The bEnumerateDevVars argument can be used to include "dev" vars. These are vars that + /// are recommended to only be editable in "debug" or "dev" mode and typically should not be + /// shown in a retail environment where a malicious local user might use this to cheat. + virtual ESteamNetworkingConfigValue IterateGenericEditableConfigValues( ESteamNetworkingConfigValue eCurrent, bool bEnumerateDevVars ) = 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 ESteamNetworkingFakeIPType SteamNetworkingIPAddr_GetFakeIPType( const SteamNetworkingIPAddr &addr ) = 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 "SteamNetworkingUtils004" + +// Global accessors +// Using standalone lib +#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB + + // Standalone lib + static_assert( STEAMNETWORKINGUTILS_INTERFACE_VERSION[22] == '4', "Version mismatch" ); + STEAMNETWORKINGSOCKETS_INTERFACE ISteamNetworkingUtils *SteamNetworkingUtils_LibV4(); + inline ISteamNetworkingUtils *SteamNetworkingUtils_Lib() { return SteamNetworkingUtils_LibV4(); } + + #ifndef STEAMNETWORKINGSOCKETS_STEAMAPI + inline ISteamNetworkingUtils *SteamNetworkingUtils() { return SteamNetworkingUtils_LibV4(); } + #endif +#endif + +// Using Steamworks SDK +#ifdef STEAMNETWORKINGSOCKETS_STEAMAPI + STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamNetworkingUtils *, SteamNetworkingUtils_SteamAPI, + /* Prefer user version of the interface. But if it isn't found, then use + gameserver one. Yes, this is a completely terrible hack */ + SteamInternal_FindOrCreateUserInterface( 0, STEAMNETWORKINGUTILS_INTERFACE_VERSION ) ? + SteamInternal_FindOrCreateUserInterface( 0, STEAMNETWORKINGUTILS_INTERFACE_VERSION ) : + SteamInternal_FindOrCreateGameServerInterface( 0, STEAMNETWORKINGUTILS_INTERFACE_VERSION ), + "global", + STEAMNETWORKINGUTILS_INTERFACE_VERSION + ) + + #ifndef STEAMNETWORKINGSOCKETS_STANDALONELIB + inline ISteamNetworkingUtils *SteamNetworkingUtils() { return SteamNetworkingUtils_SteamAPI(); } + #endif +#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 ]; +}; + +#ifndef API_GEN + +/// Utility class for printing a SteamNetworkingIdentity. +/// E.g. printf( "Identity is '%s'\n", SteamNetworkingIdentityRender( identity ).c_str() ); +struct SteamNetworkingIdentityRender +{ + SteamNetworkingIdentityRender( const SteamNetworkingIdentity &x ) { x.ToString( buf, sizeof(buf) ); } + inline const char *c_str() const { return buf; } +private: + char buf[ SteamNetworkingIdentity::k_cchMaxString ]; +}; + +/// Utility class for printing a SteamNetworkingIPAddrRender. +struct SteamNetworkingIPAddrRender +{ + SteamNetworkingIPAddrRender( const SteamNetworkingIPAddr &x, bool bWithPort = true ) { x.ToString( buf, sizeof(buf), bWithPort ); } + inline const char *c_str() const { return buf; } +private: + char buf[ SteamNetworkingIPAddr::k_cchMaxString ]; +}; + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Internal stuff + +inline void ISteamNetworkingUtils::InitRelayNetworkAccess() { CheckPingDataUpToDate( 1e10f ); } +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::SetGlobalConfigValuePtr( ESteamNetworkingConfigValue eValue, void *val ) { return SetConfigValue( eValue, k_ESteamNetworkingConfig_Global, 0, k_ESteamNetworkingConfig_Ptr, &val ); } // Note: passing pointer to pointer. +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 ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_SteamNetConnectionStatusChanged( FnSteamNetConnectionStatusChanged fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_SteamNetAuthenticationStatusChanged( FnSteamNetAuthenticationStatusChanged fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_AuthStatusChanged, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_SteamRelayNetworkStatusChanged( FnSteamRelayNetworkStatusChanged fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_RelayNetworkStatusChanged, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_FakeIPResult( FnSteamNetworkingFakeIPResult fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_FakeIPResult, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionRequest( FnSteamNetworkingMessagesSessionRequest fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_MessagesSessionRequest, (void*)fnCallback ); } +inline bool ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionFailed( FnSteamNetworkingMessagesSessionFailed fnCallback ) { return SetGlobalConfigValuePtr( k_ESteamNetworkingConfig_Callback_MessagesSessionFailed, (void*)fnCallback ); } + +inline bool ISteamNetworkingUtils::SetConfigValueStruct( const SteamNetworkingConfigValue_t &opt, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj ) +{ + // Locate the argument. Strings are a special case, since the + // "value" (the whole string buffer) doesn't fit in the struct + // NOTE: for pointer values, we pass a pointer to the pointer, + // we do not pass the pointer directly. + const void *pVal = ( opt.m_eDataType == k_ESteamNetworkingConfig_String ) ? (const void *)opt.m_val.m_string : (const void *)&opt.m_val; + return SetConfigValue( opt.m_eValue, eScopeType, scopeObj, opt.m_eDataType, pVal ); +} + +// How to get helper functions. +#if defined( STEAMNETWORKINGSOCKETS_STATIC_LINK ) || defined(STEAMNETWORKINGSOCKETS_FOREXPORT) || defined( STEAMNETWORKINGSOCKETS_STANDALONELIB ) + + // Call direct to static functions + STEAMNETWORKINGSOCKETS_INTERFACE void SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr *pAddr, char *buf, size_t cbBuf, bool bWithPort ); + STEAMNETWORKINGSOCKETS_INTERFACE bool SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr ); + STEAMNETWORKINGSOCKETS_INTERFACE ESteamNetworkingFakeIPType SteamNetworkingIPAddr_GetFakeIPType( const SteamNetworkingIPAddr *pAddr ); + STEAMNETWORKINGSOCKETS_INTERFACE void SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity *pIdentity, char *buf, size_t cbBuf ); + STEAMNETWORKINGSOCKETS_INTERFACE bool SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, size_t sizeofIdentity, const char *pszStr ); + inline void SteamNetworkingIPAddr::ToString( char *buf, size_t cbBuf, bool bWithPort ) const { SteamNetworkingIPAddr_ToString( this, buf, cbBuf, bWithPort ); } + inline bool SteamNetworkingIPAddr::ParseString( const char *pszStr ) { return SteamNetworkingIPAddr_ParseString( this, pszStr ); } + inline ESteamNetworkingFakeIPType SteamNetworkingIPAddr::GetFakeIPType() const { return SteamNetworkingIPAddr_GetFakeIPType( this ); } + inline void SteamNetworkingIdentity::ToString( char *buf, size_t cbBuf ) const { SteamNetworkingIdentity_ToString( this, buf, cbBuf ); } + inline bool SteamNetworkingIdentity::ParseString( const char *pszStr ) { return SteamNetworkingIdentity_ParseString( this, sizeof(*this), pszStr ); } + +#elif defined( STEAMNETWORKINGSOCKETS_STEAMAPI ) + // Using steamworks SDK - go through SteamNetworkingUtils() + 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 ESteamNetworkingFakeIPType SteamNetworkingIPAddr::GetFakeIPType() const { return SteamNetworkingUtils()->SteamNetworkingIPAddr_GetFakeIPType( *this ); } + 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 ); } +#else + #error "Invalid config" +#endif + +#endif // ISTEAMNETWORKINGUTILS diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamPS3OverlayRenderer.h b/Amalgam/src/SDK/Definitions/Steam/ISteamPS3OverlayRenderer.h new file mode 100644 index 0000000..4ab75d6 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/ISteamParentalSettings.h b/Amalgam/src/SDK/Definitions/Steam/ISteamParentalSettings.h new file mode 100644 index 0000000..b86a591 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamParentalSettings.h @@ -0,0 +1,64 @@ +//====== 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_EFeatureSiteLicense = 13, + k_EFeatureKioskMode = 14, + 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/Amalgam/src/SDK/Definitions/Steam/ISteamRemotePlay.h b/Amalgam/src/SDK/Definitions/Steam/ISteamRemotePlay.h new file mode 100644 index 0000000..d4e8757 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamRemotePlay.h @@ -0,0 +1,93 @@ +//============ 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 = 0, + k_ESteamDeviceFormFactorPhone = 1, + k_ESteamDeviceFormFactorTablet = 2, + k_ESteamDeviceFormFactorComputer = 3, + k_ESteamDeviceFormFactorTV = 4, +}; + +// Steam Remote Play session ID +typedef uint32 RemotePlaySessionID_t; + + +//----------------------------------------------------------------------------- +// 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 RemotePlaySessionID_t GetSessionID( int iSessionIndex ) = 0; + + // Get the SteamID of the connected user + virtual CSteamID GetSessionSteamID( RemotePlaySessionID_t unSessionID ) = 0; + + // Get the name of the session client device + // This returns NULL if the sessionID is not valid + virtual const char *GetSessionClientName( RemotePlaySessionID_t unSessionID ) = 0; + + // Get the form factor of the session client device + virtual ESteamDeviceFormFactor GetSessionClientFormFactor( RemotePlaySessionID_t 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( RemotePlaySessionID_t unSessionID, int *pnResolutionX, int *pnResolutionY ) = 0; + + // Invite a friend to Remote Play Together, or create a guest invite if steamIDFriend is empty + // This returns false if the invite can't be sent + virtual bool BSendRemotePlayTogetherInvite( CSteamID steamIDFriend ) = 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, RemotePlaySessionID_t, m_unSessionID ) +STEAM_CALLBACK_END( 0 ) + + +STEAM_CALLBACK_BEGIN( SteamRemotePlaySessionDisconnected_t, k_iSteamRemotePlayCallbacks + 2 ) + STEAM_CALLBACK_MEMBER( 0, RemotePlaySessionID_t, m_unSessionID ) +STEAM_CALLBACK_END( 0 ) + + +STEAM_CALLBACK_BEGIN( SteamRemotePlayTogetherGuestInvite_t, k_iSteamRemotePlayCallbacks + 3 ) + STEAM_CALLBACK_MEMBER_ARRAY( 0, char, m_szConnectURL, 1024 ) +STEAM_CALLBACK_END( 0 ) + + +#pragma pack( pop ) + + +#endif // #define ISTEAMREMOTEPLAY_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamRemoteStorage.h b/Amalgam/src/SDK/Definitions/Steam/ISteamRemoteStorage.h new file mode 100644 index 0000000..c7cfa26 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamRemoteStorage.h @@ -0,0 +1,660 @@ +//====== 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_ERemoteStoragePlatformSwitch = (1 << 4), + k_ERemoteStoragePlatformAndroid = (1 << 5), + k_ERemoteStoragePlatformIOS = (1 << 6), + // NB we get one more before we need to widen some things + + k_ERemoteStoragePlatformAll = 0xffffffff +}; + +enum ERemoteStoragePublishedFileVisibility +{ + k_ERemoteStoragePublishedFileVisibilityPublic = 0, + k_ERemoteStoragePublishedFileVisibilityFriendsOnly = 1, + k_ERemoteStoragePublishedFileVisibilityPrivate = 2, + k_ERemoteStoragePublishedFileVisibilityUnlisted = 3, +}; + + +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, +}; + +enum ERemoteStorageLocalFileChange +{ + k_ERemoteStorageLocalFileChange_Invalid = 0, + + // The file was updated from another device + k_ERemoteStorageLocalFileChange_FileUpdated = 1, + + // The file was deleted by another device + k_ERemoteStorageLocalFileChange_FileDeleted = 2, +}; + +enum ERemoteStorageFilePathType +{ + k_ERemoteStorageFilePathType_Invalid = 0, + + // The file is directly accessed by the game and this is the full path + k_ERemoteStorageFilePathType_Absolute = 1, + + // The file is accessed via the ISteamRemoteStorage API and this is the filename + k_ERemoteStorageFilePathType_APIFilename = 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; + + // 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; + + // Cloud dynamic state change notification + virtual int32 GetLocalFileChangeCount() = 0; + virtual const char *GetLocalFileChange( int iFile, ERemoteStorageLocalFileChange *pEChangeType, ERemoteStorageFilePathType *pEFilePathType ) = 0; + + // Indicate to Steam the beginning / end of a set of local file + // operations - for example, writing a game save that requires updating two files. + virtual bool BeginFileWriteBatch() = 0; + virtual bool EndFileWriteBatch() = 0; +}; + +#define STEAMREMOTESTORAGE_INTERFACE_VERSION "STEAMREMOTESTORAGE_INTERFACE_VERSION016" + +// 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: The result of a call to FileShare() +//----------------------------------------------------------------------------- +struct RemoteStorageFileShareResult_t +{ + enum { k_iCallback = k_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 8 is deprecated! Do not reuse + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to PublishFile() +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileResult_t +{ + enum { k_iCallback = k_iSteamRemoteStorageCallbacks + 9 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + +// k_iSteamRemoteStorageCallbacks + 10 is deprecated! Do not reuse + + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to DeletePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageDeletePublishedFileResult_t +{ + enum { k_iCallback = k_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 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_iSteamRemoteStorageCallbacks + 31 }; + EResult m_eResult; // result +}; + +//----------------------------------------------------------------------------- +// Purpose: Called when a FileReadAsync completes +//----------------------------------------------------------------------------- +struct RemoteStorageFileReadAsyncComplete_t +{ + enum { k_iCallback = k_iSteamRemoteStorageCallbacks + 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 +}; + +//----------------------------------------------------------------------------- +// Purpose: one or more files for this app have changed locally after syncing +// to remote session changes +// Note: only posted if this happens DURING the local app session +//----------------------------------------------------------------------------- +STEAM_CALLBACK_BEGIN( RemoteStorageLocalFileChange_t, k_iSteamRemoteStorageCallbacks + 33 ) +STEAM_CALLBACK_END( 0 ) + +#pragma pack( pop ) + + +#endif // ISTEAMREMOTESTORAGE_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamScreenshots.h b/Amalgam/src/SDK/Definitions/Steam/ISteamScreenshots.h new file mode 100644 index 0000000..203fc90 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/ISteamUGC.h b/Amalgam/src/SDK/Definitions/Steam/ISteamUGC.h new file mode 100644 index 0000000..e568708 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamUGC.h @@ -0,0 +1,618 @@ +//====== 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, // @note: will only be valid for CreateQueryUserUGCRequest requests +}; + +// 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, + k_EUGCQuery_RankedByLastUpdatedDate = 19, +}; + +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 +}; + +enum EUGCContentDescriptorID +{ + k_EUGCContentDescriptor_NudityOrSexualContent = 1, + k_EUGCContentDescriptor_FrequentViolenceOrGore = 2, + k_EUGCContentDescriptor_AdultOnlySexualContent = 3, + k_EUGCContentDescriptor_GratuitousSexualContent = 4, + k_EUGCContentDescriptor_AnyMatureContent = 5, +}; + +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. + STEAM_FLAT_NAME( CreateQueryAllUGCRequestPage ) + 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. + STEAM_FLAT_NAME( CreateQueryAllUGCRequestCursor ) + 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 uint32 GetQueryUGCNumTags( UGCQueryHandle_t handle, uint32 index ) = 0; + virtual bool GetQueryUGCTag( UGCQueryHandle_t handle, uint32 index, uint32 indexTag, STEAM_OUT_STRING_COUNT( cchValueSize ) char* pchValue, uint32 cchValueSize ) = 0; + virtual bool GetQueryUGCTagDisplayName( UGCQueryHandle_t handle, uint32 index, uint32 indexTag, STEAM_OUT_STRING_COUNT( cchValueSize ) char* pchValue, uint32 cchValueSize ) = 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. + STEAM_FLAT_NAME( GetQueryFirstUGCKeyValueTag ) + virtual bool GetQueryUGCKeyValueTag( UGCQueryHandle_t handle, uint32 index, const char *pchKey, STEAM_OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) = 0; + + virtual uint32 GetQueryUGCContentDescriptors( UGCQueryHandle_t handle, uint32 index, EUGCContentDescriptorID *pvecDescriptors, uint32 cMaxEntries ) = 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 AddRequiredTagGroup( UGCQueryHandle_t handle, const SteamParamStringArray_t *pTagGroups ) = 0; // match any of the tags in this group + 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 SetTimeCreatedDateRange( UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd ) = 0; + virtual bool SetTimeUpdatedDateRange( UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd ) = 0; + virtual bool AddRequiredKeyValueTag( UGCQueryHandle_t handle, const char *pKey, const char *pValue ) = 0; + + // DEPRECATED - Use CreateQueryUGCDetailsRequest call above instead! + STEAM_CALL_RESULT( SteamUGCRequestUGCDetailsResult_t ) + 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) + virtual bool AddContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid ) = 0; + virtual bool RemoveContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid ) = 0; + + 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; + + // Show the app's latest Workshop EULA to the user in an overlay window, where they can accept it or not + virtual bool ShowWorkshopEULA() = 0; + // Retrieve information related to the user's acceptance or not of the app's specific Workshop EULA + STEAM_CALL_RESULT( WorkshopEULAStatus_t ) + virtual SteamAPICall_t GetWorkshopEULAStatus() = 0; +}; + +#define STEAMUGC_INTERFACE_VERSION "STEAMUGC_INTERFACE_VERSION017" + +// 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 10 }; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to StopPlaytimeTracking() +//----------------------------------------------------------------------------- +struct StopPlaytimeTrackingResult_t +{ + enum { k_iCallback = k_iSteamUGCCallbacks + 11 }; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to AddDependency +//----------------------------------------------------------------------------- +struct AddUGCDependencyResult_t +{ + enum { k_iCallback = k_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 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_iSteamUGCCallbacks + 17 }; + EResult m_eResult; + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: signal that the list of subscribed items changed +//----------------------------------------------------------------------------- +struct UserSubscribedItemsListChanged_t +{ + enum { k_iCallback = k_iSteamUGCCallbacks + 18 }; + AppId_t m_nAppID; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Status of the user's acceptable/rejection of the app's specific Workshop EULA +//----------------------------------------------------------------------------- +struct WorkshopEULAStatus_t +{ + enum { k_iCallback = k_iSteamUGCCallbacks + 20 }; + EResult m_eResult; + AppId_t m_nAppID; + uint32 m_unVersion; + RTime32 m_rtAction; + bool m_bAccepted; + bool m_bNeedsAction; +}; + +#pragma pack( pop ) + +#endif // ISTEAMUGC_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamUser.h b/Amalgam/src/SDK/Definitions/Steam/ISteamUser.h new file mode 100644 index 0000000..668c70c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamUser.h @@ -0,0 +1,439 @@ +//====== 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" + +//----------------------------------------------------------------------------- +// 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. + // + // DEPRECATED! This function will be removed from the SDK in an upcoming version. + // Please migrate to BeginAuthSession and related functions. + virtual int InitiateGameConnection_DEPRECATED( 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 + // + // DEPRECATED! This function will be removed from the SDK in an upcoming version. + // Please migrate to BeginAuthSession and related functions. + virtual void TerminateGameConnection_DEPRECATED( 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. + // SteamNetworkingIdentity is an optional input parameter to hold the public IP address or SteamID of the entity you are connecting to + // if an IP address is passed Steam will only allow the ticket to be used by an entity with that IP address + // if a Steam ID is passed Steam will only allow the ticket to be used by that Steam ID + // not to be used for "ISteamUserAuth\AuthenticateUserTicket" - it will fail + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, const SteamNetworkingIdentity *pSteamNetworkingIdentity ) = 0; + + // Request a ticket which will be used for webapi "ISteamUserAuth\AuthenticateUserTicket" + // pchIdentity is an optional input parameter to identify the service the ticket will be sent to + // the ticket will be returned in callback GetTicketForWebApiResponse_t + virtual HAuthTicket GetAuthTicketForWebApi( const char *pchIdentity ) = 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; + + // Retrieves a finished ticket. + // If no ticket is available, or your buffer is too small, returns false. + // Upon exit, *pcbTicket will be either the size of the ticket copied into your buffer + // (if true was returned), or the size needed (if false was returned). To determine the + // proper size of the ticket, you can pass pTicket=NULL and cbMaxTicket=0; if a ticket + // is available, *pcbTicket will contain the size needed, otherwise it will be zero. + 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; + + // Advise steam china duration control system about the online state of the game. + // This will prevent offline gameplay time from counting against a user's + // playtime limits. + virtual bool BSetDurationControlOnlineState( EDurationControlOnlineState eNewState ) = 0; + +}; + +#define STEAMUSER_INTERFACE_VERSION "SteamUser023" + +// 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 an authenticated connection 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 the user can keep playing or +// whether the game should exit, and returns info about remaining gameplay time. +// +// 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 since most recent 5 hour gap in playtime, only counting up to regulatory limit of playtime, in seconds + + EDurationControlProgress m_progress; // recommended progress (either everything is fine, or please exit game) + EDurationControlNotification m_notification; // notification to show, if any (always k_EDurationControlNotification_None for API calls) + + int32 m_csecsToday; // playtime on current calendar day + int32 m_csecsRemaining; // playtime remaining until the user hits a regulatory limit +}; + + +//----------------------------------------------------------------------------- +// callback for GetTicketForWebApi +//----------------------------------------------------------------------------- +struct GetTicketForWebApiResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 68 }; + HAuthTicket m_hAuthTicket; + EResult m_eResult; + int m_cubTicket; + static const int k_nCubTicketMaxLength = 2560; + uint8 m_rgubTicket[k_nCubTicketMaxLength]; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMUSER_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamUserStats.h b/Amalgam/src/SDK/Definitions/Steam/ISteamUserStats.h new file mode 100644 index 0000000..c7c772a --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamUserStats.h @@ -0,0 +1,487 @@ +//====== 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 + STEAM_FLAT_NAME( GetStatInt32 ) + virtual bool GetStat( const char *pchName, int32 *pData ) = 0; + + STEAM_FLAT_NAME( GetStatFloat ) + virtual bool GetStat( const char *pchName, float *pData ) = 0; + + // Set / update data + STEAM_FLAT_NAME( SetStatInt32 ) + virtual bool SetStat( const char *pchName, int32 nData ) = 0; + + STEAM_FLAT_NAME( SetStatFloat ) + 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() + STEAM_FLAT_NAME( GetUserStatInt32 ) + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + + STEAM_FLAT_NAME( GetUserStatFloat ) + 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_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 + STEAM_FLAT_NAME( GetGlobalStatInt64 ) + virtual bool GetGlobalStat( const char *pchStatName, int64 *pData ) = 0; + + STEAM_FLAT_NAME( GetGlobalStatDouble ) + 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. + + STEAM_FLAT_NAME( GetGlobalStatHistoryInt64 ) + virtual int32 GetGlobalStatHistory( const char *pchStatName, STEAM_ARRAY_COUNT(cubData) int64 *pData, uint32 cubData ) = 0; + + STEAM_FLAT_NAME( GetGlobalStatHistoryDouble ) + virtual int32 GetGlobalStatHistory( const char *pchStatName, STEAM_ARRAY_COUNT(cubData) double *pData, uint32 cubData ) = 0; + + // For achievements that have related Progress stats, use this to query what the bounds of that progress are. + // You may want this info to selectively call IndicateAchievementProgress when appropriate milestones of progress + // have been made, to show a progress notification to the user. + STEAM_FLAT_NAME( GetAchievementProgressLimitsInt32 ) + virtual bool GetAchievementProgressLimits( const char *pchName, int32 *pnMinProgress, int32 *pnMaxProgress ) = 0; + + STEAM_FLAT_NAME( GetAchievementProgressLimitsFloat ) + virtual bool GetAchievementProgressLimits( const char *pchName, float *pfMinProgress, float *pfMaxProgress ) = 0; + +}; + +#define STEAMUSERSTATS_INTERFACE_VERSION "STEAMUSERSTATS_INTERFACE_VERSION012" + +// 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/Amalgam/src/SDK/Definitions/Steam/ISteamUtils.h b/Amalgam/src/SDK/Definitions/Steam/ISteamUtils.h new file mode 100644 index 0000000..93ca6ad --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/ISteamUtils.h @@ -0,0 +1,340 @@ +//====== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to utility functions in Steam +// +//============================================================================= + +#ifndef ISTEAMUTILS_H +#define ISTEAMUTILS_H + +#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 +}; + +enum EFloatingGamepadTextInputMode +{ + k_EFloatingGamepadTextInputModeModeSingleLine = 0, // Enter dismisses the keyboard + k_EFloatingGamepadTextInputModeModeMultipleLines = 1, // User needs to explictly close the keyboard + k_EFloatingGamepadTextInputModeModeEmail = 2, // Keyboard layout is email, enter dismisses the keyboard + k_EFloatingGamepadTextInputModeModeNumeric = 3, // Keyboard layout is numeric, enter dismisses the keyboard + +}; + +// The context where text filtering is being done +enum ETextFilteringContext +{ + k_ETextFilteringContextUnknown = 0, // Unknown context + k_ETextFilteringContextGameContent = 1, // Game content, only legally required filtering is performed + k_ETextFilteringContextChat = 2, // Chat from another player + k_ETextFilteringContextName = 3, // Character or item name +}; + + +//----------------------------------------------------------------------------- +// 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; + + // Deprecated. Do not call this. + STEAM_PRIVATE_API( 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 full-screen text input dialog which takes a initial text string and returns the text the user has typed + 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 Remote Play + virtual bool IsVRHeadsetStreamingEnabled() = 0; + + // Set whether the HMD content will be streamed via Steam Remote Play + // 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, loading dictionaries for the language the game is running in. + // unFilterOptions are reserved for future use and should be set to 0 + // Returns false if filtering is unavailable for the game's language, in which case FilterText() will act as a passthrough. + // + // Users can customize the text filter behavior in their Steam Account preferences: + // https://store.steampowered.com/account/preferences#CommunityContentPreferences + virtual bool InitFilterText( uint32 unFilterOptions = 0 ) = 0; + + // Filters the provided input message and places the filtered result into pchOutFilteredText, using legally required filtering and additional filtering based on the context and user settings + // eContext is the type of content in the input string + // sourceSteamID is the Steam ID that is the source of the input string (e.g. the player with the name, or who said the chat text) + // pchInputText is the input string that should be filtered, which can be ASCII or UTF-8 + // pchOutFilteredText is where the output will be placed, even if no filtering is performed + // nByteSizeOutFilteredText is the size (in bytes) of pchOutFilteredText, should be at least strlen(pchInputText)+1 + // Returns the number of characters (not bytes) filtered + virtual int FilterText( ETextFilteringContext eContext, CSteamID sourceSteamID, const char *pchInputMessage, char *pchOutFilteredText, uint32 nByteSizeOutFilteredText ) = 0; + + // Return what we believe your current ipv6 connectivity to "the internet" is on the specified protocol. + // This does NOT tell you if the Steam client is currently connected to Steam via ipv6. + virtual ESteamIPv6ConnectivityState GetIPv6ConnectivityState( ESteamIPv6ConnectivityProtocol eProtocol ) = 0; + + // returns true if currently running on the Steam Deck device + virtual bool IsSteamRunningOnSteamDeck() = 0; + + // Opens a floating keyboard over the game content and sends OS keyboard keys directly to the game. + // The text field position is specified in pixels relative the origin of the game window and is used to position the floating keyboard in a way that doesn't cover the text field + virtual bool ShowFloatingGamepadTextInput( EFloatingGamepadTextInputMode eKeyboardMode, int nTextFieldXPosition, int nTextFieldYPosition, int nTextFieldWidth, int nTextFieldHeight ) = 0; + + // In game launchers that don't have controller support you can call this to have Steam Input translate the controller input into mouse/kb to navigate the launcher + virtual void SetGameLauncherMode( bool bLauncherMode ) = 0; + + // Dismisses the floating keyboard. + virtual bool DismissFloatingGamepadTextInput() = 0; +}; + +#define STEAMUTILS_INTERFACE_VERSION "SteamUtils010" + +// Global interface accessor +inline ISteamUtils *SteamUtils(); +STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamUtils *, SteamUtils, SteamInternal_FindOrCreateUserInterface( 0, STEAMUTILS_INTERFACE_VERSION ), "user", STEAMUTILS_INTERFACE_VERSION ); + +// Global accessor for the gameserver client +inline ISteamUtils *SteamGameServerUtils(); +STEAM_DEFINE_INTERFACE_ACCESSOR( ISteamUtils *, SteamGameServerUtils, SteamInternal_FindOrCreateGameServerInterface( 0, STEAMUTILS_INTERFACE_VERSION ), "gameserver", 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 + + +//----------------------------------------------------------------------------- +// Full Screen 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; + AppId_t m_unAppID; +}; + +// k_iSteamUtilsCallbacks + 15 through 35 are taken + +STEAM_CALLBACK_BEGIN( AppResumingFromSuspend_t, k_iSteamUtilsCallbacks + 36 ) +STEAM_CALLBACK_END(0) + +// k_iSteamUtilsCallbacks + 37 is taken + +//----------------------------------------------------------------------------- +// The floating on-screen keyboard has been closed +//----------------------------------------------------------------------------- +struct FloatingGamepadTextInputDismissed_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 38 }; +}; + +//----------------------------------------------------------------------------- +// The text filtering dictionary has changed +//----------------------------------------------------------------------------- +struct FilterTextDictionaryChanged_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 39 }; + int m_eLanguage; // One of ELanguage, or k_LegallyRequiredFiltering +}; + +#pragma pack( pop ) + +#endif // ISTEAMUTILS_H diff --git a/Amalgam/src/SDK/Definitions/Steam/ISteamVideo.h b/Amalgam/src/SDK/Definitions/Steam/ISteamVideo.h new file mode 100644 index 0000000..ccd0749 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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_iSteamVideoCallbacks + 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_iSteamVideoCallbacks + 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/Amalgam/src/SDK/Definitions/Steam/MatchmakingTypes.h b/Amalgam/src/SDK/Definitions/Steam/MatchmakingTypes.h new file mode 100644 index 0000000..23c8d79 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/MatchmakingTypes.h @@ -0,0 +1,231 @@ +//========= Copyright � 1996-2008, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef MATCHMAKINGTYPES_H +#define MATCHMAKINGTYPES_H + +#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_s( 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_s( 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 ); + + // 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 unIP ); + + // 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; +} + +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_s( m_szServerName, pName, sizeof( m_szServerName ) ); + m_szServerName[ sizeof( m_szServerName ) - 1 ] = '\0'; +} + + +#endif // MATCHMAKINGTYPES_H diff --git a/Amalgam/src/SDK/Definitions/Steam/SteamClientPublic.h b/Amalgam/src/SDK/Definitions/Steam/SteamClientPublic.h new file mode 100644 index 0000000..382e883 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/SteamClientPublic.h @@ -0,0 +1,1186 @@ +//========= Copyright � 1996-2008, Valve LLC, All rights reserved. ============ +// +// Declare common types used by the Steamworks SDK. +// +//============================================================================= + +#ifndef STEAMCLIENTPUBLIC_H +#define STEAMCLIENTPUBLIC_H + +#include "SteamTypes.h" +#include "SteamUniverse.h" + +// General result codes +enum EResult +{ + k_EResultNone = 0, // no result + 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 - partner site specific + 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 + k_EResultAccountDeleted = 114, // account has been deleted + k_EResultExistingUserCancelledLicense = 115, // A license for this already exists, but cancelled + k_EResultCommunityCooldown = 116, // access is denied because of a community cooldown (probably from support profile data resets) + k_EResultNoLauncherSpecified = 117, // No launcher was specified, but a launcher was needed to choose correct realm for operation. + k_EResultMustAgreeToSSA = 118, // User must agree to china SSA or global SSA before login + k_EResultLauncherMigrated = 119, // The specified launcher type is no longer supported; the user should be directed elsewhere + k_EResultSteamRealmMismatch = 120, // The user's realm does not match the realm of the requested resource + k_EResultInvalidSignature = 121, // signature check did not match + k_EResultParseFailure = 122, // Failed to parse input + k_EResultNoVerifiedPhone = 123, // account does not have a verified phone number + k_EResultInsufficientBattery = 124, // user device doesn't have enough battery charge currently to complete the action + k_EResultChargerRequired = 125, // The operation requires a charger to be plugged in, which wasn't present + k_EResultCachedCredentialInvalid = 126, // Cached credential was invalid - user must reauthenticate + K_EResultPhoneNumberIsVOIP = 127, // The phone number provided is a Voice Over IP number +}; + +// 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 + k_EAuthSessionResponseAuthTicketNetworkIdentityFailure = 10, // The network identity in the ticket does not match the server authenticating the ticket +}; + +// 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: 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 +}; + + +const unsigned int k_unSteamAccountIDMask = 0xFFFFFFFF; +const unsigned int k_unSteamAccountInstanceMask = 0x000FFFFF; +const unsigned int k_unSteamUserDefaultInstance = 1; // fixed instance for all individual users + +// 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: Possible positions to tell the overlay to show notifications in +//----------------------------------------------------------------------------- +enum ENotificationPosition +{ + k_EPositionInvalid = -1, + 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: 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. +// +// WARNING: DO NOT RENUMBER +enum EDurationControlProgress +{ + k_EDurationControlProgress_Full = 0, // Full progress + k_EDurationControlProgress_Half = 1, // deprecated - XP or persistent rewards should be halved + k_EDurationControlProgress_None = 2, // deprecated - XP or persistent rewards should be stopped + + k_EDurationControl_ExitSoon_3h = 3, // allowed 3h time since 5h gap/break has elapsed, game should exit - steam will terminate the game soon + k_EDurationControl_ExitSoon_5h = 4, // allowed 5h time in calendar day has elapsed, game should exit - steam will terminate the game soon + k_EDurationControl_ExitSoon_Night = 5, // game running after day period, game should exit - steam will terminate the game soon +}; + + +// +// describes which notification timer has expired, for steam china duration control feature +// +// WARNING: DO NOT RENUMBER +enum EDurationControlNotification +{ + k_EDurationControlNotification_None = 0, // just informing you about progress, no notification to show + k_EDurationControlNotification_1Hour = 1, // "you've been playing for N hours" + + k_EDurationControlNotification_3Hours = 2, // deprecated - "you've been playing for 3 hours; take a break" + k_EDurationControlNotification_HalfProgress = 3,// deprecated - "your XP / progress is half normal" + k_EDurationControlNotification_NoProgress = 4, // deprecated - "your XP / progress is zero" + + k_EDurationControlNotification_ExitSoon_3h = 5, // allowed 3h time since 5h gap/break has elapsed, game should exit - steam will terminate the game soon + k_EDurationControlNotification_ExitSoon_5h = 6, // allowed 5h time in calendar day has elapsed, game should exit - steam will terminate the game soon + k_EDurationControlNotification_ExitSoon_Night = 7,// game running after day period, game should exit - steam will terminate the game soon +}; + + +// +// Specifies a game's online state in relation to duration control +// +enum EDurationControlOnlineState +{ + k_EDurationControlOnlineState_Invalid = 0, // nil value + k_EDurationControlOnlineState_Offline = 1, // currently in offline play - single-player, offline co-op, etc. + k_EDurationControlOnlineState_Online = 2, // currently in online play + k_EDurationControlOnlineState_OnlineHighPri = 3, // currently in online play and requests not to be interrupted +}; + + +#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_unSteamUserDefaultInstance ) ); // 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 + { + m_steamid.m_comp.m_unAccountInstance = k_unSteamUserDefaultInstance; + } + } + + + //----------------------------------------------------------------------------- + // 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; + } + + //----------------------------------------------------------------------------- + // 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; } + + 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 ); + + 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_unSteamUserDefaultInstance ) + 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; +} + +#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 +//----------------------------------------------------------------------------- +inline CSteamID SteamIDFromSteam2UserID( TSteamGlobalUserID *pTSteamGlobalUserID, EUniverse eUniverse ) +{ + uint32 unAccountID = pTSteamGlobalUserID->m_SteamLocalUserID.Split.Low32bits * 2 + + pTSteamGlobalUserID->m_SteamLocalUserID.Split.High32bits; + + return CSteamID( unAccountID, k_unSteamUserDefaultInstance, eUniverse, k_EAccountTypeIndividual ); +} + +bool SteamIDFromSteam2String( const char *pchSteam2ID, EUniverse eUniverse, CSteamID *pSteamIDOut ); + +//----------------------------------------------------------------------------- +// Purpose: Fills out a Steam2 ID structure +// Input: pTSteamGlobalUserID - Steam2 ID to write to +//----------------------------------------------------------------------------- +inline TSteamGlobalUserID SteamIDToSteam2UserID( CSteamID steamID ) +{ + TSteamGlobalUserID steamGlobalUserID; + + steamGlobalUserID.m_SteamInstanceID = 0; + steamGlobalUserID.m_SteamLocalUserID.Split.High32bits = steamID.GetAccountID() % 2; + steamGlobalUserID.m_SteamLocalUserID.Split.Low32bits = steamID.GetAccountID() / 2; + + return steamGlobalUserID; +} + + +#endif + +// 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: + + enum EGameIDType + { + k_EGameIDTypeApp = 0, + k_EGameIDTypeGameMod = 1, + k_EGameIDTypeShortcut = 2, + k_EGameIDTypeP2P = 3, + }; + + 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; + } + + // Not validating anything .. use IsValid() + explicit CGameID( uint32 nAppID, uint32 nModID, CGameID::EGameIDType nType ) + { + m_gameID.m_nAppID = nAppID; + m_gameID.m_nModID = nModID; + m_gameID.m_nType = nType; + } + + CGameID( const CGameID &that ) + { + m_ulGameID = that.m_ulGameID; + } + + CGameID& operator=( const CGameID & that ) + { + m_ulGameID = that.m_ulGameID; + return *this; + } + + // 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 + + 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; + } + +#if !defined(VALVE_SHORTCUT_DEBUG) + uint32 AppID( bool = false ) const + { + return m_gameID.m_nAppID; + } +#else + uint32 AppID( bool bShortcutOK = false ) const; +#endif + + 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_nAppID == k_uAppIdInvalid + && (m_gameID.m_nModID & 0x80000000) + && m_gameID.m_nModID >= (5000 | 0x80000000); // k_unMaxExpectedLocalAppId - shortcuts are pushed beyond that range + + case k_EGameIDTypeP2P: + return m_gameID.m_nAppID == k_uAppIdInvalid && (m_gameID.m_nModID & 0x80000000); + + default: + return false; + } + + } + + void Reset() + { + m_ulGameID = 0; + } + +// +// Internal stuff. Use the accessors above if possible +// + + 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; + }; + + friend CGameID GameIDFromAppAndModPath( uint32 nAppID, const char *pchModPath ); +}; + +#pragma pack( pop ) + +const int k_cchGameExtraInfoMax = 64; + + +//----------------------------------------------------------------------------- +// 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); + +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 +}; + + +enum ESteamIPv6ConnectivityProtocol +{ + k_ESteamIPv6ConnectivityProtocol_Invalid = 0, + k_ESteamIPv6ConnectivityProtocol_HTTP = 1, // because a proxy may make this different than other protocols + k_ESteamIPv6ConnectivityProtocol_UDP = 2, // test UDP connectivity. Uses a port that is commonly needed for other Steam stuff. If UDP works, TCP probably works. +}; + +// For the above transport protocol, what do we think the local machine's connectivity to the internet over ipv6 is like +enum ESteamIPv6ConnectivityState +{ + k_ESteamIPv6ConnectivityState_Unknown = 0, // We haven't run a test yet + k_ESteamIPv6ConnectivityState_Good = 1, // We have recently been able to make a request on ipv6 for the given protocol + k_ESteamIPv6ConnectivityState_Bad = 2, // We failed to make a request, either because this machine has no ipv6 address assigned, or it has no upstream connectivity +}; + + +// 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__) || defined(__FreeBSD__) +// 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/Amalgam/src/SDK/Definitions/Steam/SteamEncryptedAppTicket.h b/Amalgam/src/SDK/Definitions/Steam/SteamEncryptedAppTicket.h new file mode 100644 index 0000000..4b0d2a4 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/SteamEncryptedAppTicket.h @@ -0,0 +1,40 @@ +//========= 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 bool SteamEncryptedAppTicket_BGetAppDefinedValue( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted, uint32 *pValue ); + +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 ); + +S_API bool SteamEncryptedAppTicket_BIsLicenseBorrowed( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted ); + +S_API bool SteamEncryptedAppTicket_BIsLicenseTemporary( uint8 *rgubTicketDecrypted, uint32 cubTicketDecrypted ); diff --git a/Amalgam/src/SDK/Definitions/Steam/SteamHTTPEnums.h b/Amalgam/src/SDK/Definitions/Steam/SteamHTTPEnums.h new file mode 100644 index 0000000..21b03a7 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/SteamHTTPEnums.h @@ -0,0 +1,100 @@ +//====== 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, + k_EHTTPStatusCode308PermanentRedirect = 308, + + // 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, + k_EHTTPStatusCode444ConnectionClosed = 444, // nginx only? + + // 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/Amalgam/src/SDK/Definitions/Steam/SteamNetworkingFakeIP.h b/Amalgam/src/SDK/Definitions/Steam/SteamNetworkingFakeIP.h new file mode 100644 index 0000000..a7f7165 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/SteamNetworkingFakeIP.h @@ -0,0 +1,135 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== + +#ifndef STEAMNETWORKINGFAKEIP_H +#define STEAMNETWORKINGFAKEIP_H +#pragma once + +#include "SteamNetworkingTypes.h" +#include "Steam_API_Common.h" + +// It is HIGHLY recommended to limit messages sent via Fake UDP port to this +// value. The purpose of a Fake UDP port is to make porting ordinary ad-hoc UDP +// code easier. Although the real MTU might be higher than this, this particular +// conservative value is chosen so that fragmentation won't be occurring and +// hiding performance problems from you. +constexpr int k_cbSteamNetworkingSocketsFakeUDPPortRecommendedMTU = 1200; + +// Messages larger than this size are not allowed and cannot be sent +// via Fake UDP port. +constexpr int k_cbSteamNetworkingSocketsFakeUDPPortMaxMessageSize = 4096; + +//----------------------------------------------------------------------------- +/// ISteamNetworkingFakeUDPPort +/// +/// Acts like a UDP port, sending and receiving datagrams addressed using +/// FakeIP addresses. +/// +/// See: ISteamNetworkingSockets::CreateFakeUDPPort + +class ISteamNetworkingFakeUDPPort +{ +public: + /// Destroy the object and cleanup any internal connections. + /// Note that this function call is not threadsafe with respect + /// to any other method of this interface. (However, in general + /// all other operations are threadsafe with respect to each other.) + virtual void DestroyFakeUDPPort() = 0; + + /// Send a datagram to the specified FakeIP. + /// + /// See ISteamNetworkingSockets::SendMessageToConnection for the meaning of + /// nSendFlags and possible return codes. + /// + /// Notes: + /// - datagrams larger than the underlying MTU are supported, but + /// reliable messages (k_nSteamNetworkingSend_Reliable) are not supported. + /// - You will usually want to use k_nSteamNetworkingSend_NoNagle + /// - k_EResultBusy is returned if this is a "server" port and the global + /// allocation has not yet completed. + /// - k_EResultIPNotFound will be returned if the address is a local/ephemeral + /// address and no existing connection can be found. This can happen if + /// the remote host contacted us without having a global address, and we + /// assigned them a random local address, and then the session with + /// that host timed out. + /// - When initiating communications, the first messages may be sent + /// via backend signaling, or otherwise delayed, while a route is found. + /// Expect the ping time to fluctuate during this period, and it's possible + /// that messages will be delivered out of order (which is also possible with + /// ordinary UDP). + virtual EResult SendMessageToFakeIP( const SteamNetworkingIPAddr &remoteAddress, const void *pData, uint32 cbData, int nSendFlags ) = 0; + + /// Receive messages on the port. + /// + /// Returns the number of messages returned into your array, up to nMaxMessages. + /// + /// SteamNetworkingMessage_t::m_identity in the returned message(s) will always contain + /// a FakeIP. See ISteamNetworkingUtils::GetRealIdentityForFakeIP. + virtual int ReceiveMessages( SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) = 0; + + /// Schedule the internal connection for a given peer to be cleaned up in a few seconds. + /// + /// Idle connections automatically time out, and so this is not strictly *necessary*, + /// but if you have reason to believe that you are done talking to a given peer for + /// a while, you can call this to speed up the timeout. If any remaining packets are + /// sent or received from the peer, the cleanup is canceled and the usual timeout + /// value is restored. Thus you will usually call this immediately after sending + /// or receiving application-layer "close connection" packets. + virtual void ScheduleCleanup( const SteamNetworkingIPAddr &remoteAddress ) = 0; +}; + +/// 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 + +/// A struct used to describe a "fake IP" we have been assigned to +/// use as an identifier. This callback is posted when +/// ISteamNetworkingSoockets::BeginAsyncRequestFakeIP completes. +/// See also ISteamNetworkingSockets::GetFakeIP +struct SteamNetworkingFakeIPResult_t +{ + enum { k_iCallback = k_iSteamNetworkingSocketsCallbacks + 3 }; + + /// Status/result of the allocation request. Possible failure values are: + /// - k_EResultBusy - you called GetFakeIP but the request has not completed. + /// - k_EResultInvalidParam - you called GetFakeIP with an invalid port index + /// - k_EResultLimitExceeded - You asked for too many ports, or made an + /// additional request after one had already succeeded + /// - k_EResultNoMatch - GetFakeIP was called, but no request has been made + /// + /// Note that, with the exception of k_EResultBusy (if you are polling), + /// it is highly recommended to treat all failures as fatal. + EResult m_eResult; + + /// Local identity of the ISteamNetworkingSockets object that made + /// this request and is assigned the IP. This is needed in the callback + /// in the case where there are multiple ISteamNetworkingSockets objects. + /// (E.g. one for the user, and another for the local gameserver). + SteamNetworkingIdentity m_identity; + + /// Fake IPv4 IP address that we have been assigned. NOTE: this + /// IP address is not exclusively ours! Steam tries to avoid sharing + /// IP addresses, but this may not always be possible. The IP address + /// may be currently in use by another host, but with different port(s). + /// The exact same IP:port address may have been used previously. + /// Steam tries to avoid reusing ports until they have not been in use for + /// some time, but this may not always be possible. + uint32 m_unIP; + + /// Port number(s) assigned to us. Only the first entries will contain + /// nonzero values. Entries corresponding to ports beyond what was + /// allocated for you will be zero. + /// + /// (NOTE: At the time of this writing, the maximum number of ports you may + /// request is 4.) + enum { k_nMaxReturnPorts = 8 }; + uint16 m_unPorts[k_nMaxReturnPorts]; +}; + +#pragma pack( pop ) + +#endif // _H diff --git a/Amalgam/src/SDK/Definitions/Steam/SteamNetworkingTypes.h b/Amalgam/src/SDK/Definitions/Steam/SteamNetworkingTypes.h new file mode 100644 index 0000000..61143d9 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/SteamNetworkingTypes.h @@ -0,0 +1,1794 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Purpose: misc networking utilities +// +//============================================================================= + +#ifndef STEAMNETWORKINGTYPES +#define STEAMNETWORKINGTYPES +#pragma once + +#include +#include +#include "SteamTypes.h" +#include "SteamClientPublic.h" + +//----------------------------------------------------------------------------- +// SteamNetworkingSockets config. +#if !defined(STEAMNETWORKINGSOCKETS_STANDALONELIB) && !defined(STEAMNETWORKINGSOCKETS_STEAMAPI) + #define STEAMNETWORKINGSOCKETS_STEAMAPI +#endif +//----------------------------------------------------------------------------- + +#ifdef NN_NINTENDO_SDK // We always static link on Nintendo + #define STEAMNETWORKINGSOCKETS_STATIC_LINK +#endif +#if defined( STEAMNETWORKINGSOCKETS_STATIC_LINK ) + #define STEAMNETWORKINGSOCKETS_INTERFACE extern "C" +#elif defined( STEAMNETWORKINGSOCKETS_FOREXPORT ) + #ifdef _WIN32 + #define STEAMNETWORKINGSOCKETS_INTERFACE extern "C" __declspec( dllexport ) + #else + #define STEAMNETWORKINGSOCKETS_INTERFACE extern "C" __attribute__((visibility("default"))) + #endif +#else + #ifdef _WIN32 + #define STEAMNETWORKINGSOCKETS_INTERFACE extern "C" __declspec( dllimport ) + #else + #define STEAMNETWORKINGSOCKETS_INTERFACE extern "C" + #endif +#endif + +#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; +struct SteamNetworkingMessagesSessionRequest_t; +struct SteamNetworkingMessagesSessionFailed_t; +struct SteamNetworkingFakeIPResult_t; + +typedef void (*FnSteamNetConnectionStatusChanged)( SteamNetConnectionStatusChangedCallback_t * ); +typedef void (*FnSteamNetAuthenticationStatusChanged)( SteamNetAuthenticationStatus_t * ); +typedef void (*FnSteamRelayNetworkStatusChanged)(SteamRelayNetworkStatus_t *); +typedef void (*FnSteamNetworkingMessagesSessionRequest)(SteamNetworkingMessagesSessionRequest_t *); +typedef void (*FnSteamNetworkingMessagesSessionFailed)(SteamNetworkingMessagesSessionFailed_t *); +typedef void (*FnSteamNetworkingFakeIPResult)(SteamNetworkingFakeIPResult_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". Unlike traditional +/// Berkeley sockets, a listen socket and a connection are two +/// different abstractions. +typedef uint32 HSteamListenSocket; +const HSteamListenSocket k_HSteamListenSocket_Invalid = 0; + +/// Handle used to identify a poll group, used to query many +/// connections at once efficiently. +typedef uint32 HSteamNetPollGroup; +const HSteamNetPollGroup k_HSteamNetPollGroup_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. + // Please 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 + k_ESteamNetworkingIdentityType_XboxPairwiseID = 17, // Publisher-specific user identity, as string + k_ESteamNetworkingIdentityType_SonyPSN = 18, // 64-bit ID + k_ESteamNetworkingIdentityType_GoogleStadia = 19, // 64-bit ID + //k_ESteamNetworkingIdentityType_NintendoNetworkServiceAccount, + //k_ESteamNetworkingIdentityType_EpicGameStore + //k_ESteamNetworkingIdentityType_WeGame + + // + // 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, +}; + +/// "Fake IPs" are assigned to hosts, to make it easier to interface with +/// older code that assumed all hosts will have an IPv4 address +enum ESteamNetworkingFakeIPType +{ + k_ESteamNetworkingFakeIPType_Invalid, // Error, argument was not even an IP address, etc. + k_ESteamNetworkingFakeIPType_NotFake, // Argument was a valid IP, but was not from the reserved "fake" range + k_ESteamNetworkingFakeIPType_GlobalIPv4, // Globally unique (for a given app) IPv4 address. Address space managed by Steam + k_ESteamNetworkingFakeIPType_LocalIPv4, // Locally unique IPv4 address. Address space managed by the local process. For internal use only; should not be shared! + + k_ESteamNetworkingFakeIPType__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 + /// + /// See also SteamNetworkingIdentityRender + 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 ); + + /// RFC4038, section 4.2 + struct IPv4MappedAddress { + uint64 m_8zeros; + uint16 m_0000; + uint16 m_ffff; + uint8 m_ip[ 4 ]; // NOTE: As bytes, i.e. network byte order + }; + + union + { + uint8 m_ipv6[ 16 ]; + IPv4MappedAddress m_ipv4; + }; + uint16 m_port; // Host byte order + + /// See if two addresses are identical + bool operator==(const SteamNetworkingIPAddr &x ) const; + + /// Classify address as FakeIP. This function never returns + /// k_ESteamNetworkingFakeIPType_Invalid. + ESteamNetworkingFakeIPType GetFakeIPType() const; + + /// Return true if we are a FakeIP + bool IsFakeIP() const { return GetFakeIPType() > k_ESteamNetworkingFakeIPType_NotFake; } +}; + +/// An abstract way to represent the identity of a network host. All identities can +/// be represented as simple string. Furthermore, this string representation is actually +/// used on the wire in several places, even though it is less efficient, in order to +/// facilitate forward compatibility. (Old client code can handle an identity type that +/// it doesn't understand.) +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 + + bool SetXboxPairwiseID( const char *pszString ); // Returns false if invalid length + const char *GetXboxPairwiseID() const; // Returns nullptr if not Xbox ID + + void SetPSNID( uint64 id ); + uint64 GetPSNID() const; // Returns 0 if not PSN + + void SetStadiaID( uint64 id ); + uint64 GetStadiaID() const; // Returns 0 if not Stadia + + void SetIPAddr( const SteamNetworkingIPAddr &addr ); // Set to specified IP:port + const SteamNetworkingIPAddr *GetIPAddr() const; // returns null if we are not an IP address. + void SetIPv4Addr( uint32 nIPv4, uint16 nPort ); // Set to specified IPv4:port + uint32 GetIPv4() const; // returns 0 if we are not an IPv4 address. + + ESteamNetworkingFakeIPType GetFakeIPType() const; + bool IsFakeIP() const { return GetFakeIPType() > k_ESteamNetworkingFakeIPType_NotFake; } + + // "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. + /// + /// See also SteamNetworkingIPAddrRender + void ToString( char *buf, size_t cbBuf ) const; + + /// Parse back a string that was generated using ToString. If we don't understand the + /// string, but it looks "reasonable" (it matches the pattern type: and doesn't + /// have any funky characters, etc), then we will return true, and the type is set to + /// k_ESteamNetworkingIdentityType_UnknownType. false will only be returned if the string + /// looks invalid. + 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_cchMaxXboxPairwiseID = 33, // 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; + uint64 m_PSNID; + uint64 m_stadiaID; + char m_szGenericString[ k_cchMaxGenericString ]; + char m_szXboxPairwiseID[ k_cchMaxXboxPairwiseID ]; + 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 SDR 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, + + // ICE P2P rendezvous failed because we were not able to + // determine our "public" address (e.g. reflexive address via STUN) + // + // If relay fallback is available (it always is on Steam), then + // this is only used internally and will not be returned as a high + // level failure. + k_ESteamNetConnectionEnd_Local_P2P_ICE_NoPublicAddresses = 3006, + + 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, + + // These will never be returned + //k_ESteamNetConnectionEnd_Remote_NotLoggedIn_DEPRECATED = 4004, + //k_ESteamNetConnectionEnd_Remote_NotRunningApp_DEPRECATED = 4005, + + // Something wrong with the protocol version you are using. + // (Probably the code you are running is too old.) + k_ESteamNetConnectionEnd_Remote_BadProtocolVersion = 4006, + + // NAT punch failed failed because we never received any public + // addresses from the remote host. (But we did receive some + // signals form them.) + // + // If relay fallback is available (it always is on Steam), then + // this is only used internally and will not be returned as a high + // level failure. + k_ESteamNetConnectionEnd_Remote_P2P_ICE_NoPublicAddresses = 4007, + + 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, + + //k_ESteamNetConnectionEnd_Misc_RelayConnectivity_DEPRECATED = 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, + + // While trying to initiate a connection, we never received + // *any* communication from the peer. + //k_ESteamNetConnectionEnd_Misc_ServerNeverReplied = 5007, + + // P2P rendezvous failed in a way that we don't have more specific + // information + k_ESteamNetConnectionEnd_Misc_P2P_Rendezvous = 5008, + + // NAT punch failed, probably due to NAT/firewall configuration. + // + // If relay fallback is available (it always is on Steam), then + // this is only used internally and will not be returned as a high + // level failure. + k_ESteamNetConnectionEnd_Misc_P2P_NAT_Firewall = 5009, + + // Our peer replied that it has no record of the connection. + // This should not happen ordinarily, but can happen in a few + // exception cases: + // + // - This is an old connection, and the peer has already cleaned + // up and forgotten about it. (Perhaps it timed out and they + // closed it and were not able to communicate this to us.) + // - A bug or internal protocol error has caused us to try to + // talk to the peer about the connection before we received + // confirmation that the peer has accepted the connection. + // - The peer thinks that we have closed the connection for some + // reason (perhaps a bug), and believes that is it is + // acknowledging our closure. + k_ESteamNetConnectionEnd_Misc_PeerSentNoConnection = 5010, + + 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; + +/// Max length of the app's part of the description +const int k_cchSteamNetworkingMaxConnectionAppName = 32; + +const int k_nSteamNetworkConnectionInfoFlags_Unauthenticated = 1; // We don't have a certificate for the remote host. +const int k_nSteamNetworkConnectionInfoFlags_Unencrypted = 2; // Information is being sent out over a wire unencrypted (by this library) +const int k_nSteamNetworkConnectionInfoFlags_LoopbackBuffers = 4; // Internal loopback buffers. Won't be true for localhost. (You can check the address to determine that.) This implies k_nSteamNetworkConnectionInfoFlags_FastLAN +const int k_nSteamNetworkConnectionInfoFlags_Fast = 8; // The connection is "fast" and "reliable". Either internal/localhost (check the address to find out), or the peer is on the same LAN. (Probably. It's based on the address and the ping time, this is actually hard to determine unambiguously). +const int k_nSteamNetworkConnectionInfoFlags_Relayed = 16; // The connection is relayed somehow (SDR or TURN). +const int k_nSteamNetworkConnectionInfoFlags_DualWifi = 32; // We're taking advantage of dual-wifi multi-path + +/// 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 internal connection ID, + /// connection type (and peer information), and any name + /// given to the connection by the app. This string is used in various + /// internal logging messages. + /// + /// Note that the connection ID *usually* matches the HSteamNetConnection + /// handle, but in certain cases with symmetric connections it might not. + char m_szConnectionDescription[ k_cchSteamNetworkingMaxConnectionDescription ]; + + /// Misc flags. Bitmask of k_nSteamNetworkConnectionInfoFlags_Xxxx + int m_nFlags; + + /// Internal stuff, room to change API easily + uint32 reserved[63]; +}; + +/// Quick connection state, pared down to something you could call +/// more frequently without it being too big of a perf hit. +struct SteamNetConnectionRealTimeStatus_t +{ + + /// 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 queued a message right now, approximately how long would that message + /// wait in the queue before we actually started putting its data on the wire in + /// a packet? + /// + /// 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. + /// + /// Ignoring multiple lanes, 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. + /// + /// This value is only valid if multiple lanes are not used. If multiple lanes are + /// in use, then the queue time will be different for each lane, and you must use + /// the value in SteamNetConnectionRealTimeLaneStatus_t. + /// + /// Nagle delay is ignored for the purposes of this calculation. + SteamNetworkingMicroseconds m_usecQueueTime; + + // Internal stuff, room to change API easily + uint32 reserved[16]; +}; + +/// Quick status of a particular lane +struct SteamNetConnectionRealTimeLaneStatus_t +{ + // Counters for this particular lane. See the corresponding variables + // in SteamNetConnectionRealTimeStatus_t + int m_cbPendingUnreliable; + int m_cbPendingReliable; + int m_cbSentUnackedReliable; + int _reservePad1; // Reserved for future use + + /// Lane-specific queue time. This value takes into consideration lane priorities + /// and weights, and how much data is queued in each lane, and attempts to predict + /// how any data currently queued will be sent out. + SteamNetworkingMicroseconds m_usecQueueTime; + + // Internal stuff, room to change API easily + uint32 reserved[10]; +}; + +#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. + int m_cbSize; + + /// For messages received on connections: what connection did this come from? + /// For outgoing messages: what connection to send it to? + /// Not used when using the ISteamNetworkingMessages interface + HSteamNetConnection m_conn; + + /// For inbound messages: Who sent this to us? + /// For outbound messages on connections: not used. + /// For outbound messages on the ad-hoc ISteamNetworkingMessages interface: who should we send this to? + SteamNetworkingIdentity m_identityPeer; + + /// For messages received on connections, this is 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. + /// + /// Not used when sending messages. + int64 m_nConnUserData; + + /// Local timestamp when the message was received + /// Not used for outbound messages. + SteamNetworkingMicroseconds m_usecTimeReceived; + + /// Message number assigned by the sender. This is not used for outbound + /// messages. Note that if multiple lanes are used, each lane has its own + /// message numbers, which are assigned sequentially, so messages from + /// different lanes will share the same numbers. + 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 the internal reference count and, if + /// it's zero, release the message. You should not set this function pointer, + /// or need to access this directly! Use the Release() function instead! + void (*m_pfnRelease)( SteamNetworkingMessage_t *pMsg ); + + /// When using ISteamNetworkingMessages, the channel number the message was received on + /// (Not used for messages sent or received on "connections") + int m_nChannel; + + /// Bitmask of k_nSteamNetworkingSend_xxx flags. + /// For received messages, only the k_nSteamNetworkingSend_Reliable bit is valid. + /// For outbound messages, all bits are relevant + int m_nFlags; + + /// Arbitrary user data that you can use when sending messages using + /// ISteamNetworkingUtils::AllocateMessage and ISteamNetworkingSockets::SendMessage. + /// (The callback you set in m_pfnFreeData might use this field.) + /// + /// Not used for received messages. + int64 m_nUserData; + + /// For outbound messages, which lane to use? See ISteamNetworkingSockets::ConfigureConnectionLanes. + /// For inbound messages, what lane was the message received on? + uint16 m_idxLane; + uint16 _pad1__; + + /// You MUST call this when you're done with the object, + /// to free up memory, etc. + inline void Release(); + + // For code compatibility, some accessors +#ifndef API_GEN + 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 +protected: + // Declare destructor protected. You should never need to declare a message + // object on the stack or create one yourself. + // - You will receive a pointer to a message object when you receive messages (e.g. ISteamNetworkingSockets::ReceiveMessagesOnConnection) + // - You can allocate a message object for efficient sending using ISteamNetworkingUtils::AllocateMessage + // - Call Release() to free the object + inline ~SteamNetworkingMessage_t() {} +}; + +// +// 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; + +// By default, message sending is queued, and the work of encryption and talking to +// the operating system sockets, etc is done on a service thread. This is usually a +// a performance win when messages are sent from the "main thread". However, if this +// flag is set, and data is ready to be sent immediately (either from this message +// or earlier queued data), then that work will be done in the current thread, before +// the current call returns. If data is not ready to be sent (due to rate limiting +// or Nagle), then this flag has no effect. +// +// This is an advanced flag used to control performance at a very low level. For +// most applications running on modern hardware with more than one CPU core, doing +// the work of sending on a service thread will yield the best performance. Only +// use this flag if you have a really good reason and understand what you are doing. +// Otherwise you will probably just make performance worse. +const int k_nSteamNetworkingSend_UseCurrentThread = 16; + +// When sending a message using ISteamNetworkingMessages, automatically re-establish +// a broken session, without returning k_EResultNoConnection. Without this flag, +// if you attempt to send a message, and the session was proactively closed by the +// peer, or an error occurred that disrupted communications, then you must close the +// session using ISteamNetworkingMessages::CloseSessionWithUser before attempting to +// send another message. (Or you can simply add this flag and retry.) In this way, +// the disruption cannot go unnoticed, and a more clear order of events can be +// ascertained. This is especially important when reliable messages are used, since +// if the connection is disrupted, some of those messages will not have been delivered, +// and it is in general not possible to know which. Although a +// SteamNetworkingMessagesSessionFailed_t callback will be posted when an error occurs +// to notify you that a failure has happened, callbacks are asynchronous, so it is not +// possible to tell exactly when it happened. And because the primary purpose of +// ISteamNetworkingMessages is to be like UDP, there is no notification when a peer closes +// the session. +// +// If you are not using any reliable messages (e.g. you are using ISteamNetworkingMessages +// exactly as a transport replacement for UDP-style datagrams only), you may not need to +// know when an underlying connection fails, and so you may not need this notification. +const int k_nSteamNetworkingSend_AutoRestartBrokenSession = 32; + +// +// 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_Ptr = 5, + + k_ESteamNetworkingConfigDataType__Force32Bit = 0x7fffffff +}; + +/// Configuration options +enum ESteamNetworkingConfigValue +{ + k_ESteamNetworkingConfig_Invalid = 0, + +// +// Connection options +// + + /// [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 int64] Get/set userdata as a configuration option. + /// The default value is -1. You may want to set the user data as + /// a config value, instead of using ISteamNetworkingSockets::SetConnectionUserData + /// in two specific instances: + /// + /// - You wish to set the userdata atomically when creating + /// an outbound connection, so that the userdata is filled in properly + /// for any callbacks that happen. However, note that this trick + /// only works for connections initiated locally! For incoming + /// connections, multiple state transitions may happen and + /// callbacks be queued, before you are able to service the first + /// callback! Be careful! + /// + /// - You can set the default userdata for all newly created connections + /// by setting this value at a higher level (e.g. on the listen + /// socket or at the global level.) Then this default + /// value will be inherited when the connection is created. + /// This is useful in case -1 is a valid userdata value, and you + /// wish to use something else as the default value so you can + /// tell if it has been set or not. + /// + /// HOWEVER: once a connection is created, the effective value is + /// then bound to the connection. Unlike other connection options, + /// if you change it again at a higher level, the new value will not + /// be inherited by connections. + /// + /// Using the userdata field in callback structs is not advised because + /// of tricky race conditions. Instead, you might try one of these methods: + /// + /// - Use a separate map with the HSteamNetConnection as the key. + /// - Fetch the userdata from the connection in your callback + /// using ISteamNetworkingSockets::GetConnectionUserData, to + // ensure you have the current value. + k_ESteamNetworkingConfig_ConnectionUserData = 40, + + /// [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.) + /// + /// This is a dev configuration value, and you should not let users modify it in + /// production. + 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, + + /// [connection int32] Allow unencrypted (and unauthenticated) communication. + /// 0: Not allowed (the default) + /// 1: Allowed, but prefer encrypted + /// 2: Allowed, and preferred + /// 3: Required. (Fail the connection if the peer requires encryption.) + /// + /// This is a dev configuration value, since its purpose is to disable encryption. + /// You should not let users modify it in production. (But note that it requires + /// the peer to also modify their value in order for encryption to be disabled.) + k_ESteamNetworkingConfig_Unencrypted = 34, + + /// [connection int32] Set this to 1 on outbound connections and listen sockets, + /// to enable "symmetric connect mode", which is useful in the following + /// common peer-to-peer use case: + /// + /// - The two peers are "equal" to each other. (Neither is clearly the "client" + /// or "server".) + /// - Either peer may initiate the connection, and indeed they may do this + /// at the same time + /// - The peers only desire a single connection to each other, and if both + /// peers initiate connections simultaneously, a protocol is needed for them + /// to resolve the conflict, so that we end up with a single connection. + /// + /// This use case is both common, and involves subtle race conditions and tricky + /// pitfalls, which is why the API has support for dealing with it. + /// + /// If an incoming connection arrives on a listen socket or via custom signaling, + /// and the application has not attempted to make a matching outbound connection + /// in symmetric mode, then the incoming connection can be accepted as usual. + /// A "matching" connection means that the relevant endpoint information matches. + /// (At the time this comment is being written, this is only supported for P2P + /// connections, which means that the peer identities must match, and the virtual + /// port must match. At a later time, symmetric mode may be supported for other + /// connection types.) + /// + /// If connections are initiated by both peers simultaneously, race conditions + /// can arise, but fortunately, most of them are handled internally and do not + /// require any special awareness from the application. However, there + /// is one important case that application code must be aware of: + /// If application code attempts an outbound connection using a ConnectXxx + /// function in symmetric mode, and a matching incoming connection is already + /// waiting on a listen socket, then instead of forming a new connection, + /// the ConnectXxx call will accept the existing incoming connection, and return + /// a connection handle to this accepted connection. + /// IMPORTANT: in this case, a SteamNetConnectionStatusChangedCallback_t + /// has probably *already* been posted to the queue for the incoming connection! + /// (Once callbacks are posted to the queue, they are not modified.) It doesn't + /// matter if the callback has not been consumed by the app. Thus, application + /// code that makes use of symmetric connections must be aware that, when processing a + /// SteamNetConnectionStatusChangedCallback_t for an incoming connection, the + /// m_hConn may refer to a new connection that the app has has not + /// seen before (the usual case), but it may also refer to a connection that + /// has already been accepted implicitly through a call to Connect()! In this + /// case, AcceptConnection() will return k_EResultDuplicateRequest. + /// + /// Only one symmetric connection to a given peer (on a given virtual port) + /// may exist at any given time. If client code attempts to create a connection, + /// and a (live) connection already exists on the local host, then either the + /// existing connection will be accepted as described above, or the attempt + /// to create a new connection will fail. Furthermore, linger mode functionality + /// is not supported on symmetric connections. + /// + /// A more complicated race condition can arise if both peers initiate a connection + /// at roughly the same time. In this situation, each peer will receive an incoming + /// connection from the other peer, when the application code has already initiated + /// an outgoing connection to that peer. The peers must resolve this conflict and + /// decide who is going to act as the "server" and who will act as the "client". + /// Typically the application does not need to be aware of this case as it is handled + /// internally. On both sides, the will observe their outbound connection being + /// "accepted", although one of them one have been converted internally to act + /// as the "server". + /// + /// In general, symmetric mode should be all-or-nothing: do not mix symmetric + /// connections with a non-symmetric connection that it might possible "match" + /// with. If you use symmetric mode on any connections, then both peers should + /// use it on all connections, and the corresponding listen socket, if any. The + /// behaviour when symmetric and ordinary connections are mixed is not defined by + /// this API, and you should not rely on it. (This advice only applies when connections + /// might possibly "match". For example, it's OK to use all symmetric mode + /// connections on one virtual port, and all ordinary, non-symmetric connections + /// on a different virtual port, as there is no potential for ambiguity.) + /// + /// When using the feature, you should set it in the following situations on + /// applicable objects: + /// + /// - When creating an outbound connection using ConnectXxx function + /// - When creating a listen socket. (Note that this will automatically cause + /// any accepted connections to inherit the flag.) + /// - When using custom signaling, before accepting an incoming connection. + /// + /// Setting the flag on listen socket and accepted connections will enable the + /// API to automatically deal with duplicate incoming connections, even if the + /// local host has not made any outbound requests. (In general, such duplicate + /// requests from a peer are ignored internally and will not be visible to the + /// application code. The previous connection must be closed or resolved first.) + k_ESteamNetworkingConfig_SymmetricConnect = 37, + + /// [connection int32] For connection types that use "virtual ports", this can be used + /// to assign a local virtual port. For incoming connections, this will always be the + /// virtual port of the listen socket (or the port requested by the remote host if custom + /// signaling is used and the connection is accepted), and cannot be changed. For + /// connections initiated locally, the local virtual port will default to the same as the + /// requested remote virtual port, if you do not specify a different option when creating + /// the connection. The local port is only relevant for symmetric connections, when + /// determining if two connections "match." In this case, if you need the local and remote + /// port to differ, you can set this value. + /// + /// You can also read back this value on listen sockets. + /// + /// This value should not be read or written in any other context. + k_ESteamNetworkingConfig_LocalVirtualPort = 38, + + /// [connection int32] Enable Dual wifi band support for this connection + /// 0 = no, 1 = yes, 2 = simulate it for debugging, even if dual wifi not available + k_ESteamNetworkingConfig_DualWifi_Enable = 39, + + /// [connection int32] True to enable diagnostics reporting through + /// generic platform UI. (Only available on Steam.) + k_ESteamNetworkingConfig_EnableDiagnosticsUI = 46, + +// +// Simulating network conditions +// +// These are global (not per-connection) because they apply at +// a relatively low UDP layer. +// + + /// [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, + + /// [global int32] Trace every UDP packet, similar to Wireshark or tcpdump. + /// Value is max number of bytes to dump. -1 disables tracing. + // 0 only traces the info but no actual data bytes + k_ESteamNetworkingConfig_PacketTraceMaxBytes = 41, + + + // [global int32] Global UDP token bucket rate limits. + // "Rate" refers to the steady state rate. (Bytes/sec, the + // rate that tokens are put into the bucket.) "Burst" + // refers to the max amount that could be sent in a single + // burst. (In bytes, the max capacity of the bucket.) + // Rate=0 disables the limiter entirely, which is the default. + // Burst=0 disables burst. (This is not realistic. A + // burst of at least 4K is recommended; the default is higher.) + k_ESteamNetworkingConfig_FakeRateLimit_Send_Rate = 42, + k_ESteamNetworkingConfig_FakeRateLimit_Send_Burst = 43, + k_ESteamNetworkingConfig_FakeRateLimit_Recv_Rate = 44, + k_ESteamNetworkingConfig_FakeRateLimit_Recv_Burst = 45, + +// +// Callbacks +// + + // On Steam, you may use the default Steam callback dispatch mechanism. If you prefer + // to not use this dispatch mechanism (or you are not running with Steam), or you want + // to associate specific functions with specific listen sockets or connections, you can + // register them as configuration values. + // + // Note also that ISteamNetworkingUtils has some helpers to set these globally. + + /// [connection FnSteamNetConnectionStatusChanged] Callback that will be invoked + /// when the state of a connection changes. + /// + /// IMPORTANT: callbacks are dispatched to the handler that is in effect at the time + /// the event occurs, which might be in another thread. For example, immediately after + /// creating a listen socket, you may receive an incoming connection. And then immediately + /// after this, the remote host may close the connection. All of this could happen + /// before the function to create the listen socket has returned. For this reason, + /// callbacks usually must be in effect at the time of object creation. This means + /// you should set them when you are creating the listen socket or connection, or have + /// them in effect so they will be inherited at the time of object creation. + /// + /// For example: + /// + /// exterm void MyStatusChangedFunc( SteamNetConnectionStatusChangedCallback_t *info ); + /// SteamNetworkingConfigValue_t opt; opt.SetPtr( k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, MyStatusChangedFunc ); + /// SteamNetworkingIPAddr localAddress; localAddress.Clear(); + /// HSteamListenSocket hListenSock = SteamNetworkingSockets()->CreateListenSocketIP( localAddress, 1, &opt ); + /// + /// When accepting an incoming connection, there is no atomic way to switch the + /// callback. However, if the connection is DOA, AcceptConnection() will fail, and + /// you can fetch the state of the connection at that time. + /// + /// If all connections and listen sockets can use the same callback, the simplest + /// method is to set it globally before you create any listen sockets or connections. + k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged = 201, + + /// [global FnSteamNetAuthenticationStatusChanged] Callback that will be invoked + /// when our auth state changes. If you use this, install the callback before creating + /// any connections or listen sockets, and don't change it. + /// See: ISteamNetworkingUtils::SetGlobalCallback_SteamNetAuthenticationStatusChanged + k_ESteamNetworkingConfig_Callback_AuthStatusChanged = 202, + + /// [global FnSteamRelayNetworkStatusChanged] Callback that will be invoked + /// when our auth state changes. If you use this, install the callback before creating + /// any connections or listen sockets, and don't change it. + /// See: ISteamNetworkingUtils::SetGlobalCallback_SteamRelayNetworkStatusChanged + k_ESteamNetworkingConfig_Callback_RelayNetworkStatusChanged = 203, + + /// [global FnSteamNetworkingMessagesSessionRequest] Callback that will be invoked + /// when a peer wants to initiate a SteamNetworkingMessagesSessionRequest. + /// See: ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionRequest + k_ESteamNetworkingConfig_Callback_MessagesSessionRequest = 204, + + /// [global FnSteamNetworkingMessagesSessionFailed] Callback that will be invoked + /// when a session you have initiated, or accepted either fails to connect, or loses + /// connection in some unexpected way. + /// See: ISteamNetworkingUtils::SetGlobalCallback_MessagesSessionFailed + k_ESteamNetworkingConfig_Callback_MessagesSessionFailed = 205, + + /// [global FnSteamNetworkingSocketsCreateConnectionSignaling] Callback that will + /// be invoked when we need to create a signaling object for a connection + /// initiated locally. See: ISteamNetworkingSockets::ConnectP2P, + /// ISteamNetworkingMessages. + k_ESteamNetworkingConfig_Callback_CreateConnectionSignaling = 206, + + /// [global FnSteamNetworkingFakeIPResult] Callback that's invoked when + /// a FakeIP allocation finishes. See: ISteamNetworkingSockets::BeginAsyncRequestFakeIP, + /// ISteamNetworkingUtils::SetGlobalCallback_FakeIPResult + k_ESteamNetworkingConfig_Callback_FakeIPResult = 207, + +// +// P2P connection settings +// + +// /// [listen socket int32] When you create a P2P listen socket, we will automatically +// /// open up a UDP port to listen for LAN connections. LAN connections can be made +// /// without any signaling: both sides can be disconnected from the Internet. +// /// +// /// This value can be set to zero to disable the feature. +// k_ESteamNetworkingConfig_P2P_Discovery_Server_LocalPort = 101, +// +// /// [connection int32] P2P connections can perform broadcasts looking for the peer +// /// on the LAN. +// k_ESteamNetworkingConfig_P2P_Discovery_Client_RemotePort = 102, + + /// [connection string] Comma-separated list of STUN servers that can be used + /// for NAT piercing. If you set this to an empty string, NAT piercing will + /// not be attempted. Also if "public" candidates are not allowed for + /// P2P_Transport_ICE_Enable, then this is ignored. + k_ESteamNetworkingConfig_P2P_STUN_ServerList = 103, + + /// [connection int32] What types of ICE candidates to share with the peer. + /// See k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_xxx values + k_ESteamNetworkingConfig_P2P_Transport_ICE_Enable = 104, + + /// [connection int32] When selecting P2P transport, add various + /// penalties to the scores for selected transports. (Route selection + /// scores are on a scale of milliseconds. The score begins with the + /// route ping time and is then adjusted.) + k_ESteamNetworkingConfig_P2P_Transport_ICE_Penalty = 105, + k_ESteamNetworkingConfig_P2P_Transport_SDR_Penalty = 106, + k_ESteamNetworkingConfig_P2P_TURN_ServerList = 107, + k_ESteamNetworkingConfig_P2P_TURN_UserList = 108, + k_ESteamNetworkingConfig_P2P_TURN_PassList = 109, + //k_ESteamNetworkingConfig_P2P_Transport_LANBeacon_Penalty = 107, + k_ESteamNetworkingConfig_P2P_Transport_ICE_Implementation = 110, + +// +// 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, + + /// [global string] For debugging. Force ping times to clusters to be the specified + /// values. A comma separated list of = values. E.g. "sto=32,iad=100" + /// + /// This is a dev configuration value, you probably should not let users modify it + /// in production. + k_ESteamNetworkingConfig_SDRClient_FakeClusterPing = 36, + +// +// Log levels for debugging information of various subsystems. +// Higher numeric values will cause more stuff to be printed. +// See ISteamNetworkingUtils::SetDebugOutputFunction for more +// information +// +// The default for all values is k_ESteamNetworkingSocketsDebugOutputType_Warning. +// + 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/recv + 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 + + + // Deleted, do not use + k_ESteamNetworkingConfig_DELETED_EnumerateDevVars = 35, + + k_ESteamNetworkingConfigValue__Force32Bit = 0x7fffffff +}; + +// Bitmask of types to share +const int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Default = -1; // Special value - use user defaults +const int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Disable = 0; // Do not do any ICE work at all or share any IP addresses with peer +const int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Relay = 1; // Relayed connection via TURN server. +const int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Private = 2; // host addresses that appear to be link-local or RFC1918 addresses +const int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Public = 4; // STUN reflexive addresses, or host address that isn't a "private" address +const int k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_All = 0x7fffffff; + +/// In a few places we need to set configuration options on listen sockets and connections, and +/// have them take effect *before* the listen socket or connection really starts doing anything. +/// Creating the object and then setting the options "immediately" after creation doesn't work +/// completely, because network packets could be received between the time the object is created and +/// when the options are applied. To set options at creation time in a reliable way, they must be +/// passed to the creation function. This structure is used to pass those options. +/// +/// For the meaning of these fields, see ISteamNetworkingUtils::SetConfigValue. Basically +/// when the object is created, we just iterate over the list of options and call +/// ISteamNetworkingUtils::SetConfigValueStruct, where the scope arguments are supplied by the +/// object being created. +struct SteamNetworkingConfigValue_t +{ + /// Which option is being set + ESteamNetworkingConfigValue m_eValue; + + /// Which field below did you fill in? + ESteamNetworkingConfigDataType m_eDataType; + + /// Option value + union + { + int32_t m_int32; + int64_t m_int64; + float m_float; + const char *m_string; // Points to your '\0'-terminated buffer + void *m_ptr; + } m_val; + + // + // Shortcut helpers to set the type and value in a single call + // + inline void SetInt32( ESteamNetworkingConfigValue eVal, int32_t data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Int32; + m_val.m_int32 = data; + } + inline void SetInt64( ESteamNetworkingConfigValue eVal, int64_t data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Int64; + m_val.m_int64 = data; + } + inline void SetFloat( ESteamNetworkingConfigValue eVal, float data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Float; + m_val.m_float = data; + } + inline void SetPtr( ESteamNetworkingConfigValue eVal, void *data ) + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Ptr; + m_val.m_ptr = data; + } + inline void SetString( ESteamNetworkingConfigValue eVal, const char *data ) // WARNING - Just saves your pointer. Does NOT make a copy of the string + { + m_eValue = eVal; + m_eDataType = k_ESteamNetworkingConfig_Ptr; + m_val.m_string = data; + } +}; + +/// 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 ( result && 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' +/// +/// See also SteamNetworkingPOPIDRender +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'; + +#ifndef API_GEN + +/// Utility class for printing a SteamNetworkingPOPID. +struct SteamNetworkingPOPIDRender +{ + SteamNetworkingPOPIDRender( SteamNetworkingPOPID x ) { GetSteamNetworkingLocationPOPStringFromID( x, buf ); } + inline const char *c_str() const { return buf; } +private: + char buf[ 8 ]; +}; + +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Internal stuff +#ifndef API_GEN + +// 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 bool SteamNetworkingIdentity::SetXboxPairwiseID( const char *pszString ) { size_t l = strlen( pszString ); if ( l < 1 || l >= sizeof(m_szXboxPairwiseID) ) return false; + m_eType = k_ESteamNetworkingIdentityType_XboxPairwiseID; m_cbSize = int(l+1); memcpy( m_szXboxPairwiseID, pszString, m_cbSize ); return true; } +inline const char *SteamNetworkingIdentity::GetXboxPairwiseID() const { return m_eType == k_ESteamNetworkingIdentityType_XboxPairwiseID ? m_szXboxPairwiseID : NULL; } +inline void SteamNetworkingIdentity::SetPSNID( uint64 id ) { m_eType = k_ESteamNetworkingIdentityType_SonyPSN; m_cbSize = sizeof( m_PSNID ); m_PSNID = id; } +inline uint64 SteamNetworkingIdentity::GetPSNID() const { return m_eType == k_ESteamNetworkingIdentityType_SonyPSN ? m_PSNID : 0; } +inline void SteamNetworkingIdentity::SetStadiaID( uint64 id ) { m_eType = k_ESteamNetworkingIdentityType_GoogleStadia; m_cbSize = sizeof( m_stadiaID ); m_stadiaID = id; } +inline uint64 SteamNetworkingIdentity::GetStadiaID() const { return m_eType == k_ESteamNetworkingIdentityType_GoogleStadia ? m_stadiaID : 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::SetIPv4Addr( uint32 nIPv4, uint16 nPort ) { m_eType = k_ESteamNetworkingIdentityType_IPAddress; m_cbSize = (int)sizeof(m_ip); m_ip.SetIPv4( nIPv4, nPort ); } +inline uint32 SteamNetworkingIdentity::GetIPv4() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress ? m_ip.GetIPv4() : 0; } +inline ESteamNetworkingFakeIPType SteamNetworkingIdentity::GetFakeIPType() const { return m_eType == k_ESteamNetworkingIdentityType_IPAddress ? m_ip.GetFakeIPType() : k_ESteamNetworkingFakeIPType_Invalid; } +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 ); } + +#endif // #ifndef API_GEN + +#endif // #ifndef STEAMNETWORKINGTYPES diff --git a/Amalgam/src/SDK/Definitions/Steam/SteamPS3Params.h b/Amalgam/src/SDK/Definitions/Steam/SteamPS3Params.h new file mode 100644 index 0000000..c0741b4 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/SteamTypes.h b/Amalgam/src/SDK/Definitions/Steam/SteamTypes.h new file mode 100644 index 0000000..47df567 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/SteamTypes.h @@ -0,0 +1,181 @@ +//========= Copyright 1996-2022, Valve LLC, All rights reserved. ============ + +#ifndef STEAMTYPES_H +#define STEAMTYPES_H + +#define S_CALLTYPE __cdecl +// WARNING: __cdecl is potentially #defined away in Steam_API_Common.h + +// Steam-specific types. Defined here so this header file can be included in other code bases. +#ifndef WCHARTYPES_H +typedef unsigned char uint8; +#endif + +#ifdef __GNUC__ + #if __GNUC__ < 4 + #error "Steamworks requires GCC 4.X (4.2 or 4.4 have been tested)" + #endif +#endif + +#if defined(__LP64__) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) || defined(__s390x__) +#define X64BITS +#endif + +#if !defined(VALVE_BIG_ENDIAN) +#if defined(_PS3) +// Make sure VALVE_BIG_ENDIAN gets set on PS3, may already be set previously in Valve internal code. +#define VALVE_BIG_ENDIAN 1 +#endif +#if defined( __GNUC__ ) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define VALVE_BIG_ENDIAN 1 +#endif +#endif + +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( _WIN32 ) && !defined( __GNUC__ ) + +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 + +typedef uint32 AppId_t; +const AppId_t k_uAppIdInvalid = 0x0; + +// AppIds and DepotIDs also presently share the same namespace +typedef uint32 DepotId_t; +const DepotId_t k_uDepotIdInvalid = 0x0; + +// RTime32. Seconds elapsed since Jan 1 1970, i.e. unix timestamp. +// It's the same as time_t, but it is always 32-bit and unsigned. +typedef uint32 RTime32; + +// handle to a Steam API call +typedef uint64 SteamAPICall_t; +const SteamAPICall_t k_uAPICallInvalid = 0x0; + +typedef uint32 AccountID_t; + +// Party Beacon ID +typedef uint64 PartyBeaconID_t; +const PartyBeaconID_t k_ulPartyBeaconIdInvalid = 0; + +enum ESteamIPType +{ + k_ESteamIPTypeIPv4 = 0, + k_ESteamIPTypeIPv6 = 1, +}; + +#pragma pack( push, 1 ) + +struct SteamIPAddress_t +{ + union { + + uint32 m_unIPv4; // Host order + uint8 m_rgubIPv6[16]; // Network order! Same as inaddr_in6. (0011:2233:4455:6677:8899:aabb:ccdd:eeff) + + // Internal use only + uint64 m_ipv6Qword[2]; // big endian + }; + + ESteamIPType m_eType; + + bool IsSet() const + { + if ( k_ESteamIPTypeIPv4 == m_eType ) + { + return m_unIPv4 != 0; + } + else + { + return m_ipv6Qword[0] !=0 || m_ipv6Qword[1] != 0; + } + } + + static SteamIPAddress_t IPv4Any() + { + SteamIPAddress_t ipOut; + ipOut.m_eType = k_ESteamIPTypeIPv4; + ipOut.m_unIPv4 = 0; + + return ipOut; + } + + static SteamIPAddress_t IPv6Any() + { + SteamIPAddress_t ipOut; + ipOut.m_eType = k_ESteamIPTypeIPv6; + ipOut.m_ipv6Qword[0] = 0; + ipOut.m_ipv6Qword[1] = 0; + + return ipOut; + } + + static SteamIPAddress_t IPv4Loopback() + { + SteamIPAddress_t ipOut; + ipOut.m_eType = k_ESteamIPTypeIPv4; + ipOut.m_unIPv4 = 0x7f000001; + + return ipOut; + } + + static SteamIPAddress_t IPv6Loopback() + { + SteamIPAddress_t ipOut; + ipOut.m_eType = k_ESteamIPTypeIPv6; + ipOut.m_ipv6Qword[0] = 0; + ipOut.m_ipv6Qword[1] = 0; + ipOut.m_rgubIPv6[15] = 1; + + return ipOut; + } +}; + +#pragma pack( pop ) + +#endif // STEAMTYPES_H diff --git a/Amalgam/src/SDK/Definitions/Steam/SteamUniverse.h b/Amalgam/src/SDK/Definitions/Steam/SteamUniverse.h new file mode 100644 index 0000000..dd384dc --- /dev/null +++ b/Amalgam/src/SDK/Definitions/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/Amalgam/src/SDK/Definitions/Steam/Steam_API.h b/Amalgam/src/SDK/Definitions/Steam/Steam_API.h new file mode 100644 index 0000000..5ff444e --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/Steam_API.h @@ -0,0 +1,297 @@ +//====== 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" +#include "ISteamNetworkingMessages.h" +#include "ISteamNetworkingSockets.h" +#include "ISteamNetworkingUtils.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(); + +// 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 +// This is ignored if you are using the manual callback dispatch method +S_API void SteamAPI_SetTryCatchCallbacks( bool bTryCatchCallbacks ); + +#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 + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// +// Manual callback loop +// +// An alternative method for dispatching callbacks. Similar to a windows message loop. +// +// If you use the manual callback dispatch, you must NOT use: +// +// - SteamAPI_RunCallbacks or SteamGameServer_RunCallbacks +// - STEAM_CALLBACK, CCallResult, CCallback, or CCallbackManual +// +// Here is the basic template for replacing SteamAPI_RunCallbacks() with manual dispatch +/* + + HSteamPipe hSteamPipe = SteamAPI_GetHSteamPipe(); // See also SteamGameServer_GetHSteamPipe() + SteamAPI_ManualDispatch_RunFrame( hSteamPipe ) + CallbackMsg_t callback; + while ( SteamAPI_ManualDispatch_GetNextCallback( hSteamPipe, &callback ) ) + { + // Check for dispatching API call results + if ( callback.m_iCallback == SteamAPICallCompleted_t::k_iCallback ) + { + SteamAPICallCompleted_t *pCallCompleted = (SteamAPICallCompleted_t *)callback. + void *pTmpCallResult = malloc( pCallback->m_cubParam ); + bool bFailed; + if ( SteamAPI_ManualDispatch_GetAPICallResult( hSteamPipe, pCallCompleted->m_hAsyncCall, pTmpCallResult, pCallback->m_cubParam, pCallback->m_iCallback, &bFailed ) ) + { + // Dispatch the call result to the registered handler(s) for the + // call identified by pCallCompleted->m_hAsyncCall + } + free( pTmpCallResult ); + } + else + { + // Look at callback.m_iCallback to see what kind of callback it is, + // and dispatch to appropriate handler(s) + } + SteamAPI_ManualDispatch_FreeLastCallback( hSteamPipe ); + } + +*/ +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +/// Inform the API that you wish to use manual event dispatch. This must be called after SteamAPI_Init, but before +/// you use any of the other manual dispatch functions below. +S_API void S_CALLTYPE SteamAPI_ManualDispatch_Init(); + +/// Perform certain periodic actions that need to be performed. +S_API void S_CALLTYPE SteamAPI_ManualDispatch_RunFrame( HSteamPipe hSteamPipe ); + +/// Fetch the next pending callback on the given pipe, if any. If a callback is available, true is returned +/// and the structure is populated. In this case, you MUST call SteamAPI_ManualDispatch_FreeLastCallback +/// (after dispatching the callback) before calling SteamAPI_ManualDispatch_GetNextCallback again. +S_API bool S_CALLTYPE SteamAPI_ManualDispatch_GetNextCallback( HSteamPipe hSteamPipe, CallbackMsg_t *pCallbackMsg ); + +/// You must call this after dispatching the callback, if SteamAPI_ManualDispatch_GetNextCallback returns true. +S_API void S_CALLTYPE SteamAPI_ManualDispatch_FreeLastCallback( HSteamPipe hSteamPipe ); + +/// Return the call result for the specified call on the specified pipe. You really should +/// only call this in a handler for SteamAPICallCompleted_t callback. +S_API bool S_CALLTYPE SteamAPI_ManualDispatch_GetAPICallResult( HSteamPipe hSteamPipe, SteamAPICall_t hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed ); + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// +// CSteamAPIContext +// +// Deprecated! This is not necessary any more. Please use the global accessors directly +// +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +#ifndef STEAM_API_EXPORTS + +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/Amalgam/src/SDK/Definitions/Steam/Steam_API.json b/Amalgam/src/SDK/Definitions/Steam/Steam_API.json new file mode 100644 index 0000000..2e18c6c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/Steam_API.json @@ -0,0 +1,14147 @@ +{ + "callback_structs": [ + { + "callback_id": 101, + "fields": [], + "struct": "SteamServersConnected_t" + }, + { + "callback_id": 102, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_bStillRetrying", "fieldtype":"bool" } + ], + "struct": "SteamServerConnectFailure_t" + }, + { + "callback_id": 103, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "SteamServersDisconnected_t" + }, + { + "callback_id": 113, + "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": "ClientGameServerDeny_t" + }, + { + "callback_id": 117, + "enums": [ + { + "enumname": "EFailureType", + "fqname": "IPCFailure_t::EFailureType", + "values": [ + { "name":"k_EFailureFlushedCallbackQueue", "value":"0" }, + { "name":"k_EFailurePipeFail", "value":"1" } + ] + } + ], + "fields": [ + { "fieldname":"m_eFailureType", "fieldtype":"uint8" } + ], + "struct": "IPCFailure_t" + }, + { + "callback_id": 125, + "fields": [], + "struct": "LicensesUpdated_t" + }, + { + "callback_id": 143, + "fields": [ + { "fieldname":"m_SteamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_eAuthSessionResponse", "fieldtype":"EAuthSessionResponse" }, + { "fieldname":"m_OwnerSteamID", "fieldtype":"CSteamID" } + ], + "struct": "ValidateAuthTicketResponse_t" + }, + { + "callback_id": 152, + "fields": [ + { "fieldname":"m_unAppID", "fieldtype":"uint32" }, + { "fieldname":"m_ulOrderID", "fieldtype":"uint64" }, + { "fieldname":"m_bAuthorized", "fieldtype":"uint8" } + ], + "struct": "MicroTxnAuthorizationResponse_t" + }, + { + "callback_id": 154, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "EncryptedAppTicketResponse_t" + }, + { + "callback_id": 163, + "fields": [ + { "fieldname":"m_hAuthTicket", "fieldtype":"HAuthTicket" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "GetAuthSessionTicketResponse_t" + }, + { + "callback_id": 164, + "fields": [ + { "fieldname":"m_szURL", "fieldtype":"char [256]" } + ], + "struct": "GameWebCallback_t" + }, + { + "callback_id": 165, + "fields": [ + { "fieldname":"m_szURL", "fieldtype":"char [512]" } + ], + "struct": "StoreAuthURLResponse_t" + }, + { + "callback_id": 166, + "fields": [ + { "fieldname":"m_bAllowed", "fieldtype":"bool" }, + { "fieldname":"m_eNotAllowedReason", "fieldtype":"EMarketNotAllowedReasonFlags" }, + { "fieldname":"m_rtAllowedAtTime", "fieldtype":"RTime32" }, + { "fieldname":"m_cdaySteamGuardRequiredDays", "fieldtype":"int" }, + { "fieldname":"m_cdayNewDeviceCooldown", "fieldtype":"int" } + ], + "struct": "MarketEligibilityResponse_t" + }, + { + "callback_id": 167, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_appid", "fieldtype":"AppId_t" }, + { "fieldname":"m_bApplicable", "fieldtype":"bool" }, + { "fieldname":"m_csecsLast5h", "fieldtype":"int32" }, + { "fieldname":"m_progress", "fieldtype":"EDurationControlProgress" }, + { "fieldname":"m_notification", "fieldtype":"EDurationControlNotification" }, + { "fieldname":"m_csecsToday", "fieldtype":"int32" }, + { "fieldname":"m_csecsRemaining", "fieldtype":"int32" } + ], + "struct": "DurationControl_t" + }, + { + "callback_id": 168, + "fields": [ + { "fieldname":"m_hAuthTicket", "fieldtype":"HAuthTicket" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_cubTicket", "fieldtype":"int" }, + { "fieldname":"m_rgubTicket", "fieldtype":"uint8 [2560]" } + ], + "struct": "GetTicketForWebApiResponse_t" + }, + { + "callback_id": 304, + "fields": [ + { "fieldname":"m_ulSteamID", "fieldtype":"uint64" }, + { "fieldname":"m_nChangeFlags", "fieldtype":"int" } + ], + "struct": "PersonaStateChange_t" + }, + { + "callback_id": 331, + "fields": [ + { "fieldname":"m_bActive", "fieldtype":"uint8" }, + { "fieldname":"m_bUserInitiated", "fieldtype":"bool" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "GameOverlayActivated_t" + }, + { + "callback_id": 332, + "fields": [ + { "fieldname":"m_rgchServer", "fieldtype":"char [64]" }, + { "fieldname":"m_rgchPassword", "fieldtype":"char [64]" } + ], + "struct": "GameServerChangeRequested_t" + }, + { + "callback_id": 333, + "fields": [ + { "fieldname":"m_steamIDLobby", "fieldtype":"CSteamID" }, + { "fieldname":"m_steamIDFriend", "fieldtype":"CSteamID" } + ], + "struct": "GameLobbyJoinRequested_t" + }, + { + "callback_id": 334, + "fields": [ + { "fieldname":"m_steamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_iImage", "fieldtype":"int" }, + { "fieldname":"m_iWide", "fieldtype":"int" }, + { "fieldname":"m_iTall", "fieldtype":"int" } + ], + "struct": "AvatarImageLoaded_t" + }, + { + "callback_id": 335, + "fields": [ + { "fieldname":"m_steamIDClan", "fieldtype":"CSteamID" }, + { "fieldname":"m_cOfficers", "fieldtype":"int" }, + { "fieldname":"m_bSuccess", "fieldtype":"uint8" } + ], + "struct": "ClanOfficerListResponse_t" + }, + { + "callback_id": 336, + "fields": [ + { "fieldname":"m_steamIDFriend", "fieldtype":"CSteamID" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "FriendRichPresenceUpdate_t" + }, + { + "callback_id": 337, + "fields": [ + { "fieldname":"m_steamIDFriend", "fieldtype":"CSteamID" }, + { "fieldname":"m_rgchConnect", "fieldtype":"char [256]" } + ], + "struct": "GameRichPresenceJoinRequested_t" + }, + { + "callback_id": 338, + "fields": [ + { "fieldname":"m_steamIDClanChat", "fieldtype":"CSteamID" }, + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" }, + { "fieldname":"m_iMessageID", "fieldtype":"int" } + ], + "struct": "GameConnectedClanChatMsg_t" + }, + { + "callback_id": 339, + "fields": [ + { "fieldname":"m_steamIDClanChat", "fieldtype":"CSteamID" }, + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" } + ], + "struct": "GameConnectedChatJoin_t" + }, + { + "callback_id": 340, + "fields": [ + { "fieldname":"m_steamIDClanChat", "fieldtype":"CSteamID" }, + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" }, + { "fieldname":"m_bKicked", "fieldtype":"bool" }, + { "fieldname":"m_bDropped", "fieldtype":"bool" } + ], + "struct": "GameConnectedChatLeave_t" + }, + { + "callback_id": 341, + "fields": [ + { "fieldname":"m_bSuccess", "fieldtype":"bool" } + ], + "struct": "DownloadClanActivityCountsResult_t" + }, + { + "callback_id": 342, + "fields": [ + { "fieldname":"m_steamIDClanChat", "fieldtype":"CSteamID" }, + { "fieldname":"m_eChatRoomEnterResponse", "fieldtype":"EChatRoomEnterResponse" } + ], + "struct": "JoinClanChatRoomCompletionResult_t" + }, + { + "callback_id": 343, + "fields": [ + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" }, + { "fieldname":"m_iMessageID", "fieldtype":"int" } + ], + "struct": "GameConnectedFriendChatMsg_t" + }, + { + "callback_id": 344, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_steamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_nCount", "fieldtype":"int" } + ], + "struct": "FriendsGetFollowerCount_t" + }, + { + "callback_id": 345, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_steamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_bIsFollowing", "fieldtype":"bool" } + ], + "struct": "FriendsIsFollowing_t" + }, + { + "callback_id": 346, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_rgSteamID", "fieldtype":"CSteamID [50]" }, + { "fieldname":"m_nResultsReturned", "fieldtype":"int32" }, + { "fieldname":"m_nTotalResultCount", "fieldtype":"int32" } + ], + "struct": "FriendsEnumerateFollowingList_t" + }, + { + "callback_id": 347, + "fields": [ + { "fieldname":"m_bSuccess", "fieldtype":"bool" }, + { "fieldname":"m_bLocalSuccess", "fieldtype":"bool" }, + { "fieldname":"m_result", "fieldtype":"EResult" } + ], + "struct": "SetPersonaNameResponse_t" + }, + { + "callback_id": 348, + "fields": [], + "struct": "UnreadChatMessagesChanged_t" + }, + { + "callback_id": 349, + "fields": [ + { "fieldname":"rgchURI", "fieldtype":"char [1024]" } + ], + "struct": "OverlayBrowserProtocolNavigation_t" + }, + { + "callback_id": 350, + "fields": [ + { "fieldname":"m_steamID", "fieldtype":"CSteamID" } + ], + "struct": "EquippedProfileItemsChanged_t" + }, + { + "callback_id": 351, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_steamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_bHasAnimatedAvatar", "fieldtype":"bool" }, + { "fieldname":"m_bHasAvatarFrame", "fieldtype":"bool" }, + { "fieldname":"m_bHasProfileModifier", "fieldtype":"bool" }, + { "fieldname":"m_bHasProfileBackground", "fieldtype":"bool" }, + { "fieldname":"m_bHasMiniProfileBackground", "fieldtype":"bool" } + ], + "struct": "EquippedProfileItems_t" + }, + { + "callback_id": 701, + "fields": [], + "struct": "IPCountry_t" + }, + { + "callback_id": 702, + "fields": [ + { "fieldname":"m_nMinutesBatteryLeft", "fieldtype":"uint8" } + ], + "struct": "LowBatteryPower_t" + }, + { + "callback_id": 703, + "fields": [ + { "fieldname":"m_hAsyncCall", "fieldtype":"SteamAPICall_t" }, + { "fieldname":"m_iCallback", "fieldtype":"int" }, + { "fieldname":"m_cubParam", "fieldtype":"uint32" } + ], + "struct": "SteamAPICallCompleted_t" + }, + { + "callback_id": 704, + "fields": [], + "struct": "SteamShutdown_t" + }, + { + "callback_id": 705, + "fields": [ + { "fieldname":"m_eCheckFileSignature", "fieldtype":"ECheckFileSignature" } + ], + "struct": "CheckFileSignature_t" + }, + { + "callback_id": 714, + "fields": [ + { "fieldname":"m_bSubmitted", "fieldtype":"bool" }, + { "fieldname":"m_unSubmittedText", "fieldtype":"uint32" }, + { "fieldname":"m_unAppID", "fieldtype":"AppId_t" } + ], + "struct": "GamepadTextInputDismissed_t" + }, + { + "callback_id": 736, + "fields": [], + "struct": "AppResumingFromSuspend_t" + }, + { + "callback_id": 738, + "fields": [], + "struct": "FloatingGamepadTextInputDismissed_t" + }, + { + "callback_id": 739, + "fields": [ + { "fieldname":"m_eLanguage", "fieldtype":"int" } + ], + "struct": "FilterTextDictionaryChanged_t" + }, + { + "callback_id": 502, + "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": "FavoritesListChanged_t" + }, + { + "callback_id": 503, + "fields": [ + { "fieldname":"m_ulSteamIDUser", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_ulGameID", "fieldtype":"uint64" } + ], + "struct": "LobbyInvite_t" + }, + { + "callback_id": 504, + "fields": [ + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_rgfChatPermissions", "fieldtype":"uint32" }, + { "fieldname":"m_bLocked", "fieldtype":"bool" }, + { "fieldname":"m_EChatRoomEnterResponse", "fieldtype":"uint32" } + ], + "struct": "LobbyEnter_t" + }, + { + "callback_id": 505, + "fields": [ + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDMember", "fieldtype":"uint64" }, + { "fieldname":"m_bSuccess", "fieldtype":"uint8" } + ], + "struct": "LobbyDataUpdate_t" + }, + { + "callback_id": 506, + "fields": [ + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDUserChanged", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDMakingChange", "fieldtype":"uint64" }, + { "fieldname":"m_rgfChatMemberStateChange", "fieldtype":"uint32" } + ], + "struct": "LobbyChatUpdate_t" + }, + { + "callback_id": 507, + "fields": [ + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDUser", "fieldtype":"uint64" }, + { "fieldname":"m_eChatEntryType", "fieldtype":"uint8" }, + { "fieldname":"m_iChatID", "fieldtype":"uint32" } + ], + "struct": "LobbyChatMsg_t" + }, + { + "callback_id": 509, + "fields": [ + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDGameServer", "fieldtype":"uint64" }, + { "fieldname":"m_unIP", "fieldtype":"uint32" }, + { "fieldname":"m_usPort", "fieldtype":"uint16" } + ], + "struct": "LobbyGameCreated_t" + }, + { + "callback_id": 510, + "fields": [ + { "fieldname":"m_nLobbiesMatching", "fieldtype":"uint32" } + ], + "struct": "LobbyMatchList_t" + }, + { + "callback_id": 512, + "fields": [ + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" }, + { "fieldname":"m_ulSteamIDAdmin", "fieldtype":"uint64" }, + { "fieldname":"m_bKickedDueToDisconnect", "fieldtype":"uint8" } + ], + "struct": "LobbyKicked_t" + }, + { + "callback_id": 513, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ulSteamIDLobby", "fieldtype":"uint64" } + ], + "struct": "LobbyCreated_t" + }, + { + "callback_id": 515, + "fields": [ + { "fieldname":"m_bGameBootInviteExists", "fieldtype":"bool" }, + { "fieldname":"m_steamIDLobby", "fieldtype":"CSteamID" } + ], + "struct": "PSNGameBootInviteResult_t" + }, + { + "callback_id": 516, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "FavoritesListAccountsUpdated_t" + }, + { + "callback_id": 5201, + "fields": [ + { "fieldname":"m_ullSearchID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_lobbyID", "fieldtype":"CSteamID" }, + { "fieldname":"m_steamIDEndedSearch", "fieldtype":"CSteamID" }, + { "fieldname":"m_nSecondsRemainingEstimate", "fieldtype":"int32" }, + { "fieldname":"m_cPlayersSearching", "fieldtype":"int32" } + ], + "struct": "SearchForGameProgressCallback_t" + }, + { + "callback_id": 5202, + "fields": [ + { "fieldname":"m_ullSearchID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nCountPlayersInGame", "fieldtype":"int32" }, + { "fieldname":"m_nCountAcceptedGame", "fieldtype":"int32" }, + { "fieldname":"m_steamIDHost", "fieldtype":"CSteamID" }, + { "fieldname":"m_bFinalCallback", "fieldtype":"bool" } + ], + "struct": "SearchForGameResultCallback_t" + }, + { + "callback_id": 5211, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ullSearchID", "fieldtype":"uint64" } + ], + "struct": "RequestPlayersForGameProgressCallback_t" + }, + { + "callback_id": 5212, + "enums": [ + { + "enumname": "PlayerAcceptState_t", + "fqname": "RequestPlayersForGameResultCallback_t::PlayerAcceptState_t", + "values": [ + { "name":"k_EStateUnknown", "value":"0" }, + { "name":"k_EStatePlayerAccepted", "value":"1" }, + { "name":"k_EStatePlayerDeclined", "value":"2" } + ] + } + ], + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ullSearchID", "fieldtype":"uint64" }, + { "fieldname":"m_SteamIDPlayerFound", "fieldtype":"CSteamID" }, + { "fieldname":"m_SteamIDLobby", "fieldtype":"CSteamID" }, + { "fieldname":"m_ePlayerAcceptState", "fieldtype":"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": "RequestPlayersForGameResultCallback_t" + }, + { + "callback_id": 5213, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ullSearchID", "fieldtype":"uint64" }, + { "fieldname":"m_ullUniqueGameID", "fieldtype":"uint64" } + ], + "struct": "RequestPlayersForGameFinalResultCallback_t" + }, + { + "callback_id": 5214, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"ullUniqueGameID", "fieldtype":"uint64" }, + { "fieldname":"steamIDPlayer", "fieldtype":"CSteamID" } + ], + "struct": "SubmitPlayerResultResultCallback_t" + }, + { + "callback_id": 5215, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"ullUniqueGameID", "fieldtype":"uint64" } + ], + "struct": "EndGameResultCallback_t" + }, + { + "callback_id": 5301, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ulBeaconID", "fieldtype":"PartyBeaconID_t" }, + { "fieldname":"m_SteamIDBeaconOwner", "fieldtype":"CSteamID" }, + { "fieldname":"m_rgchConnectString", "fieldtype":"char [256]" } + ], + "struct": "JoinPartyCallback_t" + }, + { + "callback_id": 5302, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ulBeaconID", "fieldtype":"PartyBeaconID_t" } + ], + "struct": "CreateBeaconCallback_t" + }, + { + "callback_id": 5303, + "fields": [ + { "fieldname":"m_ulBeaconID", "fieldtype":"PartyBeaconID_t" }, + { "fieldname":"m_steamIDJoiner", "fieldtype":"CSteamID" } + ], + "struct": "ReservationNotificationCallback_t" + }, + { + "callback_id": 5304, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "ChangeNumOpenSlotsCallback_t" + }, + { + "callback_id": 5305, + "fields": [], + "struct": "AvailableBeaconLocationsUpdated_t" + }, + { + "callback_id": 5306, + "fields": [], + "struct": "ActiveBeaconsUpdated_t" + }, + { + "callback_id": 1307, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_hFile", "fieldtype":"UGCHandle_t" }, + { "fieldname":"m_rgchFilename", "fieldtype":"char [260]" } + ], + "struct": "RemoteStorageFileShareResult_t" + }, + { + "callback_id": 1309, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype":"bool" } + ], + "struct": "RemoteStoragePublishFileResult_t" + }, + { + "callback_id": 1311, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "RemoteStorageDeletePublishedFileResult_t" + }, + { + "callback_id": 1312, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nResultsReturned", "fieldtype":"int32" }, + { "fieldname":"m_nTotalResultCount", "fieldtype":"int32" }, + { "fieldname":"m_rgPublishedFileId", "fieldtype":"PublishedFileId_t [50]" } + ], + "struct": "RemoteStorageEnumerateUserPublishedFilesResult_t" + }, + { + "callback_id": 1313, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "RemoteStorageSubscribePublishedFileResult_t" + }, + { + "callback_id": 1314, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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": "RemoteStorageEnumerateUserSubscribedFilesResult_t" + }, + { + "callback_id": 1315, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "RemoteStorageUnsubscribePublishedFileResult_t" + }, + { + "callback_id": 1316, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype":"bool" } + ], + "struct": "RemoteStorageUpdatePublishedFileResult_t" + }, + { + "callback_id": 1317, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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": "RemoteStorageDownloadUGCResult_t" + }, + { + "callback_id": 1318, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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":"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":"EWorkshopFileType" }, + { "fieldname":"m_bAcceptedForUse", "fieldtype":"bool" } + ], + "struct": "RemoteStorageGetPublishedFileDetailsResult_t" + }, + { + "callback_id": 1319, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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": "RemoteStorageEnumerateWorkshopFilesResult_t" + }, + { + "callback_id": 1320, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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": "RemoteStorageGetPublishedItemVoteDetailsResult_t" + }, + { + "callback_id": 1321, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "RemoteStoragePublishedFileSubscribed_t" + }, + { + "callback_id": 1322, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "RemoteStoragePublishedFileUnsubscribed_t" + }, + { + "callback_id": 1323, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "RemoteStoragePublishedFileDeleted_t" + }, + { + "callback_id": 1324, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "RemoteStorageUpdateUserPublishedItemVoteResult_t" + }, + { + "callback_id": 1325, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eVote", "fieldtype":"EWorkshopVote" } + ], + "struct": "RemoteStorageUserVoteDetails_t" + }, + { + "callback_id": 1326, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nResultsReturned", "fieldtype":"int32" }, + { "fieldname":"m_nTotalResultCount", "fieldtype":"int32" }, + { "fieldname":"m_rgPublishedFileId", "fieldtype":"PublishedFileId_t [50]" } + ], + "struct": "RemoteStorageEnumerateUserSharedWorkshopFilesResult_t" + }, + { + "callback_id": 1327, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eAction", "fieldtype":"EWorkshopFileAction" } + ], + "struct": "RemoteStorageSetUserPublishedFileActionResult_t" + }, + { + "callback_id": 1328, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_eAction", "fieldtype":"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": "RemoteStorageEnumeratePublishedFilesByUserActionResult_t" + }, + { + "callback_id": 1329, + "fields": [ + { "fieldname":"m_dPercentFile", "fieldtype":"double" }, + { "fieldname":"m_bPreview", "fieldtype":"bool" } + ], + "struct": "RemoteStoragePublishFileProgress_t" + }, + { + "callback_id": 1330, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_ulUnused", "fieldtype":"uint64" } + ], + "struct": "RemoteStoragePublishedFileUpdated_t" + }, + { + "callback_id": 1331, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "RemoteStorageFileWriteAsyncComplete_t" + }, + { + "callback_id": 1332, + "fields": [ + { "fieldname":"m_hFileReadAsync", "fieldtype":"SteamAPICall_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nOffset", "fieldtype":"uint32" }, + { "fieldname":"m_cubRead", "fieldtype":"uint32" } + ], + "struct": "RemoteStorageFileReadAsyncComplete_t" + }, + { + "callback_id": 1333, + "fields": [], + "struct": "RemoteStorageLocalFileChange_t" + }, + { + "callback_id": 1101, + "fields": [ + { "fieldname":"m_nGameID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" } + ], + "struct": "UserStatsReceived_t" + }, + { + "callback_id": 1102, + "fields": [ + { "fieldname":"m_nGameID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "UserStatsStored_t" + }, + { + "callback_id": 1103, + "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": "UserAchievementStored_t" + }, + { + "callback_id": 1104, + "fields": [ + { "fieldname":"m_hSteamLeaderboard", "fieldtype":"SteamLeaderboard_t" }, + { "fieldname":"m_bLeaderboardFound", "fieldtype":"uint8" } + ], + "struct": "LeaderboardFindResult_t" + }, + { + "callback_id": 1105, + "fields": [ + { "fieldname":"m_hSteamLeaderboard", "fieldtype":"SteamLeaderboard_t" }, + { "fieldname":"m_hSteamLeaderboardEntries", "fieldtype":"SteamLeaderboardEntries_t" }, + { "fieldname":"m_cEntryCount", "fieldtype":"int" } + ], + "struct": "LeaderboardScoresDownloaded_t" + }, + { + "callback_id": 1106, + "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": "LeaderboardScoreUploaded_t" + }, + { + "callback_id": 1107, + "fields": [ + { "fieldname":"m_bSuccess", "fieldtype":"uint8" }, + { "fieldname":"m_cPlayers", "fieldtype":"int32" } + ], + "struct": "NumberOfCurrentPlayers_t" + }, + { + "callback_id": 1108, + "fields": [ + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" } + ], + "struct": "UserStatsUnloaded_t" + }, + { + "callback_id": 1109, + "fields": [ + { "fieldname":"m_nGameID", "fieldtype":"CGameID" }, + { "fieldname":"m_rgchAchievementName", "fieldtype":"char [128]" }, + { "fieldname":"m_bAchieved", "fieldtype":"bool" }, + { "fieldname":"m_nIconHandle", "fieldtype":"int" } + ], + "struct": "UserAchievementIconFetched_t" + }, + { + "callback_id": 1110, + "fields": [ + { "fieldname":"m_nGameID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "GlobalAchievementPercentagesReady_t" + }, + { + "callback_id": 1111, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_hSteamLeaderboard", "fieldtype":"SteamLeaderboard_t" } + ], + "struct": "LeaderboardUGCSet_t" + }, + { + "callback_id": 1112, + "fields": [ + { "fieldname":"m_nGameID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ulRequiredDiskSpace", "fieldtype":"uint64" } + ], + "struct": "PS3TrophiesInstalled_t" + }, + { + "callback_id": 1112, + "fields": [ + { "fieldname":"m_nGameID", "fieldtype":"uint64" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "GlobalStatsReceived_t" + }, + { + "callback_id": 1005, + "fields": [ + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "DlcInstalled_t" + }, + { + "callback_id": 1014, + "fields": [], + "struct": "NewUrlLaunchParameters_t" + }, + { + "callback_id": 1021, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nAppID", "fieldtype":"uint32" }, + { "fieldname":"m_cchKeyLength", "fieldtype":"uint32" }, + { "fieldname":"m_rgchKey", "fieldtype":"char [240]" } + ], + "struct": "AppProofOfPurchaseKeyResponse_t" + }, + { + "callback_id": 1023, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_ulFileSize", "fieldtype":"uint64" }, + { "fieldname":"m_FileSHA", "fieldtype":"uint8 [20]" }, + { "fieldname":"m_unFlags", "fieldtype":"uint32" } + ], + "struct": "FileDetailsResult_t" + }, + { + "callback_id": 1030, + "fields": [ + { "fieldname":"m_unAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_bIsOffline", "fieldtype":"bool" }, + { "fieldname":"m_unSecondsAllowed", "fieldtype":"uint32" }, + { "fieldname":"m_unSecondsPlayed", "fieldtype":"uint32" } + ], + "struct": "TimedTrialStatus_t" + }, + { + "callback_id": 1202, + "fields": [ + { "fieldname":"m_steamIDRemote", "fieldtype":"CSteamID" } + ], + "struct": "P2PSessionRequest_t" + }, + { + "callback_id": 1203, + "fields": [ + { "fieldname":"m_steamIDRemote", "fieldtype":"CSteamID" }, + { "fieldname":"m_eP2PSessionError", "fieldtype":"uint8" } + ], + "struct": "P2PSessionConnectFail_t" + }, + { + "callback_id": 1201, + "fields": [ + { "fieldname":"m_hSocket", "fieldtype":"SNetSocket_t" }, + { "fieldname":"m_hListenSocket", "fieldtype":"SNetListenSocket_t" }, + { "fieldname":"m_steamIDRemote", "fieldtype":"CSteamID" }, + { "fieldname":"m_eSNetSocketState", "fieldtype":"int" } + ], + "struct": "SocketStatusCallback_t" + }, + { + "callback_id": 2301, + "fields": [ + { "fieldname":"m_hLocal", "fieldtype":"ScreenshotHandle" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "ScreenshotReady_t" + }, + { + "callback_id": 2302, + "fields": [], + "struct": "ScreenshotRequested_t" + }, + { + "callback_id": 4001, + "fields": [], + "struct": "PlaybackStatusHasChanged_t" + }, + { + "callback_id": 4002, + "fields": [ + { "fieldname":"m_flNewVolume", "fieldtype":"float" } + ], + "struct": "VolumeHasChanged_t" + }, + { + "callback_id": 4101, + "fields": [], + "struct": "MusicPlayerRemoteWillActivate_t" + }, + { + "callback_id": 4102, + "fields": [], + "struct": "MusicPlayerRemoteWillDeactivate_t" + }, + { + "callback_id": 4103, + "fields": [], + "struct": "MusicPlayerRemoteToFront_t" + }, + { + "callback_id": 4104, + "fields": [], + "struct": "MusicPlayerWillQuit_t" + }, + { + "callback_id": 4105, + "fields": [], + "struct": "MusicPlayerWantsPlay_t" + }, + { + "callback_id": 4106, + "fields": [], + "struct": "MusicPlayerWantsPause_t" + }, + { + "callback_id": 4107, + "fields": [], + "struct": "MusicPlayerWantsPlayPrevious_t" + }, + { + "callback_id": 4108, + "fields": [], + "struct": "MusicPlayerWantsPlayNext_t" + }, + { + "callback_id": 4109, + "fields": [ + { "fieldname":"m_bShuffled", "fieldtype":"bool" } + ], + "struct": "MusicPlayerWantsShuffled_t" + }, + { + "callback_id": 4110, + "fields": [ + { "fieldname":"m_bLooped", "fieldtype":"bool" } + ], + "struct": "MusicPlayerWantsLooped_t" + }, + { + "callback_id": 4011, + "fields": [ + { "fieldname":"m_flNewVolume", "fieldtype":"float" } + ], + "struct": "MusicPlayerWantsVolume_t" + }, + { + "callback_id": 4012, + "fields": [ + { "fieldname":"nID", "fieldtype":"int" } + ], + "struct": "MusicPlayerSelectsQueueEntry_t" + }, + { + "callback_id": 4013, + "fields": [ + { "fieldname":"nID", "fieldtype":"int" } + ], + "struct": "MusicPlayerSelectsPlaylistEntry_t" + }, + { + "callback_id": 4114, + "fields": [ + { "fieldname":"m_nPlayingRepeatStatus", "fieldtype":"int" } + ], + "struct": "MusicPlayerWantsPlayingRepeatStatus_t" + }, + { + "callback_id": 2101, + "fields": [ + { "fieldname":"m_hRequest", "fieldtype":"HTTPRequestHandle" }, + { "fieldname":"m_ulContextValue", "fieldtype":"uint64" }, + { "fieldname":"m_bRequestSuccessful", "fieldtype":"bool" }, + { "fieldname":"m_eStatusCode", "fieldtype":"EHTTPStatusCode" }, + { "fieldname":"m_unBodySize", "fieldtype":"uint32" } + ], + "struct": "HTTPRequestCompleted_t" + }, + { + "callback_id": 2102, + "fields": [ + { "fieldname":"m_hRequest", "fieldtype":"HTTPRequestHandle" }, + { "fieldname":"m_ulContextValue", "fieldtype":"uint64" } + ], + "struct": "HTTPRequestHeadersReceived_t" + }, + { + "callback_id": 2103, + "fields": [ + { "fieldname":"m_hRequest", "fieldtype":"HTTPRequestHandle" }, + { "fieldname":"m_ulContextValue", "fieldtype":"uint64" }, + { "fieldname":"m_cOffset", "fieldtype":"uint32" }, + { "fieldname":"m_cBytesReceived", "fieldtype":"uint32" } + ], + "struct": "HTTPRequestDataReceived_t" + }, + { + "callback_id": 2801, + "fields": [ + { "fieldname":"m_ulConnectedDeviceHandle", "fieldtype":"InputHandle_t" } + ], + "struct": "SteamInputDeviceConnected_t" + }, + { + "callback_id": 2802, + "fields": [ + { "fieldname":"m_ulDisconnectedDeviceHandle", "fieldtype":"InputHandle_t" } + ], + "struct": "SteamInputDeviceDisconnected_t" + }, + { + "callback_id": 2803, + "fields": [ + { "fieldname":"m_unAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_ulDeviceHandle", "fieldtype":"InputHandle_t" }, + { "fieldname":"m_ulMappingCreator", "fieldtype":"CSteamID" }, + { "fieldname":"m_unMajorRevision", "fieldtype":"uint32" }, + { "fieldname":"m_unMinorRevision", "fieldtype":"uint32" }, + { "fieldname":"m_bUsesSteamInputAPI", "fieldtype":"bool" }, + { "fieldname":"m_bUsesGamepadAPI", "fieldtype":"bool" } + ], + "struct": "SteamInputConfigurationLoaded_t" + }, + { + "callback_id": 2804, + "fields": [ + { "fieldname":"m_unAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_ulDeviceHandle", "fieldtype":"InputHandle_t" }, + { "fieldname":"m_eDeviceType", "fieldtype":"ESteamInputType" }, + { "fieldname":"m_nOldGamepadSlot", "fieldtype":"int" }, + { "fieldname":"m_nNewGamepadSlot", "fieldtype":"int" } + ], + "struct": "SteamInputGamepadSlotChange_t" + }, + { + "callback_id": 3401, + "fields": [ + { "fieldname":"m_handle", "fieldtype":"UGCQueryHandle_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_unNumResultsReturned", "fieldtype":"uint32" }, + { "fieldname":"m_unTotalMatchingResults", "fieldtype":"uint32" }, + { "fieldname":"m_bCachedData", "fieldtype":"bool" }, + { "fieldname":"m_rgchNextCursor", "fieldtype":"char [256]" } + ], + "struct": "SteamUGCQueryCompleted_t" + }, + { + "callback_id": 3402, + "fields": [ + { "fieldname":"m_details", "fieldtype":"SteamUGCDetails_t" }, + { "fieldname":"m_bCachedData", "fieldtype":"bool" } + ], + "struct": "SteamUGCRequestUGCDetailsResult_t" + }, + { + "callback_id": 3403, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype":"bool" } + ], + "struct": "CreateItemResult_t" + }, + { + "callback_id": 3404, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_bUserNeedsToAcceptWorkshopLegalAgreement", "fieldtype":"bool" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "SubmitItemUpdateResult_t" + }, + { + "callback_id": 3405, + "fields": [ + { "fieldname":"m_unAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "ItemInstalled_t" + }, + { + "callback_id": 3406, + "fields": [ + { "fieldname":"m_unAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "DownloadItemResult_t" + }, + { + "callback_id": 3407, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_bWasAddRequest", "fieldtype":"bool" } + ], + "struct": "UserFavoriteItemsListChanged_t" + }, + { + "callback_id": 3408, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_bVoteUp", "fieldtype":"bool" } + ], + "struct": "SetUserItemVoteResult_t" + }, + { + "callback_id": 3409, + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_bVotedUp", "fieldtype":"bool" }, + { "fieldname":"m_bVotedDown", "fieldtype":"bool" }, + { "fieldname":"m_bVoteSkipped", "fieldtype":"bool" } + ], + "struct": "GetUserItemVoteResult_t" + }, + { + "callback_id": 3410, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "StartPlaytimeTrackingResult_t" + }, + { + "callback_id": 3411, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "StopPlaytimeTrackingResult_t" + }, + { + "callback_id": 3412, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nChildPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "AddUGCDependencyResult_t" + }, + { + "callback_id": 3413, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nChildPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "RemoveUGCDependencyResult_t" + }, + { + "callback_id": 3414, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "AddAppDependencyResult_t" + }, + { + "callback_id": 3415, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "RemoveAppDependencyResult_t" + }, + { + "callback_id": 3416, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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": "GetAppDependenciesResult_t" + }, + { + "callback_id": 3417, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" } + ], + "struct": "DeleteItemResult_t" + }, + { + "callback_id": 3418, + "fields": [ + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" } + ], + "struct": "UserSubscribedItemsListChanged_t" + }, + { + "callback_id": 3420, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_unVersion", "fieldtype":"uint32" }, + { "fieldname":"m_rtAction", "fieldtype":"RTime32" }, + { "fieldname":"m_bAccepted", "fieldtype":"bool" }, + { "fieldname":"m_bNeedsAction", "fieldtype":"bool" } + ], + "struct": "WorkshopEULAStatus_t" + }, + { + "callback_id": 3901, + "fields": [ + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_iInstallFolderIndex", "fieldtype":"int" } + ], + "struct": "SteamAppInstalled_t" + }, + { + "callback_id": 3902, + "fields": [ + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_iInstallFolderIndex", "fieldtype":"int" } + ], + "struct": "SteamAppUninstalled_t" + }, + { + "callback_id": 4501, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" } + ], + "struct": "HTML_BrowserReady_t" + }, + { + "callback_id": 4502, + "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_NeedsPaint_t" + }, + { + "callback_id": 4503, + "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_StartRequest_t" + }, + { + "callback_id": 4504, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" } + ], + "struct": "HTML_CloseBrowser_t" + }, + { + "callback_id": 4505, + "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_URLChanged_t" + }, + { + "callback_id": 4506, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchURL", "fieldtype":"const char *" }, + { "fieldname":"pchPageTitle", "fieldtype":"const char *" } + ], + "struct": "HTML_FinishedRequest_t" + }, + { + "callback_id": 4507, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchURL", "fieldtype":"const char *" } + ], + "struct": "HTML_OpenLinkInNewTab_t" + }, + { + "callback_id": 4508, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchTitle", "fieldtype":"const char *" } + ], + "struct": "HTML_ChangedTitle_t" + }, + { + "callback_id": 4509, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"unResults", "fieldtype":"uint32" }, + { "fieldname":"unCurrentMatch", "fieldtype":"uint32" } + ], + "struct": "HTML_SearchResults_t" + }, + { + "callback_id": 4510, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"bCanGoBack", "fieldtype":"bool" }, + { "fieldname":"bCanGoForward", "fieldtype":"bool" } + ], + "struct": "HTML_CanGoBackAndForward_t" + }, + { + "callback_id": 4511, + "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_HorizontalScroll_t" + }, + { + "callback_id": 4512, + "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" + }, + { + "callback_id": 4513, + "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_LinkAtPosition_t" + }, + { + "callback_id": 4514, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchMessage", "fieldtype":"const char *" } + ], + "struct": "HTML_JSAlert_t" + }, + { + "callback_id": 4515, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchMessage", "fieldtype":"const char *" } + ], + "struct": "HTML_JSConfirm_t" + }, + { + "callback_id": 4516, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchTitle", "fieldtype":"const char *" }, + { "fieldname":"pchInitialFile", "fieldtype":"const char *" } + ], + "struct": "HTML_FileOpenDialog_t" + }, + { + "callback_id": 4521, + "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_NewWindow_t" + }, + { + "callback_id": 4522, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"eMouseCursor", "fieldtype":"uint32" } + ], + "struct": "HTML_SetCursor_t" + }, + { + "callback_id": 4523, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchMsg", "fieldtype":"const char *" } + ], + "struct": "HTML_StatusText_t" + }, + { + "callback_id": 4524, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchMsg", "fieldtype":"const char *" } + ], + "struct": "HTML_ShowToolTip_t" + }, + { + "callback_id": 4525, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"pchMsg", "fieldtype":"const char *" } + ], + "struct": "HTML_UpdateToolTip_t" + }, + { + "callback_id": 4526, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" } + ], + "struct": "HTML_HideToolTip_t" + }, + { + "callback_id": 4527, + "fields": [ + { "fieldname":"unBrowserHandle", "fieldtype":"HHTMLBrowser" }, + { "fieldname":"unOldBrowserHandle", "fieldtype":"HHTMLBrowser" } + ], + "struct": "HTML_BrowserRestarted_t" + }, + { + "callback_id": 4700, + "fields": [ + { "fieldname":"m_handle", "fieldtype":"SteamInventoryResult_t" }, + { "fieldname":"m_result", "fieldtype":"EResult" } + ], + "struct": "SteamInventoryResultReady_t" + }, + { + "callback_id": 4701, + "fields": [ + { "fieldname":"m_handle", "fieldtype":"SteamInventoryResult_t" } + ], + "struct": "SteamInventoryFullUpdate_t" + }, + { + "callback_id": 4702, + "fields": [], + "struct": "SteamInventoryDefinitionUpdate_t" + }, + { + "callback_id": 4703, + "fields": [ + { "fieldname":"m_result", "fieldtype":"EResult" }, + { "fieldname":"m_steamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_numEligiblePromoItemDefs", "fieldtype":"int" }, + { "fieldname":"m_bCachedData", "fieldtype":"bool" } + ], + "struct": "SteamInventoryEligiblePromoItemDefIDs_t" + }, + { + "callback_id": 4704, + "fields": [ + { "fieldname":"m_result", "fieldtype":"EResult" }, + { "fieldname":"m_ulOrderID", "fieldtype":"uint64" }, + { "fieldname":"m_ulTransID", "fieldtype":"uint64" } + ], + "struct": "SteamInventoryStartPurchaseResult_t" + }, + { + "callback_id": 4705, + "fields": [ + { "fieldname":"m_result", "fieldtype":"EResult" }, + { "fieldname":"m_rgchCurrency", "fieldtype":"char [4]" } + ], + "struct": "SteamInventoryRequestPricesResult_t" + }, + { + "callback_id": 4611, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_unVideoAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_rgchURL", "fieldtype":"char [256]" } + ], + "struct": "GetVideoURLResult_t" + }, + { + "callback_id": 4624, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_unVideoAppID", "fieldtype":"AppId_t" } + ], + "struct": "GetOPFSettingsResult_t" + }, + { + "callback_id": 5001, + "fields": [], + "struct": "SteamParentalSettingsChanged_t" + }, + { + "callback_id": 5701, + "fields": [ + { "fieldname":"m_unSessionID", "fieldtype":"RemotePlaySessionID_t" } + ], + "struct": "SteamRemotePlaySessionConnected_t" + }, + { + "callback_id": 5702, + "fields": [ + { "fieldname":"m_unSessionID", "fieldtype":"RemotePlaySessionID_t" } + ], + "struct": "SteamRemotePlaySessionDisconnected_t" + }, + { + "callback_id": 5703, + "fields": [ + { "fieldname":"m_szConnectURL", "fieldtype":"char [1024]" } + ], + "struct": "SteamRemotePlayTogetherGuestInvite_t" + }, + { + "callback_id": 1251, + "fields": [ + { "fieldname":"m_identityRemote", "fieldtype":"SteamNetworkingIdentity" } + ], + "struct": "SteamNetworkingMessagesSessionRequest_t" + }, + { + "callback_id": 1252, + "fields": [ + { "fieldname":"m_info", "fieldtype":"SteamNetConnectionInfo_t" } + ], + "struct": "SteamNetworkingMessagesSessionFailed_t" + }, + { + "callback_id": 1221, + "fields": [ + { "fieldname":"m_hConn", "fieldtype":"HSteamNetConnection" }, + { "fieldname":"m_info", "fieldtype":"SteamNetConnectionInfo_t" }, + { "fieldname":"m_eOldState", "fieldtype":"ESteamNetworkingConnectionState" } + ], + "struct": "SteamNetConnectionStatusChangedCallback_t" + }, + { + "callback_id": 1222, + "fields": [ + { "fieldname":"m_eAvail", "fieldtype":"ESteamNetworkingAvailability" }, + { "fieldname":"m_debugMsg", "fieldtype":"char [256]" } + ], + "struct": "SteamNetAuthenticationStatus_t" + }, + { + "callback_id": 1281, + "fields": [ + { "fieldname":"m_eAvail", "fieldtype":"ESteamNetworkingAvailability" }, + { "fieldname":"m_bPingMeasurementInProgress", "fieldtype":"int" }, + { "fieldname":"m_eAvailNetworkConfig", "fieldtype":"ESteamNetworkingAvailability" }, + { "fieldname":"m_eAvailAnyRelay", "fieldtype":"ESteamNetworkingAvailability" }, + { "fieldname":"m_debugMsg", "fieldtype":"char [256]" } + ], + "struct": "SteamRelayNetworkStatus_t" + }, + { + "callback_id": 201, + "fields": [ + { "fieldname":"m_SteamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_OwnerSteamID", "fieldtype":"CSteamID" } + ], + "struct": "GSClientApprove_t" + }, + { + "callback_id": 202, + "fields": [ + { "fieldname":"m_SteamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_eDenyReason", "fieldtype":"EDenyReason" }, + { "fieldname":"m_rgchOptionalText", "fieldtype":"char [128]" } + ], + "struct": "GSClientDeny_t" + }, + { + "callback_id": 203, + "fields": [ + { "fieldname":"m_SteamID", "fieldtype":"CSteamID" }, + { "fieldname":"m_eDenyReason", "fieldtype":"EDenyReason" } + ], + "struct": "GSClientKick_t" + }, + { + "callback_id": 206, + "fields": [ + { "fieldname":"m_SteamID", "fieldtype":"uint64" }, + { "fieldname":"m_pchAchievement", "fieldtype":"char [128]" }, + { "fieldname":"m_bUnlocked", "fieldtype":"bool" } + ], + "struct": "GSClientAchievementStatus_t" + }, + { + "callback_id": 115, + "fields": [ + { "fieldname":"m_bSecure", "fieldtype":"uint8" } + ], + "struct": "GSPolicyResponse_t" + }, + { + "callback_id": 207, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_nRank", "fieldtype":"int32" }, + { "fieldname":"m_unTotalConnects", "fieldtype":"uint32" }, + { "fieldname":"m_unTotalMinutesPlayed", "fieldtype":"uint32" } + ], + "struct": "GSGameplayStats_t" + }, + { + "callback_id": 208, + "fields": [ + { "fieldname":"m_SteamIDUser", "fieldtype":"CSteamID" }, + { "fieldname":"m_SteamIDGroup", "fieldtype":"CSteamID" }, + { "fieldname":"m_bMember", "fieldtype":"bool" }, + { "fieldname":"m_bOfficer", "fieldtype":"bool" } + ], + "struct": "GSClientGroupStatus_t" + }, + { + "callback_id": 209, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"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": "GSReputation_t" + }, + { + "callback_id": 210, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" } + ], + "struct": "AssociateWithClanResult_t" + }, + { + "callback_id": 211, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_cPlayersThatDontLikeCandidate", "fieldtype":"int" }, + { "fieldname":"m_cPlayersThatCandidateDoesntLike", "fieldtype":"int" }, + { "fieldname":"m_cClanPlayersThatDontLikeCandidate", "fieldtype":"int" }, + { "fieldname":"m_SteamIDCandidate", "fieldtype":"CSteamID" } + ], + "struct": "ComputeNewPlayerCompatibilityResult_t" + }, + { + "callback_id": 1800, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" } + ], + "struct": "GSStatsReceived_t" + }, + { + "callback_id": 1801, + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" } + ], + "struct": "GSStatsStored_t" + }, + { + "callback_id": 1108, + "fields": [ + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" } + ], + "struct": "GSStatsUnloaded_t" + }, + { + "callback_id": 1223, + "consts": [ + { "constname":"k_nMaxReturnPorts", "consttype":"int", "constval":"8" } + ], + "fields": [ + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_identity", "fieldtype":"SteamNetworkingIdentity" }, + { "fieldname":"m_unIP", "fieldtype":"uint32" }, + { "fieldname":"m_unPorts", "fieldtype":"uint16 [8]" } + ], + "struct": "SteamNetworkingFakeIPResult_t" + } + ], + "consts": [ + { "constname":"k_uAppIdInvalid", "consttype":"AppId_t", "constval":"0x0" }, + { "constname":"k_uDepotIdInvalid", "consttype":"DepotId_t", "constval":"0x0" }, + { "constname":"k_uAPICallInvalid", "consttype":"SteamAPICall_t", "constval":"0x0" }, + { "constname":"k_ulPartyBeaconIdInvalid", "consttype":"PartyBeaconID_t", "constval":"0" }, + { "constname":"k_HAuthTicketInvalid", "consttype":"HAuthTicket", "constval":"0" }, + { "constname":"k_unSteamAccountIDMask", "consttype":"unsigned int", "constval":"0xFFFFFFFF" }, + { "constname":"k_unSteamAccountInstanceMask", "consttype":"unsigned int", "constval":"0x000FFFFF" }, + { "constname":"k_unSteamUserDefaultInstance", "consttype":"unsigned int", "constval":"1" }, + { "constname":"k_cchGameExtraInfoMax", "consttype":"int", "constval":"64" }, + { "constname":"k_cchMaxFriendsGroupName", "consttype":"int", "constval":"64" }, + { "constname":"k_cFriendsGroupLimit", "consttype":"int", "constval":"100" }, + { "constname":"k_FriendsGroupID_Invalid", "consttype":"FriendsGroupID_t", "constval":"- 1" }, + { "constname":"k_cEnumerateFollowersMax", "consttype":"int", "constval":"50" }, + { "constname":"k_cubChatMetadataMax", "consttype":"uint32", "constval":"8192" }, + { "constname":"k_cbMaxGameServerGameDir", "consttype":"int", "constval":"32" }, + { "constname":"k_cbMaxGameServerMapName", "consttype":"int", "constval":"32" }, + { "constname":"k_cbMaxGameServerGameDescription", "consttype":"int", "constval":"64" }, + { "constname":"k_cbMaxGameServerName", "consttype":"int", "constval":"64" }, + { "constname":"k_cbMaxGameServerTags", "consttype":"int", "constval":"128" }, + { "constname":"k_cbMaxGameServerGameData", "consttype":"int", "constval":"2048" }, + { "constname":"HSERVERQUERY_INVALID", "consttype":"int", "constval":"0xffffffff" }, + { "constname":"k_unFavoriteFlagNone", "consttype":"uint32", "constval":"0x00" }, + { "constname":"k_unFavoriteFlagFavorite", "consttype":"uint32", "constval":"0x01" }, + { "constname":"k_unFavoriteFlagHistory", "consttype":"uint32", "constval":"0x02" }, + { "constname":"k_unMaxCloudFileChunkSize", "consttype":"uint32", "constval":"100 * 1024 * 1024" }, + { "constname":"k_PublishedFileIdInvalid", "consttype":"PublishedFileId_t", "constval":"0" }, + { "constname":"k_UGCHandleInvalid", "consttype":"UGCHandle_t", "constval":"0xffffffffffffffffull" }, + { "constname":"k_PublishedFileUpdateHandleInvalid", "consttype":"PublishedFileUpdateHandle_t", "constval":"0xffffffffffffffffull" }, + { "constname":"k_UGCFileStreamHandleInvalid", "consttype":"UGCFileWriteStreamHandle_t", "constval":"0xffffffffffffffffull" }, + { "constname":"k_cchPublishedDocumentTitleMax", "consttype":"uint32", "constval":"128 + 1" }, + { "constname":"k_cchPublishedDocumentDescriptionMax", "consttype":"uint32", "constval":"8000" }, + { "constname":"k_cchPublishedDocumentChangeDescriptionMax", "consttype":"uint32", "constval":"8000" }, + { "constname":"k_unEnumeratePublishedFilesMaxResults", "consttype":"uint32", "constval":"50" }, + { "constname":"k_cchTagListMax", "consttype":"uint32", "constval":"1024 + 1" }, + { "constname":"k_cchFilenameMax", "consttype":"uint32", "constval":"260" }, + { "constname":"k_cchPublishedFileURLMax", "consttype":"uint32", "constval":"256" }, + { "constname":"k_cubAppProofOfPurchaseKeyMax", "consttype":"int", "constval":"240" }, + { "constname":"k_nScreenshotMaxTaggedUsers", "consttype":"uint32", "constval":"32" }, + { "constname":"k_nScreenshotMaxTaggedPublishedFiles", "consttype":"uint32", "constval":"32" }, + { "constname":"k_cubUFSTagTypeMax", "consttype":"int", "constval":"255" }, + { "constname":"k_cubUFSTagValueMax", "consttype":"int", "constval":"255" }, + { "constname":"k_ScreenshotThumbWidth", "consttype":"int", "constval":"200" }, + { "constname":"k_UGCQueryHandleInvalid", "consttype":"UGCQueryHandle_t", "constval":"0xffffffffffffffffull" }, + { "constname":"k_UGCUpdateHandleInvalid", "consttype":"UGCUpdateHandle_t", "constval":"0xffffffffffffffffull" }, + { "constname":"kNumUGCResultsPerPage", "consttype":"uint32", "constval":"50" }, + { "constname":"k_cchDeveloperMetadataMax", "consttype":"uint32", "constval":"5000" }, + { "constname":"INVALID_HTMLBROWSER", "consttype":"uint32", "constval":"0" }, + { "constname":"k_SteamItemInstanceIDInvalid", "consttype":"SteamItemInstanceID_t", "constval":"( SteamItemInstanceID_t ) ~ 0" }, + { "constname":"k_SteamInventoryResultInvalid", "consttype":"SteamInventoryResult_t", "constval":"- 1" }, + { "constname":"k_SteamInventoryUpdateHandleInvalid", "consttype":"SteamInventoryUpdateHandle_t", "constval":"0xffffffffffffffffull" }, + { "constname":"k_HSteamNetConnection_Invalid", "consttype":"HSteamNetConnection", "constval":"0" }, + { "constname":"k_HSteamListenSocket_Invalid", "consttype":"HSteamListenSocket", "constval":"0" }, + { "constname":"k_HSteamNetPollGroup_Invalid", "consttype":"HSteamNetPollGroup", "constval":"0" }, + { "constname":"k_cchMaxSteamNetworkingErrMsg", "consttype":"int", "constval":"1024" }, + { "constname":"k_cchSteamNetworkingMaxConnectionCloseReason", "consttype":"int", "constval":"128" }, + { "constname":"k_cchSteamNetworkingMaxConnectionDescription", "consttype":"int", "constval":"128" }, + { "constname":"k_cchSteamNetworkingMaxConnectionAppName", "consttype":"int", "constval":"32" }, + { "constname":"k_nSteamNetworkConnectionInfoFlags_Unauthenticated", "consttype":"int", "constval":"1" }, + { "constname":"k_nSteamNetworkConnectionInfoFlags_Unencrypted", "consttype":"int", "constval":"2" }, + { "constname":"k_nSteamNetworkConnectionInfoFlags_LoopbackBuffers", "consttype":"int", "constval":"4" }, + { "constname":"k_nSteamNetworkConnectionInfoFlags_Fast", "consttype":"int", "constval":"8" }, + { "constname":"k_nSteamNetworkConnectionInfoFlags_Relayed", "consttype":"int", "constval":"16" }, + { "constname":"k_nSteamNetworkConnectionInfoFlags_DualWifi", "consttype":"int", "constval":"32" }, + { "constname":"k_cbMaxSteamNetworkingSocketsMessageSizeSend", "consttype":"int", "constval":"512 * 1024" }, + { "constname":"k_nSteamNetworkingSend_Unreliable", "consttype":"int", "constval":"0" }, + { "constname":"k_nSteamNetworkingSend_NoNagle", "consttype":"int", "constval":"1" }, + { "constname":"k_nSteamNetworkingSend_UnreliableNoNagle", "consttype":"int", "constval":"k_nSteamNetworkingSend_Unreliable | k_nSteamNetworkingSend_NoNagle" }, + { "constname":"k_nSteamNetworkingSend_NoDelay", "consttype":"int", "constval":"4" }, + { "constname":"k_nSteamNetworkingSend_UnreliableNoDelay", "consttype":"int", "constval":"k_nSteamNetworkingSend_Unreliable | k_nSteamNetworkingSend_NoDelay | k_nSteamNetworkingSend_NoNagle" }, + { "constname":"k_nSteamNetworkingSend_Reliable", "consttype":"int", "constval":"8" }, + { "constname":"k_nSteamNetworkingSend_ReliableNoNagle", "consttype":"int", "constval":"k_nSteamNetworkingSend_Reliable | k_nSteamNetworkingSend_NoNagle" }, + { "constname":"k_nSteamNetworkingSend_UseCurrentThread", "consttype":"int", "constval":"16" }, + { "constname":"k_nSteamNetworkingSend_AutoRestartBrokenSession", "consttype":"int", "constval":"32" }, + { "constname":"k_cchMaxSteamNetworkingPingLocationString", "consttype":"int", "constval":"1024" }, + { "constname":"k_nSteamNetworkingPing_Failed", "consttype":"int", "constval":"- 1" }, + { "constname":"k_nSteamNetworkingPing_Unknown", "consttype":"int", "constval":"- 2" }, + { "constname":"k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Default", "consttype":"int", "constval":"- 1" }, + { "constname":"k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Disable", "consttype":"int", "constval":"0" }, + { "constname":"k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Relay", "consttype":"int", "constval":"1" }, + { "constname":"k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Private", "consttype":"int", "constval":"2" }, + { "constname":"k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_Public", "consttype":"int", "constval":"4" }, + { "constname":"k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_All", "consttype":"int", "constval":"0x7fffffff" }, + { "constname":"k_SteamDatagramPOPID_dev", "consttype":"SteamNetworkingPOPID", "constval":"( ( uint32 ) 'd' << 16U ) | ( ( uint32 ) 'e' << 8U ) | ( uint32 ) 'v'" }, + { "constname":"STEAMGAMESERVER_QUERY_PORT_SHARED", "consttype":"uint16", "constval":"0xffff" }, + { "constname":"MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE", "consttype":"uint16", "constval":"STEAMGAMESERVER_QUERY_PORT_SHARED" }, + { "constname":"k_cbSteamDatagramMaxSerializedTicket", "consttype":"uint32", "constval":"512" }, + { "constname":"k_cbMaxSteamDatagramGameCoordinatorServerLoginAppData", "consttype":"uint32", "constval":"2048" }, + { "constname":"k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized", "consttype":"uint32", "constval":"4096" }, + { "constname":"k_cbSteamNetworkingSocketsFakeUDPPortRecommendedMTU", "consttype":"int", "constval":"1200" }, + { "constname":"k_cbSteamNetworkingSocketsFakeUDPPortMaxMessageSize", "consttype":"int", "constval":"4096" } + ], + "enums": [ + { + "enumname": "ESteamIPType", + "values": [ + { "name":"k_ESteamIPTypeIPv4", "value":"0" }, + { "name":"k_ESteamIPTypeIPv6", "value":"1" } + ] + }, + { + "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_EResultNone", "value":"0" }, + { "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" }, + { "name":"k_EResultAccountDeleted", "value":"114" }, + { "name":"k_EResultExistingUserCancelledLicense", "value":"115" }, + { "name":"k_EResultCommunityCooldown", "value":"116" }, + { "name":"k_EResultNoLauncherSpecified", "value":"117" }, + { "name":"k_EResultMustAgreeToSSA", "value":"118" }, + { "name":"k_EResultLauncherMigrated", "value":"119" }, + { "name":"k_EResultSteamRealmMismatch", "value":"120" }, + { "name":"k_EResultInvalidSignature", "value":"121" }, + { "name":"k_EResultParseFailure", "value":"122" }, + { "name":"k_EResultNoVerifiedPhone", "value":"123" }, + { "name":"k_EResultInsufficientBattery", "value":"124" }, + { "name":"k_EResultChargerRequired", "value":"125" }, + { "name":"k_EResultCachedCredentialInvalid", "value":"126" }, + { "name":"K_EResultPhoneNumberIsVOIP", "value":"127" } + ] + }, + { + "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" }, + { "name":"k_EAuthSessionResponseAuthTicketNetworkIdentityFailure", "value":"10" } + ] + }, + { + "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": "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": "ENotificationPosition", + "values": [ + { "name":"k_EPositionInvalid", "value":"-1" }, + { "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": "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" }, + { "name":"k_EDurationControl_ExitSoon_3h", "value":"3" }, + { "name":"k_EDurationControl_ExitSoon_5h", "value":"4" }, + { "name":"k_EDurationControl_ExitSoon_Night", "value":"5" } + ] + }, + { + "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" }, + { "name":"k_EDurationControlNotification_ExitSoon_3h", "value":"5" }, + { "name":"k_EDurationControlNotification_ExitSoon_5h", "value":"6" }, + { "name":"k_EDurationControlNotification_ExitSoon_Night", "value":"7" } + ] + }, + { + "enumname": "EDurationControlOnlineState", + "values": [ + { "name":"k_EDurationControlOnlineState_Invalid", "value":"0" }, + { "name":"k_EDurationControlOnlineState_Offline", "value":"1" }, + { "name":"k_EDurationControlOnlineState_Online", "value":"2" }, + { "name":"k_EDurationControlOnlineState_OnlineHighPri", "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": "ESteamIPv6ConnectivityProtocol", + "values": [ + { "name":"k_ESteamIPv6ConnectivityProtocol_Invalid", "value":"0" }, + { "name":"k_ESteamIPv6ConnectivityProtocol_HTTP", "value":"1" }, + { "name":"k_ESteamIPv6ConnectivityProtocol_UDP", "value":"2" } + ] + }, + { + "enumname": "ESteamIPv6ConnectivityState", + "values": [ + { "name":"k_ESteamIPv6ConnectivityState_Unknown", "value":"0" }, + { "name":"k_ESteamIPv6ConnectivityState_Good", "value":"1" }, + { "name":"k_ESteamIPv6ConnectivityState_Bad", "value":"2" } + ] + }, + { + "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": "ECommunityProfileItemType", + "values": [ + { "name":"k_ECommunityProfileItemType_AnimatedAvatar", "value":"0" }, + { "name":"k_ECommunityProfileItemType_AvatarFrame", "value":"1" }, + { "name":"k_ECommunityProfileItemType_ProfileModifier", "value":"2" }, + { "name":"k_ECommunityProfileItemType_ProfileBackground", "value":"3" }, + { "name":"k_ECommunityProfileItemType_MiniProfileBackground", "value":"4" } + ] + }, + { + "enumname": "ECommunityProfileItemProperty", + "values": [ + { "name":"k_ECommunityProfileItemProperty_ImageSmall", "value":"0" }, + { "name":"k_ECommunityProfileItemProperty_ImageLarge", "value":"1" }, + { "name":"k_ECommunityProfileItemProperty_InternalName", "value":"2" }, + { "name":"k_ECommunityProfileItemProperty_Title", "value":"3" }, + { "name":"k_ECommunityProfileItemProperty_Description", "value":"4" }, + { "name":"k_ECommunityProfileItemProperty_AppID", "value":"5" }, + { "name":"k_ECommunityProfileItemProperty_TypeID", "value":"6" }, + { "name":"k_ECommunityProfileItemProperty_Class", "value":"7" }, + { "name":"k_ECommunityProfileItemProperty_MovieWebM", "value":"8" }, + { "name":"k_ECommunityProfileItemProperty_MovieMP4", "value":"9" }, + { "name":"k_ECommunityProfileItemProperty_MovieWebMSmall", "value":"10" }, + { "name":"k_ECommunityProfileItemProperty_MovieMP4Small", "value":"11" } + ] + }, + { + "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": "EFloatingGamepadTextInputMode", + "values": [ + { "name":"k_EFloatingGamepadTextInputModeModeSingleLine", "value":"0" }, + { "name":"k_EFloatingGamepadTextInputModeModeMultipleLines", "value":"1" }, + { "name":"k_EFloatingGamepadTextInputModeModeEmail", "value":"2" }, + { "name":"k_EFloatingGamepadTextInputModeModeNumeric", "value":"3" } + ] + }, + { + "enumname": "ETextFilteringContext", + "values": [ + { "name":"k_ETextFilteringContextUnknown", "value":"0" }, + { "name":"k_ETextFilteringContextGameContent", "value":"1" }, + { "name":"k_ETextFilteringContextChat", "value":"2" }, + { "name":"k_ETextFilteringContextName", "value":"3" } + ] + }, + { + "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": "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_ERemoteStoragePlatformSwitch", "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" }, + { "name":"k_ERemoteStoragePublishedFileVisibilityUnlisted", "value":"3" } + ] + }, + { + "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": "ERemoteStorageLocalFileChange", + "values": [ + { "name":"k_ERemoteStorageLocalFileChange_Invalid", "value":"0" }, + { "name":"k_ERemoteStorageLocalFileChange_FileUpdated", "value":"1" }, + { "name":"k_ERemoteStorageLocalFileChange_FileDeleted", "value":"2" } + ] + }, + { + "enumname": "ERemoteStorageFilePathType", + "values": [ + { "name":"k_ERemoteStorageFilePathType_Invalid", "value":"0" }, + { "name":"k_ERemoteStorageFilePathType_Absolute", "value":"1" }, + { "name":"k_ERemoteStorageFilePathType_APIFilename", "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": "EP2PSessionError", + "values": [ + { "name":"k_EP2PSessionErrorNone", "value":"0" }, + { "name":"k_EP2PSessionErrorNoRightsToApp", "value":"2" }, + { "name":"k_EP2PSessionErrorTimeout", "value":"4" }, + { "name":"k_EP2PSessionErrorNotRunningApp_DELETED", "value":"1" }, + { "name":"k_EP2PSessionErrorDestinationNotLoggedIn_DELETED", "value":"3" }, + { "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_EHTTPStatusCode308PermanentRedirect", "value":"308" }, + { "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_EHTTPStatusCode444ConnectionClosed", "value":"444" }, + { "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": "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_LeftGrip_Lower", "value":"143" }, + { "name":"k_EInputActionOrigin_XBoxOne_LeftGrip_Upper", "value":"144" }, + { "name":"k_EInputActionOrigin_XBoxOne_RightGrip_Lower", "value":"145" }, + { "name":"k_EInputActionOrigin_XBoxOne_RightGrip_Upper", "value":"146" }, + { "name":"k_EInputActionOrigin_XBoxOne_Share", "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_JoyConButton_N", "value":"248" }, + { "name":"k_EInputActionOrigin_Switch_JoyConButton_E", "value":"249" }, + { "name":"k_EInputActionOrigin_Switch_JoyConButton_S", "value":"250" }, + { "name":"k_EInputActionOrigin_Switch_JoyConButton_W", "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_PS5_X", "value":"258" }, + { "name":"k_EInputActionOrigin_PS5_Circle", "value":"259" }, + { "name":"k_EInputActionOrigin_PS5_Triangle", "value":"260" }, + { "name":"k_EInputActionOrigin_PS5_Square", "value":"261" }, + { "name":"k_EInputActionOrigin_PS5_LeftBumper", "value":"262" }, + { "name":"k_EInputActionOrigin_PS5_RightBumper", "value":"263" }, + { "name":"k_EInputActionOrigin_PS5_Option", "value":"264" }, + { "name":"k_EInputActionOrigin_PS5_Create", "value":"265" }, + { "name":"k_EInputActionOrigin_PS5_Mute", "value":"266" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_Touch", "value":"267" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_Swipe", "value":"268" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_Click", "value":"269" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_DPadNorth", "value":"270" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_DPadSouth", "value":"271" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_DPadWest", "value":"272" }, + { "name":"k_EInputActionOrigin_PS5_LeftPad_DPadEast", "value":"273" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_Touch", "value":"274" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_Swipe", "value":"275" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_Click", "value":"276" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_DPadNorth", "value":"277" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_DPadSouth", "value":"278" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_DPadWest", "value":"279" }, + { "name":"k_EInputActionOrigin_PS5_RightPad_DPadEast", "value":"280" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_Touch", "value":"281" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_Swipe", "value":"282" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_Click", "value":"283" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_DPadNorth", "value":"284" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_DPadSouth", "value":"285" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_DPadWest", "value":"286" }, + { "name":"k_EInputActionOrigin_PS5_CenterPad_DPadEast", "value":"287" }, + { "name":"k_EInputActionOrigin_PS5_LeftTrigger_Pull", "value":"288" }, + { "name":"k_EInputActionOrigin_PS5_LeftTrigger_Click", "value":"289" }, + { "name":"k_EInputActionOrigin_PS5_RightTrigger_Pull", "value":"290" }, + { "name":"k_EInputActionOrigin_PS5_RightTrigger_Click", "value":"291" }, + { "name":"k_EInputActionOrigin_PS5_LeftStick_Move", "value":"292" }, + { "name":"k_EInputActionOrigin_PS5_LeftStick_Click", "value":"293" }, + { "name":"k_EInputActionOrigin_PS5_LeftStick_DPadNorth", "value":"294" }, + { "name":"k_EInputActionOrigin_PS5_LeftStick_DPadSouth", "value":"295" }, + { "name":"k_EInputActionOrigin_PS5_LeftStick_DPadWest", "value":"296" }, + { "name":"k_EInputActionOrigin_PS5_LeftStick_DPadEast", "value":"297" }, + { "name":"k_EInputActionOrigin_PS5_RightStick_Move", "value":"298" }, + { "name":"k_EInputActionOrigin_PS5_RightStick_Click", "value":"299" }, + { "name":"k_EInputActionOrigin_PS5_RightStick_DPadNorth", "value":"300" }, + { "name":"k_EInputActionOrigin_PS5_RightStick_DPadSouth", "value":"301" }, + { "name":"k_EInputActionOrigin_PS5_RightStick_DPadWest", "value":"302" }, + { "name":"k_EInputActionOrigin_PS5_RightStick_DPadEast", "value":"303" }, + { "name":"k_EInputActionOrigin_PS5_DPad_North", "value":"304" }, + { "name":"k_EInputActionOrigin_PS5_DPad_South", "value":"305" }, + { "name":"k_EInputActionOrigin_PS5_DPad_West", "value":"306" }, + { "name":"k_EInputActionOrigin_PS5_DPad_East", "value":"307" }, + { "name":"k_EInputActionOrigin_PS5_Gyro_Move", "value":"308" }, + { "name":"k_EInputActionOrigin_PS5_Gyro_Pitch", "value":"309" }, + { "name":"k_EInputActionOrigin_PS5_Gyro_Yaw", "value":"310" }, + { "name":"k_EInputActionOrigin_PS5_Gyro_Roll", "value":"311" }, + { "name":"k_EInputActionOrigin_PS5_DPad_Move", "value":"312" }, + { "name":"k_EInputActionOrigin_PS5_LeftGrip", "value":"313" }, + { "name":"k_EInputActionOrigin_PS5_RightGrip", "value":"314" }, + { "name":"k_EInputActionOrigin_PS5_LeftFn", "value":"315" }, + { "name":"k_EInputActionOrigin_PS5_RightFn", "value":"316" }, + { "name":"k_EInputActionOrigin_PS5_Reserved5", "value":"317" }, + { "name":"k_EInputActionOrigin_PS5_Reserved6", "value":"318" }, + { "name":"k_EInputActionOrigin_PS5_Reserved7", "value":"319" }, + { "name":"k_EInputActionOrigin_PS5_Reserved8", "value":"320" }, + { "name":"k_EInputActionOrigin_PS5_Reserved9", "value":"321" }, + { "name":"k_EInputActionOrigin_PS5_Reserved10", "value":"322" }, + { "name":"k_EInputActionOrigin_PS5_Reserved11", "value":"323" }, + { "name":"k_EInputActionOrigin_PS5_Reserved12", "value":"324" }, + { "name":"k_EInputActionOrigin_PS5_Reserved13", "value":"325" }, + { "name":"k_EInputActionOrigin_PS5_Reserved14", "value":"326" }, + { "name":"k_EInputActionOrigin_PS5_Reserved15", "value":"327" }, + { "name":"k_EInputActionOrigin_PS5_Reserved16", "value":"328" }, + { "name":"k_EInputActionOrigin_PS5_Reserved17", "value":"329" }, + { "name":"k_EInputActionOrigin_PS5_Reserved18", "value":"330" }, + { "name":"k_EInputActionOrigin_PS5_Reserved19", "value":"331" }, + { "name":"k_EInputActionOrigin_PS5_Reserved20", "value":"332" }, + { "name":"k_EInputActionOrigin_SteamDeck_A", "value":"333" }, + { "name":"k_EInputActionOrigin_SteamDeck_B", "value":"334" }, + { "name":"k_EInputActionOrigin_SteamDeck_X", "value":"335" }, + { "name":"k_EInputActionOrigin_SteamDeck_Y", "value":"336" }, + { "name":"k_EInputActionOrigin_SteamDeck_L1", "value":"337" }, + { "name":"k_EInputActionOrigin_SteamDeck_R1", "value":"338" }, + { "name":"k_EInputActionOrigin_SteamDeck_Menu", "value":"339" }, + { "name":"k_EInputActionOrigin_SteamDeck_View", "value":"340" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_Touch", "value":"341" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_Swipe", "value":"342" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_Click", "value":"343" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_DPadNorth", "value":"344" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_DPadSouth", "value":"345" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_DPadWest", "value":"346" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftPad_DPadEast", "value":"347" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_Touch", "value":"348" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_Swipe", "value":"349" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_Click", "value":"350" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_DPadNorth", "value":"351" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_DPadSouth", "value":"352" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_DPadWest", "value":"353" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightPad_DPadEast", "value":"354" }, + { "name":"k_EInputActionOrigin_SteamDeck_L2_SoftPull", "value":"355" }, + { "name":"k_EInputActionOrigin_SteamDeck_L2", "value":"356" }, + { "name":"k_EInputActionOrigin_SteamDeck_R2_SoftPull", "value":"357" }, + { "name":"k_EInputActionOrigin_SteamDeck_R2", "value":"358" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftStick_Move", "value":"359" }, + { "name":"k_EInputActionOrigin_SteamDeck_L3", "value":"360" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftStick_DPadNorth", "value":"361" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftStick_DPadSouth", "value":"362" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftStick_DPadWest", "value":"363" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftStick_DPadEast", "value":"364" }, + { "name":"k_EInputActionOrigin_SteamDeck_LeftStick_Touch", "value":"365" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightStick_Move", "value":"366" }, + { "name":"k_EInputActionOrigin_SteamDeck_R3", "value":"367" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightStick_DPadNorth", "value":"368" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightStick_DPadSouth", "value":"369" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightStick_DPadWest", "value":"370" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightStick_DPadEast", "value":"371" }, + { "name":"k_EInputActionOrigin_SteamDeck_RightStick_Touch", "value":"372" }, + { "name":"k_EInputActionOrigin_SteamDeck_L4", "value":"373" }, + { "name":"k_EInputActionOrigin_SteamDeck_R4", "value":"374" }, + { "name":"k_EInputActionOrigin_SteamDeck_L5", "value":"375" }, + { "name":"k_EInputActionOrigin_SteamDeck_R5", "value":"376" }, + { "name":"k_EInputActionOrigin_SteamDeck_DPad_Move", "value":"377" }, + { "name":"k_EInputActionOrigin_SteamDeck_DPad_North", "value":"378" }, + { "name":"k_EInputActionOrigin_SteamDeck_DPad_South", "value":"379" }, + { "name":"k_EInputActionOrigin_SteamDeck_DPad_West", "value":"380" }, + { "name":"k_EInputActionOrigin_SteamDeck_DPad_East", "value":"381" }, + { "name":"k_EInputActionOrigin_SteamDeck_Gyro_Move", "value":"382" }, + { "name":"k_EInputActionOrigin_SteamDeck_Gyro_Pitch", "value":"383" }, + { "name":"k_EInputActionOrigin_SteamDeck_Gyro_Yaw", "value":"384" }, + { "name":"k_EInputActionOrigin_SteamDeck_Gyro_Roll", "value":"385" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved1", "value":"386" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved2", "value":"387" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved3", "value":"388" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved4", "value":"389" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved5", "value":"390" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved6", "value":"391" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved7", "value":"392" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved8", "value":"393" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved9", "value":"394" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved10", "value":"395" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved11", "value":"396" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved12", "value":"397" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved13", "value":"398" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved14", "value":"399" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved15", "value":"400" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved16", "value":"401" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved17", "value":"402" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved18", "value":"403" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved19", "value":"404" }, + { "name":"k_EInputActionOrigin_SteamDeck_Reserved20", "value":"405" }, + { "name":"k_EInputActionOrigin_Count", "value":"406" }, + { "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": "EControllerHapticLocation", + "values": [ + { "name":"k_EControllerHapticLocation_Left", "value":"1" }, + { "name":"k_EControllerHapticLocation_Right", "value":"2" }, + { "name":"k_EControllerHapticLocation_Both", "value":"3" } + ] + }, + { + "enumname": "EControllerHapticType", + "values": [ + { "name":"k_EControllerHapticType_Off", "value":"0" }, + { "name":"k_EControllerHapticType_Tick", "value":"1" }, + { "name":"k_EControllerHapticType_Click", "value":"2" } + ] + }, + { + "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_PS5Controller", "value":"13" }, + { "name":"k_ESteamInputType_SteamDeckController", "value":"14" }, + { "name":"k_ESteamInputType_Count", "value":"15" }, + { "name":"k_ESteamInputType_MaximumPossibleValue", "value":"255" } + ] + }, + { + "enumname": "ESteamInputConfigurationEnableType", + "values": [ + { "name":"k_ESteamInputConfigurationEnableType_None", "value":"0" }, + { "name":"k_ESteamInputConfigurationEnableType_Playstation", "value":"1" }, + { "name":"k_ESteamInputConfigurationEnableType_Xbox", "value":"2" }, + { "name":"k_ESteamInputConfigurationEnableType_Generic", "value":"4" }, + { "name":"k_ESteamInputConfigurationEnableType_Switch", "value":"8" } + ] + }, + { + "enumname": "ESteamInputLEDFlag", + "values": [ + { "name":"k_ESteamInputLEDFlag_SetColor", "value":"0" }, + { "name":"k_ESteamInputLEDFlag_RestoreUserDefault", "value":"1" } + ] + }, + { + "enumname": "ESteamInputGlyphSize", + "values": [ + { "name":"k_ESteamInputGlyphSize_Small", "value":"0" }, + { "name":"k_ESteamInputGlyphSize_Medium", "value":"1" }, + { "name":"k_ESteamInputGlyphSize_Large", "value":"2" }, + { "name":"k_ESteamInputGlyphSize_Count", "value":"3" } + ] + }, + { + "enumname": "ESteamInputGlyphStyle", + "values": [ + { "name":"ESteamInputGlyphStyle_Knockout", "value":"0" }, + { "name":"ESteamInputGlyphStyle_Light", "value":"1" }, + { "name":"ESteamInputGlyphStyle_Dark", "value":"2" }, + { "name":"ESteamInputGlyphStyle_NeutralColorABXY", "value":"16" }, + { "name":"ESteamInputGlyphStyle_SolidABXY", "value":"32" } + ] + }, + { + "enumname": "ESteamInputActionEventType", + "values": [ + { "name":"ESteamInputActionEventType_DigitalAction", "value":"0" }, + { "name":"ESteamInputActionEventType_AnalogAction", "value":"1" } + ] + }, + { + "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_PS5_X", "value":"245" }, + { "name":"k_EControllerActionOrigin_PS5_Circle", "value":"246" }, + { "name":"k_EControllerActionOrigin_PS5_Triangle", "value":"247" }, + { "name":"k_EControllerActionOrigin_PS5_Square", "value":"248" }, + { "name":"k_EControllerActionOrigin_PS5_LeftBumper", "value":"249" }, + { "name":"k_EControllerActionOrigin_PS5_RightBumper", "value":"250" }, + { "name":"k_EControllerActionOrigin_PS5_Option", "value":"251" }, + { "name":"k_EControllerActionOrigin_PS5_Create", "value":"252" }, + { "name":"k_EControllerActionOrigin_PS5_Mute", "value":"253" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_Touch", "value":"254" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_Swipe", "value":"255" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_Click", "value":"256" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_DPadNorth", "value":"257" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_DPadSouth", "value":"258" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_DPadWest", "value":"259" }, + { "name":"k_EControllerActionOrigin_PS5_LeftPad_DPadEast", "value":"260" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_Touch", "value":"261" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_Swipe", "value":"262" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_Click", "value":"263" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_DPadNorth", "value":"264" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_DPadSouth", "value":"265" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_DPadWest", "value":"266" }, + { "name":"k_EControllerActionOrigin_PS5_RightPad_DPadEast", "value":"267" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_Touch", "value":"268" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_Swipe", "value":"269" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_Click", "value":"270" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_DPadNorth", "value":"271" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_DPadSouth", "value":"272" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_DPadWest", "value":"273" }, + { "name":"k_EControllerActionOrigin_PS5_CenterPad_DPadEast", "value":"274" }, + { "name":"k_EControllerActionOrigin_PS5_LeftTrigger_Pull", "value":"275" }, + { "name":"k_EControllerActionOrigin_PS5_LeftTrigger_Click", "value":"276" }, + { "name":"k_EControllerActionOrigin_PS5_RightTrigger_Pull", "value":"277" }, + { "name":"k_EControllerActionOrigin_PS5_RightTrigger_Click", "value":"278" }, + { "name":"k_EControllerActionOrigin_PS5_LeftStick_Move", "value":"279" }, + { "name":"k_EControllerActionOrigin_PS5_LeftStick_Click", "value":"280" }, + { "name":"k_EControllerActionOrigin_PS5_LeftStick_DPadNorth", "value":"281" }, + { "name":"k_EControllerActionOrigin_PS5_LeftStick_DPadSouth", "value":"282" }, + { "name":"k_EControllerActionOrigin_PS5_LeftStick_DPadWest", "value":"283" }, + { "name":"k_EControllerActionOrigin_PS5_LeftStick_DPadEast", "value":"284" }, + { "name":"k_EControllerActionOrigin_PS5_RightStick_Move", "value":"285" }, + { "name":"k_EControllerActionOrigin_PS5_RightStick_Click", "value":"286" }, + { "name":"k_EControllerActionOrigin_PS5_RightStick_DPadNorth", "value":"287" }, + { "name":"k_EControllerActionOrigin_PS5_RightStick_DPadSouth", "value":"288" }, + { "name":"k_EControllerActionOrigin_PS5_RightStick_DPadWest", "value":"289" }, + { "name":"k_EControllerActionOrigin_PS5_RightStick_DPadEast", "value":"290" }, + { "name":"k_EControllerActionOrigin_PS5_DPad_Move", "value":"291" }, + { "name":"k_EControllerActionOrigin_PS5_DPad_North", "value":"292" }, + { "name":"k_EControllerActionOrigin_PS5_DPad_South", "value":"293" }, + { "name":"k_EControllerActionOrigin_PS5_DPad_West", "value":"294" }, + { "name":"k_EControllerActionOrigin_PS5_DPad_East", "value":"295" }, + { "name":"k_EControllerActionOrigin_PS5_Gyro_Move", "value":"296" }, + { "name":"k_EControllerActionOrigin_PS5_Gyro_Pitch", "value":"297" }, + { "name":"k_EControllerActionOrigin_PS5_Gyro_Yaw", "value":"298" }, + { "name":"k_EControllerActionOrigin_PS5_Gyro_Roll", "value":"299" }, + { "name":"k_EControllerActionOrigin_XBoxOne_LeftGrip_Lower", "value":"300" }, + { "name":"k_EControllerActionOrigin_XBoxOne_LeftGrip_Upper", "value":"301" }, + { "name":"k_EControllerActionOrigin_XBoxOne_RightGrip_Lower", "value":"302" }, + { "name":"k_EControllerActionOrigin_XBoxOne_RightGrip_Upper", "value":"303" }, + { "name":"k_EControllerActionOrigin_XBoxOne_Share", "value":"304" }, + { "name":"k_EControllerActionOrigin_SteamDeck_A", "value":"305" }, + { "name":"k_EControllerActionOrigin_SteamDeck_B", "value":"306" }, + { "name":"k_EControllerActionOrigin_SteamDeck_X", "value":"307" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Y", "value":"308" }, + { "name":"k_EControllerActionOrigin_SteamDeck_L1", "value":"309" }, + { "name":"k_EControllerActionOrigin_SteamDeck_R1", "value":"310" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Menu", "value":"311" }, + { "name":"k_EControllerActionOrigin_SteamDeck_View", "value":"312" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_Touch", "value":"313" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_Swipe", "value":"314" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_Click", "value":"315" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_DPadNorth", "value":"316" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_DPadSouth", "value":"317" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_DPadWest", "value":"318" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftPad_DPadEast", "value":"319" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_Touch", "value":"320" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_Swipe", "value":"321" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_Click", "value":"322" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_DPadNorth", "value":"323" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_DPadSouth", "value":"324" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_DPadWest", "value":"325" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightPad_DPadEast", "value":"326" }, + { "name":"k_EControllerActionOrigin_SteamDeck_L2_SoftPull", "value":"327" }, + { "name":"k_EControllerActionOrigin_SteamDeck_L2", "value":"328" }, + { "name":"k_EControllerActionOrigin_SteamDeck_R2_SoftPull", "value":"329" }, + { "name":"k_EControllerActionOrigin_SteamDeck_R2", "value":"330" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftStick_Move", "value":"331" }, + { "name":"k_EControllerActionOrigin_SteamDeck_L3", "value":"332" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftStick_DPadNorth", "value":"333" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftStick_DPadSouth", "value":"334" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftStick_DPadWest", "value":"335" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftStick_DPadEast", "value":"336" }, + { "name":"k_EControllerActionOrigin_SteamDeck_LeftStick_Touch", "value":"337" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightStick_Move", "value":"338" }, + { "name":"k_EControllerActionOrigin_SteamDeck_R3", "value":"339" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightStick_DPadNorth", "value":"340" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightStick_DPadSouth", "value":"341" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightStick_DPadWest", "value":"342" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightStick_DPadEast", "value":"343" }, + { "name":"k_EControllerActionOrigin_SteamDeck_RightStick_Touch", "value":"344" }, + { "name":"k_EControllerActionOrigin_SteamDeck_L4", "value":"345" }, + { "name":"k_EControllerActionOrigin_SteamDeck_R4", "value":"346" }, + { "name":"k_EControllerActionOrigin_SteamDeck_L5", "value":"347" }, + { "name":"k_EControllerActionOrigin_SteamDeck_R5", "value":"348" }, + { "name":"k_EControllerActionOrigin_SteamDeck_DPad_Move", "value":"349" }, + { "name":"k_EControllerActionOrigin_SteamDeck_DPad_North", "value":"350" }, + { "name":"k_EControllerActionOrigin_SteamDeck_DPad_South", "value":"351" }, + { "name":"k_EControllerActionOrigin_SteamDeck_DPad_West", "value":"352" }, + { "name":"k_EControllerActionOrigin_SteamDeck_DPad_East", "value":"353" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Gyro_Move", "value":"354" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Gyro_Pitch", "value":"355" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Gyro_Yaw", "value":"356" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Gyro_Roll", "value":"357" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved1", "value":"358" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved2", "value":"359" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved3", "value":"360" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved4", "value":"361" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved5", "value":"362" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved6", "value":"363" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved7", "value":"364" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved8", "value":"365" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved9", "value":"366" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved10", "value":"367" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved11", "value":"368" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved12", "value":"369" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved13", "value":"370" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved14", "value":"371" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved15", "value":"372" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved16", "value":"373" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved17", "value":"374" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved18", "value":"375" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved19", "value":"376" }, + { "name":"k_EControllerActionOrigin_SteamDeck_Reserved20", "value":"377" }, + { "name":"k_EControllerActionOrigin_Switch_JoyConButton_N", "value":"378" }, + { "name":"k_EControllerActionOrigin_Switch_JoyConButton_E", "value":"379" }, + { "name":"k_EControllerActionOrigin_Switch_JoyConButton_S", "value":"380" }, + { "name":"k_EControllerActionOrigin_Switch_JoyConButton_W", "value":"381" }, + { "name":"k_EControllerActionOrigin_PS5_LeftGrip", "value":"382" }, + { "name":"k_EControllerActionOrigin_PS5_RightGrip", "value":"383" }, + { "name":"k_EControllerActionOrigin_PS5_LeftFn", "value":"384" }, + { "name":"k_EControllerActionOrigin_PS5_RightFn", "value":"385" }, + { "name":"k_EControllerActionOrigin_Count", "value":"386" }, + { "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" }, + { "name":"k_EUGCQuery_RankedByLastUpdatedDate", "value":"19" } + ] + }, + { + "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": "EUGCContentDescriptorID", + "values": [ + { "name":"k_EUGCContentDescriptor_NudityOrSexualContent", "value":"1" }, + { "name":"k_EUGCContentDescriptor_FrequentViolenceOrGore", "value":"2" }, + { "name":"k_EUGCContentDescriptor_AdultOnlySexualContent", "value":"3" }, + { "name":"k_EUGCContentDescriptor_GratuitousSexualContent", "value":"4" }, + { "name":"k_EUGCContentDescriptor_AnyMatureContent", "value":"5" } + ] + }, + { + "enumname": "ESteamItemFlags", + "values": [ + { "name":"k_ESteamItemNoTrade", "value":"1" }, + { "name":"k_ESteamItemRemoved", "value":"256" }, + { "name":"k_ESteamItemConsumed", "value":"512" } + ] + }, + { + "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_EFeatureSiteLicense", "value":"13" }, + { "name":"k_EFeatureKioskMode", "value":"14" }, + { "name":"k_EFeatureMax", "value":"15" } + ] + }, + { + "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" } + ] + }, + { + "enumname": "ESteamNetworkingAvailability", + "values": [ + { "name":"k_ESteamNetworkingAvailability_CannotTry", "value":"-102" }, + { "name":"k_ESteamNetworkingAvailability_Failed", "value":"-101" }, + { "name":"k_ESteamNetworkingAvailability_Previously", "value":"-100" }, + { "name":"k_ESteamNetworkingAvailability_Retrying", "value":"-10" }, + { "name":"k_ESteamNetworkingAvailability_NeverTried", "value":"1" }, + { "name":"k_ESteamNetworkingAvailability_Waiting", "value":"2" }, + { "name":"k_ESteamNetworkingAvailability_Attempting", "value":"3" }, + { "name":"k_ESteamNetworkingAvailability_Current", "value":"100" }, + { "name":"k_ESteamNetworkingAvailability_Unknown", "value":"0" }, + { "name":"k_ESteamNetworkingAvailability__Force32bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingIdentityType", + "values": [ + { "name":"k_ESteamNetworkingIdentityType_Invalid", "value":"0" }, + { "name":"k_ESteamNetworkingIdentityType_SteamID", "value":"16" }, + { "name":"k_ESteamNetworkingIdentityType_XboxPairwiseID", "value":"17" }, + { "name":"k_ESteamNetworkingIdentityType_SonyPSN", "value":"18" }, + { "name":"k_ESteamNetworkingIdentityType_GoogleStadia", "value":"19" }, + { "name":"k_ESteamNetworkingIdentityType_IPAddress", "value":"1" }, + { "name":"k_ESteamNetworkingIdentityType_GenericString", "value":"2" }, + { "name":"k_ESteamNetworkingIdentityType_GenericBytes", "value":"3" }, + { "name":"k_ESteamNetworkingIdentityType_UnknownType", "value":"4" }, + { "name":"k_ESteamNetworkingIdentityType__Force32bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingFakeIPType", + "values": [ + { "name":"k_ESteamNetworkingFakeIPType_Invalid", "value":"0" }, + { "name":"k_ESteamNetworkingFakeIPType_NotFake", "value":"1" }, + { "name":"k_ESteamNetworkingFakeIPType_GlobalIPv4", "value":"2" }, + { "name":"k_ESteamNetworkingFakeIPType_LocalIPv4", "value":"3" }, + { "name":"k_ESteamNetworkingFakeIPType__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingConnectionState", + "values": [ + { "name":"k_ESteamNetworkingConnectionState_None", "value":"0" }, + { "name":"k_ESteamNetworkingConnectionState_Connecting", "value":"1" }, + { "name":"k_ESteamNetworkingConnectionState_FindingRoute", "value":"2" }, + { "name":"k_ESteamNetworkingConnectionState_Connected", "value":"3" }, + { "name":"k_ESteamNetworkingConnectionState_ClosedByPeer", "value":"4" }, + { "name":"k_ESteamNetworkingConnectionState_ProblemDetectedLocally", "value":"5" }, + { "name":"k_ESteamNetworkingConnectionState_FinWait", "value":"-1" }, + { "name":"k_ESteamNetworkingConnectionState_Linger", "value":"-2" }, + { "name":"k_ESteamNetworkingConnectionState_Dead", "value":"-3" }, + { "name":"k_ESteamNetworkingConnectionState__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetConnectionEnd", + "values": [ + { "name":"k_ESteamNetConnectionEnd_Invalid", "value":"0" }, + { "name":"k_ESteamNetConnectionEnd_App_Min", "value":"1000" }, + { "name":"k_ESteamNetConnectionEnd_App_Generic", "value":"1000" }, + { "name":"k_ESteamNetConnectionEnd_App_Max", "value":"1999" }, + { "name":"k_ESteamNetConnectionEnd_AppException_Min", "value":"2000" }, + { "name":"k_ESteamNetConnectionEnd_AppException_Generic", "value":"2000" }, + { "name":"k_ESteamNetConnectionEnd_AppException_Max", "value":"2999" }, + { "name":"k_ESteamNetConnectionEnd_Local_Min", "value":"3000" }, + { "name":"k_ESteamNetConnectionEnd_Local_OfflineMode", "value":"3001" }, + { "name":"k_ESteamNetConnectionEnd_Local_ManyRelayConnectivity", "value":"3002" }, + { "name":"k_ESteamNetConnectionEnd_Local_HostedServerPrimaryRelay", "value":"3003" }, + { "name":"k_ESteamNetConnectionEnd_Local_NetworkConfig", "value":"3004" }, + { "name":"k_ESteamNetConnectionEnd_Local_Rights", "value":"3005" }, + { "name":"k_ESteamNetConnectionEnd_Local_P2P_ICE_NoPublicAddresses", "value":"3006" }, + { "name":"k_ESteamNetConnectionEnd_Local_Max", "value":"3999" }, + { "name":"k_ESteamNetConnectionEnd_Remote_Min", "value":"4000" }, + { "name":"k_ESteamNetConnectionEnd_Remote_Timeout", "value":"4001" }, + { "name":"k_ESteamNetConnectionEnd_Remote_BadCrypt", "value":"4002" }, + { "name":"k_ESteamNetConnectionEnd_Remote_BadCert", "value":"4003" }, + { "name":"k_ESteamNetConnectionEnd_Remote_BadProtocolVersion", "value":"4006" }, + { "name":"k_ESteamNetConnectionEnd_Remote_P2P_ICE_NoPublicAddresses", "value":"4007" }, + { "name":"k_ESteamNetConnectionEnd_Remote_Max", "value":"4999" }, + { "name":"k_ESteamNetConnectionEnd_Misc_Min", "value":"5000" }, + { "name":"k_ESteamNetConnectionEnd_Misc_Generic", "value":"5001" }, + { "name":"k_ESteamNetConnectionEnd_Misc_InternalError", "value":"5002" }, + { "name":"k_ESteamNetConnectionEnd_Misc_Timeout", "value":"5003" }, + { "name":"k_ESteamNetConnectionEnd_Misc_SteamConnectivity", "value":"5005" }, + { "name":"k_ESteamNetConnectionEnd_Misc_NoRelaySessionsToClient", "value":"5006" }, + { "name":"k_ESteamNetConnectionEnd_Misc_P2P_Rendezvous", "value":"5008" }, + { "name":"k_ESteamNetConnectionEnd_Misc_P2P_NAT_Firewall", "value":"5009" }, + { "name":"k_ESteamNetConnectionEnd_Misc_PeerSentNoConnection", "value":"5010" }, + { "name":"k_ESteamNetConnectionEnd_Misc_Max", "value":"5999" }, + { "name":"k_ESteamNetConnectionEnd__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingConfigScope", + "values": [ + { "name":"k_ESteamNetworkingConfig_Global", "value":"1" }, + { "name":"k_ESteamNetworkingConfig_SocketsInterface", "value":"2" }, + { "name":"k_ESteamNetworkingConfig_ListenSocket", "value":"3" }, + { "name":"k_ESteamNetworkingConfig_Connection", "value":"4" }, + { "name":"k_ESteamNetworkingConfigScope__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingConfigDataType", + "values": [ + { "name":"k_ESteamNetworkingConfig_Int32", "value":"1" }, + { "name":"k_ESteamNetworkingConfig_Int64", "value":"2" }, + { "name":"k_ESteamNetworkingConfig_Float", "value":"3" }, + { "name":"k_ESteamNetworkingConfig_String", "value":"4" }, + { "name":"k_ESteamNetworkingConfig_Ptr", "value":"5" }, + { "name":"k_ESteamNetworkingConfigDataType__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingConfigValue", + "values": [ + { "name":"k_ESteamNetworkingConfig_Invalid", "value":"0" }, + { "name":"k_ESteamNetworkingConfig_TimeoutInitial", "value":"24" }, + { "name":"k_ESteamNetworkingConfig_TimeoutConnected", "value":"25" }, + { "name":"k_ESteamNetworkingConfig_SendBufferSize", "value":"9" }, + { "name":"k_ESteamNetworkingConfig_ConnectionUserData", "value":"40" }, + { "name":"k_ESteamNetworkingConfig_SendRateMin", "value":"10" }, + { "name":"k_ESteamNetworkingConfig_SendRateMax", "value":"11" }, + { "name":"k_ESteamNetworkingConfig_NagleTime", "value":"12" }, + { "name":"k_ESteamNetworkingConfig_IP_AllowWithoutAuth", "value":"23" }, + { "name":"k_ESteamNetworkingConfig_MTU_PacketSize", "value":"32" }, + { "name":"k_ESteamNetworkingConfig_MTU_DataSize", "value":"33" }, + { "name":"k_ESteamNetworkingConfig_Unencrypted", "value":"34" }, + { "name":"k_ESteamNetworkingConfig_SymmetricConnect", "value":"37" }, + { "name":"k_ESteamNetworkingConfig_LocalVirtualPort", "value":"38" }, + { "name":"k_ESteamNetworkingConfig_DualWifi_Enable", "value":"39" }, + { "name":"k_ESteamNetworkingConfig_EnableDiagnosticsUI", "value":"46" }, + { "name":"k_ESteamNetworkingConfig_FakePacketLoss_Send", "value":"2" }, + { "name":"k_ESteamNetworkingConfig_FakePacketLoss_Recv", "value":"3" }, + { "name":"k_ESteamNetworkingConfig_FakePacketLag_Send", "value":"4" }, + { "name":"k_ESteamNetworkingConfig_FakePacketLag_Recv", "value":"5" }, + { "name":"k_ESteamNetworkingConfig_FakePacketReorder_Send", "value":"6" }, + { "name":"k_ESteamNetworkingConfig_FakePacketReorder_Recv", "value":"7" }, + { "name":"k_ESteamNetworkingConfig_FakePacketReorder_Time", "value":"8" }, + { "name":"k_ESteamNetworkingConfig_FakePacketDup_Send", "value":"26" }, + { "name":"k_ESteamNetworkingConfig_FakePacketDup_Recv", "value":"27" }, + { "name":"k_ESteamNetworkingConfig_FakePacketDup_TimeMax", "value":"28" }, + { "name":"k_ESteamNetworkingConfig_PacketTraceMaxBytes", "value":"41" }, + { "name":"k_ESteamNetworkingConfig_FakeRateLimit_Send_Rate", "value":"42" }, + { "name":"k_ESteamNetworkingConfig_FakeRateLimit_Send_Burst", "value":"43" }, + { "name":"k_ESteamNetworkingConfig_FakeRateLimit_Recv_Rate", "value":"44" }, + { "name":"k_ESteamNetworkingConfig_FakeRateLimit_Recv_Burst", "value":"45" }, + { "name":"k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged", "value":"201" }, + { "name":"k_ESteamNetworkingConfig_Callback_AuthStatusChanged", "value":"202" }, + { "name":"k_ESteamNetworkingConfig_Callback_RelayNetworkStatusChanged", "value":"203" }, + { "name":"k_ESteamNetworkingConfig_Callback_MessagesSessionRequest", "value":"204" }, + { "name":"k_ESteamNetworkingConfig_Callback_MessagesSessionFailed", "value":"205" }, + { "name":"k_ESteamNetworkingConfig_Callback_CreateConnectionSignaling", "value":"206" }, + { "name":"k_ESteamNetworkingConfig_Callback_FakeIPResult", "value":"207" }, + { "name":"k_ESteamNetworkingConfig_P2P_STUN_ServerList", "value":"103" }, + { "name":"k_ESteamNetworkingConfig_P2P_Transport_ICE_Enable", "value":"104" }, + { "name":"k_ESteamNetworkingConfig_P2P_Transport_ICE_Penalty", "value":"105" }, + { "name":"k_ESteamNetworkingConfig_P2P_Transport_SDR_Penalty", "value":"106" }, + { "name":"k_ESteamNetworkingConfig_P2P_TURN_ServerList", "value":"107" }, + { "name":"k_ESteamNetworkingConfig_P2P_TURN_UserList", "value":"108" }, + { "name":"k_ESteamNetworkingConfig_P2P_TURN_PassList", "value":"109" }, + { "name":"k_ESteamNetworkingConfig_P2P_Transport_ICE_Implementation", "value":"110" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_ConsecutitivePingTimeoutsFailInitial", "value":"19" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_ConsecutitivePingTimeoutsFail", "value":"20" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_MinPingsBeforePingAccurate", "value":"21" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_SingleSocket", "value":"22" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_ForceRelayCluster", "value":"29" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_DebugTicketAddress", "value":"30" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_ForceProxyAddr", "value":"31" }, + { "name":"k_ESteamNetworkingConfig_SDRClient_FakeClusterPing", "value":"36" }, + { "name":"k_ESteamNetworkingConfig_LogLevel_AckRTT", "value":"13" }, + { "name":"k_ESteamNetworkingConfig_LogLevel_PacketDecode", "value":"14" }, + { "name":"k_ESteamNetworkingConfig_LogLevel_Message", "value":"15" }, + { "name":"k_ESteamNetworkingConfig_LogLevel_PacketGaps", "value":"16" }, + { "name":"k_ESteamNetworkingConfig_LogLevel_P2PRendezvous", "value":"17" }, + { "name":"k_ESteamNetworkingConfig_LogLevel_SDRRelayPings", "value":"18" }, + { "name":"k_ESteamNetworkingConfig_DELETED_EnumerateDevVars", "value":"35" }, + { "name":"k_ESteamNetworkingConfigValue__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingGetConfigValueResult", + "values": [ + { "name":"k_ESteamNetworkingGetConfigValue_BadValue", "value":"-1" }, + { "name":"k_ESteamNetworkingGetConfigValue_BadScopeObj", "value":"-2" }, + { "name":"k_ESteamNetworkingGetConfigValue_BufferTooSmall", "value":"-3" }, + { "name":"k_ESteamNetworkingGetConfigValue_OK", "value":"1" }, + { "name":"k_ESteamNetworkingGetConfigValue_OKInherited", "value":"2" }, + { "name":"k_ESteamNetworkingGetConfigValueResult__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "ESteamNetworkingSocketsDebugOutputType", + "values": [ + { "name":"k_ESteamNetworkingSocketsDebugOutputType_None", "value":"0" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Bug", "value":"1" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Error", "value":"2" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Important", "value":"3" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Warning", "value":"4" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Msg", "value":"5" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Verbose", "value":"6" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Debug", "value":"7" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType_Everything", "value":"8" }, + { "name":"k_ESteamNetworkingSocketsDebugOutputType__Force32Bit", "value":"2147483647" } + ] + }, + { + "enumname": "EServerMode", + "values": [ + { "name":"eServerModeInvalid", "value":"0" }, + { "name":"eServerModeNoAuthentication", "value":"1" }, + { "name":"eServerModeAuthentication", "value":"2" }, + { "name":"eServerModeAuthenticationAndSecure", "value":"3" } + ] + } + ], + "interfaces": [ + { + "classname": "ISteamClient", + "fields": [], + "methods": [ + { + "methodname": "CreateSteamPipe", + "methodname_flat": "SteamAPI_ISteamClient_CreateSteamPipe", + "params": [], + "returntype": "HSteamPipe" + }, + { + "methodname": "BReleaseSteamPipe", + "methodname_flat": "SteamAPI_ISteamClient_BReleaseSteamPipe", + "params": [ + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" } + ], + "returntype": "bool" + }, + { + "methodname": "ConnectToGlobalUser", + "methodname_flat": "SteamAPI_ISteamClient_ConnectToGlobalUser", + "params": [ + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" } + ], + "returntype": "HSteamUser" + }, + { + "methodname": "CreateLocalUser", + "methodname_flat": "SteamAPI_ISteamClient_CreateLocalUser", + "params": [ + { "paramname":"phSteamPipe", "paramtype":"HSteamPipe *" }, + { "paramname":"eAccountType", "paramtype":"EAccountType" } + ], + "returntype": "HSteamUser" + }, + { + "methodname": "ReleaseUser", + "methodname_flat": "SteamAPI_ISteamClient_ReleaseUser", + "params": [ + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"hUser", "paramtype":"HSteamUser" } + ], + "returntype": "void" + }, + { + "methodname": "GetISteamUser", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamUser", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamUser *" + }, + { + "methodname": "GetISteamGameServer", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamGameServer", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamGameServer *" + }, + { + "methodname": "SetLocalIPBinding", + "methodname_flat": "SteamAPI_ISteamClient_SetLocalIPBinding", + "params": [ + { "paramname":"unIP", "paramtype":"const SteamIPAddress_t &" }, + { "paramname":"usPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "GetISteamFriends", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamFriends", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamFriends *" + }, + { + "methodname": "GetISteamUtils", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamUtils", + "params": [ + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamUtils *" + }, + { + "methodname": "GetISteamMatchmaking", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamMatchmaking", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamMatchmaking *" + }, + { + "methodname": "GetISteamMatchmakingServers", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamMatchmakingServers", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamMatchmakingServers *" + }, + { + "methodname": "GetISteamGenericInterface", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamGenericInterface", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "void *" + }, + { + "methodname": "GetISteamUserStats", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamUserStats", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamUserStats *" + }, + { + "methodname": "GetISteamGameServerStats", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamGameServerStats", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamGameServerStats *" + }, + { + "methodname": "GetISteamApps", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamApps", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamApps *" + }, + { + "methodname": "GetISteamNetworking", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamNetworking", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamNetworking *" + }, + { + "methodname": "GetISteamRemoteStorage", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamRemoteStorage", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamRemoteStorage *" + }, + { + "methodname": "GetISteamScreenshots", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamScreenshots", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamScreenshots *" + }, + { + "methodname": "GetISteamGameSearch", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamGameSearch", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamGameSearch *" + }, + { + "methodname": "GetIPCCallCount", + "methodname_flat": "SteamAPI_ISteamClient_GetIPCCallCount", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "SetWarningMessageHook", + "methodname_flat": "SteamAPI_ISteamClient_SetWarningMessageHook", + "params": [ + { "paramname":"pFunction", "paramtype":"SteamAPIWarningMessageHook_t" } + ], + "returntype": "void" + }, + { + "methodname": "BShutdownIfAllPipesClosed", + "methodname_flat": "SteamAPI_ISteamClient_BShutdownIfAllPipesClosed", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetISteamHTTP", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamHTTP", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamHTTP *" + }, + { + "methodname": "GetISteamController", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamController", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamController *" + }, + { + "methodname": "GetISteamUGC", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamUGC", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamUGC *" + }, + { + "methodname": "GetISteamAppList", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamAppList", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamAppList *" + }, + { + "methodname": "GetISteamMusic", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamMusic", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamMusic *" + }, + { + "methodname": "GetISteamMusicRemote", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamMusicRemote", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamMusicRemote *" + }, + { + "methodname": "GetISteamHTMLSurface", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamHTMLSurface", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamHTMLSurface *" + }, + { + "methodname": "GetISteamInventory", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamInventory", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamInventory *" + }, + { + "methodname": "GetISteamVideo", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamVideo", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamVideo *" + }, + { + "methodname": "GetISteamParentalSettings", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamParentalSettings", + "params": [ + { "paramname":"hSteamuser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamParentalSettings *" + }, + { + "methodname": "GetISteamInput", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamInput", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamInput *" + }, + { + "methodname": "GetISteamParties", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamParties", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamParties *" + }, + { + "methodname": "GetISteamRemotePlay", + "methodname_flat": "SteamAPI_ISteamClient_GetISteamRemotePlay", + "params": [ + { "paramname":"hSteamUser", "paramtype":"HSteamUser" }, + { "paramname":"hSteamPipe", "paramtype":"HSteamPipe" }, + { "paramname":"pchVersion", "paramtype":"const char *" } + ], + "returntype": "ISteamRemotePlay *" + } + ] + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamUser", + "name_flat": "SteamAPI_SteamUser_v023" + } + ], + "classname": "ISteamUser", + "fields": [], + "methods": [ + { + "methodname": "GetHSteamUser", + "methodname_flat": "SteamAPI_ISteamUser_GetHSteamUser", + "params": [], + "returntype": "HSteamUser" + }, + { + "methodname": "BLoggedOn", + "methodname_flat": "SteamAPI_ISteamUser_BLoggedOn", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetSteamID", + "methodname_flat": "SteamAPI_ISteamUser_GetSteamID", + "params": [], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "InitiateGameConnection_DEPRECATED", + "methodname_flat": "SteamAPI_ISteamUser_InitiateGameConnection_DEPRECATED", + "params": [ + { "paramname":"pAuthBlob", "paramtype":"void *" }, + { "paramname":"cbMaxAuthBlob", "paramtype":"int" }, + { "paramname":"steamIDGameServer", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"unIPServer", "paramtype":"uint32" }, + { "paramname":"usPortServer", "paramtype":"uint16" }, + { "paramname":"bSecure", "paramtype":"bool" } + ], + "returntype": "int" + }, + { + "methodname": "TerminateGameConnection_DEPRECATED", + "methodname_flat": "SteamAPI_ISteamUser_TerminateGameConnection_DEPRECATED", + "params": [ + { "paramname":"unIPServer", "paramtype":"uint32" }, + { "paramname":"usPortServer", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "TrackAppUsageEvent", + "methodname_flat": "SteamAPI_ISteamUser_TrackAppUsageEvent", + "params": [ + { "paramname":"gameID", "paramtype":"CGameID", "paramtype_flat":"uint64_gameid" }, + { "paramname":"eAppUsageEvent", "paramtype":"int" }, + { "paramname":"pchExtraInfo", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "GetUserDataFolder", + "methodname_flat": "SteamAPI_ISteamUser_GetUserDataFolder", + "params": [ + { "paramname":"pchBuffer", "paramtype":"char *" }, + { "paramname":"cubBuffer", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "StartVoiceRecording", + "methodname_flat": "SteamAPI_ISteamUser_StartVoiceRecording", + "params": [], + "returntype": "void" + }, + { + "methodname": "StopVoiceRecording", + "methodname_flat": "SteamAPI_ISteamUser_StopVoiceRecording", + "params": [], + "returntype": "void" + }, + { + "methodname": "GetAvailableVoice", + "methodname_flat": "SteamAPI_ISteamUser_GetAvailableVoice", + "params": [ + { "paramname":"pcbCompressed", "paramtype":"uint32 *" }, + { "paramname":"pcbUncompressed_Deprecated", "paramtype":"uint32 *" }, + { "paramname":"nUncompressedVoiceDesiredSampleRate_Deprecated", "paramtype":"uint32" } + ], + "returntype": "EVoiceResult" + }, + { + "methodname": "GetVoice", + "methodname_flat": "SteamAPI_ISteamUser_GetVoice", + "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" } + ], + "returntype": "EVoiceResult" + }, + { + "methodname": "DecompressVoice", + "methodname_flat": "SteamAPI_ISteamUser_DecompressVoice", + "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" } + ], + "returntype": "EVoiceResult" + }, + { + "methodname": "GetVoiceOptimalSampleRate", + "methodname_flat": "SteamAPI_ISteamUser_GetVoiceOptimalSampleRate", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetAuthSessionTicket", + "methodname_flat": "SteamAPI_ISteamUser_GetAuthSessionTicket", + "params": [ + { "paramname":"pTicket", "paramtype":"void *" }, + { "paramname":"cbMaxTicket", "paramtype":"int" }, + { "paramname":"pcbTicket", "paramtype":"uint32 *" }, + { "paramname":"pSteamNetworkingIdentity", "paramtype":"const SteamNetworkingIdentity *" } + ], + "returntype": "HAuthTicket" + }, + { + "methodname": "GetAuthTicketForWebApi", + "methodname_flat": "SteamAPI_ISteamUser_GetAuthTicketForWebApi", + "params": [ + { "paramname":"pchIdentity", "paramtype":"const char *" } + ], + "returntype": "HAuthTicket" + }, + { + "methodname": "BeginAuthSession", + "methodname_flat": "SteamAPI_ISteamUser_BeginAuthSession", + "params": [ + { "paramname":"pAuthTicket", "paramtype":"const void *" }, + { "paramname":"cbAuthTicket", "paramtype":"int" }, + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "EBeginAuthSessionResult" + }, + { + "methodname": "EndAuthSession", + "methodname_flat": "SteamAPI_ISteamUser_EndAuthSession", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "CancelAuthTicket", + "methodname_flat": "SteamAPI_ISteamUser_CancelAuthTicket", + "params": [ + { "paramname":"hAuthTicket", "paramtype":"HAuthTicket" } + ], + "returntype": "void" + }, + { + "methodname": "UserHasLicenseForApp", + "methodname_flat": "SteamAPI_ISteamUser_UserHasLicenseForApp", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"appID", "paramtype":"AppId_t" } + ], + "returntype": "EUserHasLicenseForAppResult" + }, + { + "methodname": "BIsBehindNAT", + "methodname_flat": "SteamAPI_ISteamUser_BIsBehindNAT", + "params": [], + "returntype": "bool" + }, + { + "methodname": "AdvertiseGame", + "methodname_flat": "SteamAPI_ISteamUser_AdvertiseGame", + "params": [ + { "paramname":"steamIDGameServer", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"unIPServer", "paramtype":"uint32" }, + { "paramname":"usPortServer", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "callresult": "EncryptedAppTicketResponse_t", + "methodname": "RequestEncryptedAppTicket", + "methodname_flat": "SteamAPI_ISteamUser_RequestEncryptedAppTicket", + "params": [ + { "paramname":"pDataToInclude", "paramtype":"void *" }, + { "paramname":"cbDataToInclude", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetEncryptedAppTicket", + "methodname_flat": "SteamAPI_ISteamUser_GetEncryptedAppTicket", + "params": [ + { "paramname":"pTicket", "paramtype":"void *" }, + { "paramname":"cbMaxTicket", "paramtype":"int" }, + { "paramname":"pcbTicket", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetGameBadgeLevel", + "methodname_flat": "SteamAPI_ISteamUser_GetGameBadgeLevel", + "params": [ + { "paramname":"nSeries", "paramtype":"int" }, + { "paramname":"bFoil", "paramtype":"bool" } + ], + "returntype": "int" + }, + { + "methodname": "GetPlayerSteamLevel", + "methodname_flat": "SteamAPI_ISteamUser_GetPlayerSteamLevel", + "params": [], + "returntype": "int" + }, + { + "callresult": "StoreAuthURLResponse_t", + "methodname": "RequestStoreAuthURL", + "methodname_flat": "SteamAPI_ISteamUser_RequestStoreAuthURL", + "params": [ + { "paramname":"pchRedirectURL", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "BIsPhoneVerified", + "methodname_flat": "SteamAPI_ISteamUser_BIsPhoneVerified", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsTwoFactorEnabled", + "methodname_flat": "SteamAPI_ISteamUser_BIsTwoFactorEnabled", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsPhoneIdentifying", + "methodname_flat": "SteamAPI_ISteamUser_BIsPhoneIdentifying", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsPhoneRequiringVerification", + "methodname_flat": "SteamAPI_ISteamUser_BIsPhoneRequiringVerification", + "params": [], + "returntype": "bool" + }, + { + "callresult": "MarketEligibilityResponse_t", + "methodname": "GetMarketEligibility", + "methodname_flat": "SteamAPI_ISteamUser_GetMarketEligibility", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "DurationControl_t", + "methodname": "GetDurationControl", + "methodname_flat": "SteamAPI_ISteamUser_GetDurationControl", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "BSetDurationControlOnlineState", + "methodname_flat": "SteamAPI_ISteamUser_BSetDurationControlOnlineState", + "params": [ + { "paramname":"eNewState", "paramtype":"EDurationControlOnlineState" } + ], + "returntype": "bool" + } + ], + "version_string": "SteamUser023" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamFriends", + "name_flat": "SteamAPI_SteamFriends_v017" + } + ], + "classname": "ISteamFriends", + "fields": [], + "methods": [ + { + "methodname": "GetPersonaName", + "methodname_flat": "SteamAPI_ISteamFriends_GetPersonaName", + "params": [], + "returntype": "const char *" + }, + { + "callresult": "SetPersonaNameResponse_t", + "methodname": "SetPersonaName", + "methodname_flat": "SteamAPI_ISteamFriends_SetPersonaName", + "params": [ + { "paramname":"pchPersonaName", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetPersonaState", + "methodname_flat": "SteamAPI_ISteamFriends_GetPersonaState", + "params": [], + "returntype": "EPersonaState" + }, + { + "methodname": "GetFriendCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendCount", + "params": [ + { "paramname":"iFriendFlags", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "GetFriendByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendByIndex", + "params": [ + { "paramname":"iFriend", "paramtype":"int" }, + { "paramname":"iFriendFlags", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetFriendRelationship", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendRelationship", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "EFriendRelationship" + }, + { + "methodname": "GetFriendPersonaState", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendPersonaState", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "EPersonaState" + }, + { + "methodname": "GetFriendPersonaName", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendPersonaName", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetFriendGamePlayed", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendGamePlayed", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { + "out_struct": "", + "paramname": "pFriendGameInfo", + "paramtype": "FriendGameInfo_t *" + } + ], + "returntype": "bool" + }, + { + "methodname": "GetFriendPersonaNameHistory", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendPersonaNameHistory", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iPersonaName", "paramtype":"int" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetFriendSteamLevel", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendSteamLevel", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetPlayerNickname", + "methodname_flat": "SteamAPI_ISteamFriends_GetPlayerNickname", + "params": [ + { "paramname":"steamIDPlayer", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetFriendsGroupCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendsGroupCount", + "params": [], + "returntype": "int" + }, + { + "methodname": "GetFriendsGroupIDByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex", + "params": [ + { "paramname":"iFG", "paramtype":"int" } + ], + "returntype": "FriendsGroupID_t" + }, + { + "methodname": "GetFriendsGroupName", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendsGroupName", + "params": [ + { "paramname":"friendsGroupID", "paramtype":"FriendsGroupID_t" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetFriendsGroupMembersCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendsGroupMembersCount", + "params": [ + { "paramname":"friendsGroupID", "paramtype":"FriendsGroupID_t" } + ], + "returntype": "int" + }, + { + "methodname": "GetFriendsGroupMembersList", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendsGroupMembersList", + "params": [ + { "paramname":"friendsGroupID", "paramtype":"FriendsGroupID_t" }, + { + "out_array_call": "nMembersCount,GetFriendsGroupMembersCount,friendsGroupID", + "paramname": "pOutSteamIDMembers", + "paramtype": "CSteamID *" + }, + { "paramname":"nMembersCount", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "HasFriend", + "methodname_flat": "SteamAPI_ISteamFriends_HasFriend", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iFriendFlags", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetClanCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanCount", + "params": [], + "returntype": "int" + }, + { + "methodname": "GetClanByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanByIndex", + "params": [ + { "paramname":"iClan", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetClanName", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanName", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetClanTag", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanTag", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetClanActivityCounts", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanActivityCounts", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pnOnline", "paramtype":"int *" }, + { "paramname":"pnInGame", "paramtype":"int *" }, + { "paramname":"pnChatting", "paramtype":"int *" } + ], + "returntype": "bool" + }, + { + "callresult": "DownloadClanActivityCountsResult_t", + "methodname": "DownloadClanActivityCounts", + "methodname_flat": "SteamAPI_ISteamFriends_DownloadClanActivityCounts", + "params": [ + { + "array_count": "cClansToRequest", + "paramname": "psteamIDClans", + "paramtype": "CSteamID *" + }, + { "paramname":"cClansToRequest", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetFriendCountFromSource", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendCountFromSource", + "params": [ + { "paramname":"steamIDSource", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetFriendFromSourceByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendFromSourceByIndex", + "params": [ + { "paramname":"steamIDSource", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iFriend", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "IsUserInSource", + "methodname_flat": "SteamAPI_ISteamFriends_IsUserInSource", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDSource", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "SetInGameVoiceSpeaking", + "methodname_flat": "SteamAPI_ISteamFriends_SetInGameVoiceSpeaking", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"bSpeaking", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "ActivateGameOverlay", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlay", + "params": [ + { "paramname":"pchDialog", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "ActivateGameOverlayToUser", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlayToUser", + "params": [ + { "paramname":"pchDialog", "paramtype":"const char *" }, + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "ActivateGameOverlayToWebPage", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage", + "params": [ + { "paramname":"pchURL", "paramtype":"const char *" }, + { "paramname":"eMode", "paramtype":"EActivateGameOverlayToWebPageMode" } + ], + "returntype": "void" + }, + { + "methodname": "ActivateGameOverlayToStore", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlayToStore", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" }, + { "paramname":"eFlag", "paramtype":"EOverlayToStoreFlag" } + ], + "returntype": "void" + }, + { + "methodname": "SetPlayedWith", + "methodname_flat": "SteamAPI_ISteamFriends_SetPlayedWith", + "params": [ + { "paramname":"steamIDUserPlayedWith", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "ActivateGameOverlayInviteDialog", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "GetSmallFriendAvatar", + "methodname_flat": "SteamAPI_ISteamFriends_GetSmallFriendAvatar", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetMediumFriendAvatar", + "methodname_flat": "SteamAPI_ISteamFriends_GetMediumFriendAvatar", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetLargeFriendAvatar", + "methodname_flat": "SteamAPI_ISteamFriends_GetLargeFriendAvatar", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "RequestUserInformation", + "methodname_flat": "SteamAPI_ISteamFriends_RequestUserInformation", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"bRequireNameOnly", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "callresult": "ClanOfficerListResponse_t", + "methodname": "RequestClanOfficerList", + "methodname_flat": "SteamAPI_ISteamFriends_RequestClanOfficerList", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetClanOwner", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanOwner", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetClanOfficerCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanOfficerCount", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetClanOfficerByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanOfficerByIndex", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iOfficer", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetUserRestrictions", + "methodname_flat": "SteamAPI_ISteamFriends_GetUserRestrictions", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "SetRichPresence", + "methodname_flat": "SteamAPI_ISteamFriends_SetRichPresence", + "params": [ + { "paramname":"pchKey", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "ClearRichPresence", + "methodname_flat": "SteamAPI_ISteamFriends_ClearRichPresence", + "params": [], + "returntype": "void" + }, + { + "methodname": "GetFriendRichPresence", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendRichPresence", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetFriendRichPresenceKeyCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetFriendRichPresenceKeyByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iKey", "paramtype":"int" } + ], + "returntype": "const char *" + }, + { + "methodname": "RequestFriendRichPresence", + "methodname_flat": "SteamAPI_ISteamFriends_RequestFriendRichPresence", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "InviteUserToGame", + "methodname_flat": "SteamAPI_ISteamFriends_InviteUserToGame", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchConnectString", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetCoplayFriendCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetCoplayFriendCount", + "params": [], + "returntype": "int" + }, + { + "methodname": "GetCoplayFriend", + "methodname_flat": "SteamAPI_ISteamFriends_GetCoplayFriend", + "params": [ + { "paramname":"iCoplayFriend", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetFriendCoplayTime", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendCoplayTime", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetFriendCoplayGame", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendCoplayGame", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "AppId_t" + }, + { + "callresult": "JoinClanChatRoomCompletionResult_t", + "methodname": "JoinClanChatRoom", + "methodname_flat": "SteamAPI_ISteamFriends_JoinClanChatRoom", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "LeaveClanChatRoom", + "methodname_flat": "SteamAPI_ISteamFriends_LeaveClanChatRoom", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "GetClanChatMemberCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanChatMemberCount", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetChatMemberByIndex", + "methodname_flat": "SteamAPI_ISteamFriends_GetChatMemberByIndex", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iUser", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "SendClanChatMessage", + "methodname_flat": "SteamAPI_ISteamFriends_SendClanChatMessage", + "params": [ + { "paramname":"steamIDClanChat", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchText", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetClanChatMessage", + "methodname_flat": "SteamAPI_ISteamFriends_GetClanChatMessage", + "params": [ + { "paramname":"steamIDClanChat", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iMessage", "paramtype":"int" }, + { "paramname":"prgchText", "paramtype":"void *" }, + { "paramname":"cchTextMax", "paramtype":"int" }, + { "paramname":"peChatEntryType", "paramtype":"EChatEntryType *" }, + { + "out_struct": "", + "paramname": "psteamidChatter", + "paramtype": "CSteamID *" + } + ], + "returntype": "int" + }, + { + "methodname": "IsClanChatAdmin", + "methodname_flat": "SteamAPI_ISteamFriends_IsClanChatAdmin", + "params": [ + { "paramname":"steamIDClanChat", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "IsClanChatWindowOpenInSteam", + "methodname_flat": "SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam", + "params": [ + { "paramname":"steamIDClanChat", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "OpenClanChatWindowInSteam", + "methodname_flat": "SteamAPI_ISteamFriends_OpenClanChatWindowInSteam", + "params": [ + { "paramname":"steamIDClanChat", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "CloseClanChatWindowInSteam", + "methodname_flat": "SteamAPI_ISteamFriends_CloseClanChatWindowInSteam", + "params": [ + { "paramname":"steamIDClanChat", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "SetListenForFriendsMessages", + "methodname_flat": "SteamAPI_ISteamFriends_SetListenForFriendsMessages", + "params": [ + { "paramname":"bInterceptEnabled", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "ReplyToFriendMessage", + "methodname_flat": "SteamAPI_ISteamFriends_ReplyToFriendMessage", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchMsgToSend", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetFriendMessage", + "methodname_flat": "SteamAPI_ISteamFriends_GetFriendMessage", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iMessageID", "paramtype":"int" }, + { "paramname":"pvData", "paramtype":"void *" }, + { "paramname":"cubData", "paramtype":"int" }, + { "paramname":"peChatEntryType", "paramtype":"EChatEntryType *" } + ], + "returntype": "int" + }, + { + "callresult": "FriendsGetFollowerCount_t", + "methodname": "GetFollowerCount", + "methodname_flat": "SteamAPI_ISteamFriends_GetFollowerCount", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "FriendsIsFollowing_t", + "methodname": "IsFollowing", + "methodname_flat": "SteamAPI_ISteamFriends_IsFollowing", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "FriendsEnumerateFollowingList_t", + "methodname": "EnumerateFollowingList", + "methodname_flat": "SteamAPI_ISteamFriends_EnumerateFollowingList", + "params": [ + { "paramname":"unStartIndex", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "IsClanPublic", + "methodname_flat": "SteamAPI_ISteamFriends_IsClanPublic", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "IsClanOfficialGameGroup", + "methodname_flat": "SteamAPI_ISteamFriends_IsClanOfficialGameGroup", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "GetNumChatsWithUnreadPriorityMessages", + "methodname_flat": "SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages", + "params": [], + "returntype": "int" + }, + { + "methodname": "ActivateGameOverlayRemotePlayTogetherInviteDialog", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlayRemotePlayTogetherInviteDialog", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "RegisterProtocolInOverlayBrowser", + "methodname_flat": "SteamAPI_ISteamFriends_RegisterProtocolInOverlayBrowser", + "params": [ + { "paramname":"pchProtocol", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "ActivateGameOverlayInviteDialogConnectString", + "methodname_flat": "SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialogConnectString", + "params": [ + { "paramname":"pchConnectString", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "callresult": "EquippedProfileItems_t", + "methodname": "RequestEquippedProfileItems", + "methodname_flat": "SteamAPI_ISteamFriends_RequestEquippedProfileItems", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "BHasEquippedProfileItem", + "methodname_flat": "SteamAPI_ISteamFriends_BHasEquippedProfileItem", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"itemType", "paramtype":"ECommunityProfileItemType" } + ], + "returntype": "bool" + }, + { + "methodname": "GetProfileItemPropertyString", + "methodname_flat": "SteamAPI_ISteamFriends_GetProfileItemPropertyString", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"itemType", "paramtype":"ECommunityProfileItemType" }, + { "paramname":"prop", "paramtype":"ECommunityProfileItemProperty" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetProfileItemPropertyUint", + "methodname_flat": "SteamAPI_ISteamFriends_GetProfileItemPropertyUint", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"itemType", "paramtype":"ECommunityProfileItemType" }, + { "paramname":"prop", "paramtype":"ECommunityProfileItemProperty" } + ], + "returntype": "uint32" + } + ], + "version_string": "SteamFriends017" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamUtils", + "name_flat": "SteamAPI_SteamUtils_v010" + }, + { + "kind": "gameserver", + "name": "SteamGameServerUtils", + "name_flat": "SteamAPI_SteamGameServerUtils_v010" + } + ], + "classname": "ISteamUtils", + "fields": [], + "methods": [ + { + "methodname": "GetSecondsSinceAppActive", + "methodname_flat": "SteamAPI_ISteamUtils_GetSecondsSinceAppActive", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetSecondsSinceComputerActive", + "methodname_flat": "SteamAPI_ISteamUtils_GetSecondsSinceComputerActive", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetConnectedUniverse", + "methodname_flat": "SteamAPI_ISteamUtils_GetConnectedUniverse", + "params": [], + "returntype": "EUniverse" + }, + { + "methodname": "GetServerRealTime", + "methodname_flat": "SteamAPI_ISteamUtils_GetServerRealTime", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetIPCountry", + "methodname_flat": "SteamAPI_ISteamUtils_GetIPCountry", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "GetImageSize", + "methodname_flat": "SteamAPI_ISteamUtils_GetImageSize", + "params": [ + { "paramname":"iImage", "paramtype":"int" }, + { "paramname":"pnWidth", "paramtype":"uint32 *" }, + { "paramname":"pnHeight", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetImageRGBA", + "methodname_flat": "SteamAPI_ISteamUtils_GetImageRGBA", + "params": [ + { "paramname":"iImage", "paramtype":"int" }, + { "paramname":"pubDest", "paramtype":"uint8 *" }, + { "paramname":"nDestBufferSize", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetCurrentBatteryPower", + "methodname_flat": "SteamAPI_ISteamUtils_GetCurrentBatteryPower", + "params": [], + "returntype": "uint8" + }, + { + "methodname": "GetAppID", + "methodname_flat": "SteamAPI_ISteamUtils_GetAppID", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "SetOverlayNotificationPosition", + "methodname_flat": "SteamAPI_ISteamUtils_SetOverlayNotificationPosition", + "params": [ + { "paramname":"eNotificationPosition", "paramtype":"ENotificationPosition" } + ], + "returntype": "void" + }, + { + "methodname": "IsAPICallCompleted", + "methodname_flat": "SteamAPI_ISteamUtils_IsAPICallCompleted", + "params": [ + { "paramname":"hSteamAPICall", "paramtype":"SteamAPICall_t" }, + { "paramname":"pbFailed", "paramtype":"bool *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAPICallFailureReason", + "methodname_flat": "SteamAPI_ISteamUtils_GetAPICallFailureReason", + "params": [ + { "paramname":"hSteamAPICall", "paramtype":"SteamAPICall_t" } + ], + "returntype": "ESteamAPICallFailure" + }, + { + "methodname": "GetAPICallResult", + "methodname_flat": "SteamAPI_ISteamUtils_GetAPICallResult", + "params": [ + { "paramname":"hSteamAPICall", "paramtype":"SteamAPICall_t" }, + { "paramname":"pCallback", "paramtype":"void *" }, + { "paramname":"cubCallback", "paramtype":"int" }, + { "paramname":"iCallbackExpected", "paramtype":"int" }, + { "paramname":"pbFailed", "paramtype":"bool *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetIPCCallCount", + "methodname_flat": "SteamAPI_ISteamUtils_GetIPCCallCount", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "SetWarningMessageHook", + "methodname_flat": "SteamAPI_ISteamUtils_SetWarningMessageHook", + "params": [ + { "paramname":"pFunction", "paramtype":"SteamAPIWarningMessageHook_t" } + ], + "returntype": "void" + }, + { + "methodname": "IsOverlayEnabled", + "methodname_flat": "SteamAPI_ISteamUtils_IsOverlayEnabled", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BOverlayNeedsPresent", + "methodname_flat": "SteamAPI_ISteamUtils_BOverlayNeedsPresent", + "params": [], + "returntype": "bool" + }, + { + "callresult": "CheckFileSignature_t", + "methodname": "CheckFileSignature", + "methodname_flat": "SteamAPI_ISteamUtils_CheckFileSignature", + "params": [ + { "paramname":"szFileName", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "ShowGamepadTextInput", + "methodname_flat": "SteamAPI_ISteamUtils_ShowGamepadTextInput", + "params": [ + { "paramname":"eInputMode", "paramtype":"EGamepadTextInputMode" }, + { "paramname":"eLineInputMode", "paramtype":"EGamepadTextInputLineMode" }, + { "paramname":"pchDescription", "paramtype":"const char *" }, + { "paramname":"unCharMax", "paramtype":"uint32" }, + { "paramname":"pchExistingText", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetEnteredGamepadTextLength", + "methodname_flat": "SteamAPI_ISteamUtils_GetEnteredGamepadTextLength", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetEnteredGamepadTextInput", + "methodname_flat": "SteamAPI_ISteamUtils_GetEnteredGamepadTextInput", + "params": [ + { "paramname":"pchText", "paramtype":"char *" }, + { "paramname":"cchText", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetSteamUILanguage", + "methodname_flat": "SteamAPI_ISteamUtils_GetSteamUILanguage", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "IsSteamRunningInVR", + "methodname_flat": "SteamAPI_ISteamUtils_IsSteamRunningInVR", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetOverlayNotificationInset", + "methodname_flat": "SteamAPI_ISteamUtils_SetOverlayNotificationInset", + "params": [ + { "paramname":"nHorizontalInset", "paramtype":"int" }, + { "paramname":"nVerticalInset", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "IsSteamInBigPictureMode", + "methodname_flat": "SteamAPI_ISteamUtils_IsSteamInBigPictureMode", + "params": [], + "returntype": "bool" + }, + { + "methodname": "StartVRDashboard", + "methodname_flat": "SteamAPI_ISteamUtils_StartVRDashboard", + "params": [], + "returntype": "void" + }, + { + "methodname": "IsVRHeadsetStreamingEnabled", + "methodname_flat": "SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetVRHeadsetStreamingEnabled", + "methodname_flat": "SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled", + "params": [ + { "paramname":"bEnabled", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "IsSteamChinaLauncher", + "methodname_flat": "SteamAPI_ISteamUtils_IsSteamChinaLauncher", + "params": [], + "returntype": "bool" + }, + { + "methodname": "InitFilterText", + "methodname_flat": "SteamAPI_ISteamUtils_InitFilterText", + "params": [ + { "paramname":"unFilterOptions", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "FilterText", + "methodname_flat": "SteamAPI_ISteamUtils_FilterText", + "params": [ + { "paramname":"eContext", "paramtype":"ETextFilteringContext" }, + { "paramname":"sourceSteamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchInputMessage", "paramtype":"const char *" }, + { "paramname":"pchOutFilteredText", "paramtype":"char *" }, + { "paramname":"nByteSizeOutFilteredText", "paramtype":"uint32" } + ], + "returntype": "int" + }, + { + "methodname": "GetIPv6ConnectivityState", + "methodname_flat": "SteamAPI_ISteamUtils_GetIPv6ConnectivityState", + "params": [ + { "paramname":"eProtocol", "paramtype":"ESteamIPv6ConnectivityProtocol" } + ], + "returntype": "ESteamIPv6ConnectivityState" + }, + { + "methodname": "IsSteamRunningOnSteamDeck", + "methodname_flat": "SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck", + "params": [], + "returntype": "bool" + }, + { + "methodname": "ShowFloatingGamepadTextInput", + "methodname_flat": "SteamAPI_ISteamUtils_ShowFloatingGamepadTextInput", + "params": [ + { "paramname":"eKeyboardMode", "paramtype":"EFloatingGamepadTextInputMode" }, + { "paramname":"nTextFieldXPosition", "paramtype":"int" }, + { "paramname":"nTextFieldYPosition", "paramtype":"int" }, + { "paramname":"nTextFieldWidth", "paramtype":"int" }, + { "paramname":"nTextFieldHeight", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGameLauncherMode", + "methodname_flat": "SteamAPI_ISteamUtils_SetGameLauncherMode", + "params": [ + { "paramname":"bLauncherMode", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "DismissFloatingGamepadTextInput", + "methodname_flat": "SteamAPI_ISteamUtils_DismissFloatingGamepadTextInput", + "params": [], + "returntype": "bool" + } + ], + "version_string": "SteamUtils010" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamMatchmaking", + "name_flat": "SteamAPI_SteamMatchmaking_v009" + } + ], + "classname": "ISteamMatchmaking", + "fields": [], + "methods": [ + { + "methodname": "GetFavoriteGameCount", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetFavoriteGameCount", + "params": [], + "returntype": "int" + }, + { + "methodname": "GetFavoriteGame", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetFavoriteGame", + "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 *" } + ], + "returntype": "bool" + }, + { + "methodname": "AddFavoriteGame", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddFavoriteGame", + "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" } + ], + "returntype": "int" + }, + { + "methodname": "RemoveFavoriteGame", + "methodname_flat": "SteamAPI_ISteamMatchmaking_RemoveFavoriteGame", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" }, + { "paramname":"nIP", "paramtype":"uint32" }, + { "paramname":"nConnPort", "paramtype":"uint16" }, + { "paramname":"nQueryPort", "paramtype":"uint16" }, + { "paramname":"unFlags", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "callresult": "LobbyMatchList_t", + "methodname": "RequestLobbyList", + "methodname_flat": "SteamAPI_ISteamMatchmaking_RequestLobbyList", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "AddRequestLobbyListStringFilter", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter", + "params": [ + { "paramname":"pchKeyToMatch", "paramtype":"const char *" }, + { "paramname":"pchValueToMatch", "paramtype":"const char *" }, + { "paramname":"eComparisonType", "paramtype":"ELobbyComparison" } + ], + "returntype": "void" + }, + { + "methodname": "AddRequestLobbyListNumericalFilter", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter", + "params": [ + { "paramname":"pchKeyToMatch", "paramtype":"const char *" }, + { "paramname":"nValueToMatch", "paramtype":"int" }, + { "paramname":"eComparisonType", "paramtype":"ELobbyComparison" } + ], + "returntype": "void" + }, + { + "methodname": "AddRequestLobbyListNearValueFilter", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter", + "params": [ + { "paramname":"pchKeyToMatch", "paramtype":"const char *" }, + { "paramname":"nValueToBeCloseTo", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "AddRequestLobbyListFilterSlotsAvailable", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable", + "params": [ + { "paramname":"nSlotsAvailable", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "AddRequestLobbyListDistanceFilter", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter", + "params": [ + { "paramname":"eLobbyDistanceFilter", "paramtype":"ELobbyDistanceFilter" } + ], + "returntype": "void" + }, + { + "methodname": "AddRequestLobbyListResultCountFilter", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter", + "params": [ + { "paramname":"cMaxResults", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "AddRequestLobbyListCompatibleMembersFilter", + "methodname_flat": "SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "GetLobbyByIndex", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyByIndex", + "params": [ + { "paramname":"iLobby", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "callresult": "LobbyCreated_t", + "methodname": "CreateLobby", + "methodname_flat": "SteamAPI_ISteamMatchmaking_CreateLobby", + "params": [ + { "paramname":"eLobbyType", "paramtype":"ELobbyType" }, + { "paramname":"cMaxMembers", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "LobbyEnter_t", + "methodname": "JoinLobby", + "methodname_flat": "SteamAPI_ISteamMatchmaking_JoinLobby", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "LeaveLobby", + "methodname_flat": "SteamAPI_ISteamMatchmaking_LeaveLobby", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "InviteUserToLobby", + "methodname_flat": "SteamAPI_ISteamMatchmaking_InviteUserToLobby", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDInvitee", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "GetNumLobbyMembers", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetNumLobbyMembers", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetLobbyMemberByIndex", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iMember", "paramtype":"int" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetLobbyData", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyData", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "const char *" + }, + { + "methodname": "SetLobbyData", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyData", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchKey", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetLobbyDataCount", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyDataCount", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "GetLobbyDataByIndex", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iLobbyData", "paramtype":"int" }, + { "paramname":"pchKey", "paramtype":"char *" }, + { "paramname":"cchKeyBufferSize", "paramtype":"int" }, + { "paramname":"pchValue", "paramtype":"char *" }, + { "paramname":"cchValueBufferSize", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "DeleteLobbyData", + "methodname_flat": "SteamAPI_ISteamMatchmaking_DeleteLobbyData", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetLobbyMemberData", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyMemberData", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "const char *" + }, + { + "methodname": "SetLobbyMemberData", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyMemberData", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchKey", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SendLobbyChatMsg", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SendLobbyChatMsg", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pvMsgBody", "paramtype":"const void *" }, + { "paramname":"cubMsgBody", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetLobbyChatEntry", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyChatEntry", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"iChatID", "paramtype":"int" }, + { + "out_struct": "", + "paramname": "pSteamIDUser", + "paramtype": "CSteamID *" + }, + { "paramname":"pvData", "paramtype":"void *" }, + { "paramname":"cubData", "paramtype":"int" }, + { "paramname":"peChatEntryType", "paramtype":"EChatEntryType *" } + ], + "returntype": "int" + }, + { + "methodname": "RequestLobbyData", + "methodname_flat": "SteamAPI_ISteamMatchmaking_RequestLobbyData", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "SetLobbyGameServer", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyGameServer", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"unGameServerIP", "paramtype":"uint32" }, + { "paramname":"unGameServerPort", "paramtype":"uint16" }, + { "paramname":"steamIDGameServer", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "GetLobbyGameServer", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyGameServer", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"punGameServerIP", "paramtype":"uint32 *" }, + { "paramname":"punGameServerPort", "paramtype":"uint16 *" }, + { + "out_struct": "", + "paramname": "psteamIDGameServer", + "paramtype": "CSteamID *" + } + ], + "returntype": "bool" + }, + { + "methodname": "SetLobbyMemberLimit", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"cMaxMembers", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetLobbyMemberLimit", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "int" + }, + { + "methodname": "SetLobbyType", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyType", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"eLobbyType", "paramtype":"ELobbyType" } + ], + "returntype": "bool" + }, + { + "methodname": "SetLobbyJoinable", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyJoinable", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"bLobbyJoinable", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "GetLobbyOwner", + "methodname_flat": "SteamAPI_ISteamMatchmaking_GetLobbyOwner", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "SetLobbyOwner", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLobbyOwner", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDNewOwner", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "SetLinkedLobby", + "methodname_flat": "SteamAPI_ISteamMatchmaking_SetLinkedLobby", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDLobbyDependent", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + } + ], + "version_string": "SteamMatchMaking009" + }, + { + "classname": "ISteamMatchmakingServerListResponse", + "fields": [], + "methods": [ + { + "methodname": "ServerResponded", + "methodname_flat": "SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" }, + { "paramname":"iServer", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "ServerFailedToRespond", + "methodname_flat": "SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" }, + { "paramname":"iServer", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "RefreshComplete", + "methodname_flat": "SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" }, + { "paramname":"response", "paramtype":"EMatchMakingServerResponse" } + ], + "returntype": "void" + } + ] + }, + { + "classname": "ISteamMatchmakingPingResponse", + "fields": [], + "methods": [ + { + "methodname": "ServerResponded", + "methodname_flat": "SteamAPI_ISteamMatchmakingPingResponse_ServerResponded", + "params": [ + { "paramname":"server", "paramtype":"gameserveritem_t &" } + ], + "returntype": "void" + }, + { + "methodname": "ServerFailedToRespond", + "methodname_flat": "SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond", + "params": [], + "returntype": "void" + } + ] + }, + { + "classname": "ISteamMatchmakingPlayersResponse", + "fields": [], + "methods": [ + { + "methodname": "AddPlayerToList", + "methodname_flat": "SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"nScore", "paramtype":"int" }, + { "paramname":"flTimePlayed", "paramtype":"float" } + ], + "returntype": "void" + }, + { + "methodname": "PlayersFailedToRespond", + "methodname_flat": "SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond", + "params": [], + "returntype": "void" + }, + { + "methodname": "PlayersRefreshComplete", + "methodname_flat": "SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete", + "params": [], + "returntype": "void" + } + ] + }, + { + "classname": "ISteamMatchmakingRulesResponse", + "fields": [], + "methods": [ + { + "methodname": "RulesResponded", + "methodname_flat": "SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded", + "params": [ + { "paramname":"pchRule", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "RulesFailedToRespond", + "methodname_flat": "SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond", + "params": [], + "returntype": "void" + }, + { + "methodname": "RulesRefreshComplete", + "methodname_flat": "SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete", + "params": [], + "returntype": "void" + } + ] + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamMatchmakingServers", + "name_flat": "SteamAPI_SteamMatchmakingServers_v002" + } + ], + "classname": "ISteamMatchmakingServers", + "fields": [], + "methods": [ + { + "methodname": "RequestInternetServerList", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RequestInternetServerList", + "params": [ + { "paramname":"iApp", "paramtype":"AppId_t" }, + { + "array_count": "nFilters", + "paramname": "ppchFilters", + "paramtype": "MatchMakingKeyValuePair_t **" + }, + { "paramname":"nFilters", "paramtype":"uint32" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingServerListResponse *" } + ], + "returntype": "HServerListRequest" + }, + { + "methodname": "RequestLANServerList", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RequestLANServerList", + "params": [ + { "paramname":"iApp", "paramtype":"AppId_t" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingServerListResponse *" } + ], + "returntype": "HServerListRequest" + }, + { + "methodname": "RequestFriendsServerList", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList", + "params": [ + { "paramname":"iApp", "paramtype":"AppId_t" }, + { + "array_count": "nFilters", + "paramname": "ppchFilters", + "paramtype": "MatchMakingKeyValuePair_t **" + }, + { "paramname":"nFilters", "paramtype":"uint32" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingServerListResponse *" } + ], + "returntype": "HServerListRequest" + }, + { + "methodname": "RequestFavoritesServerList", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList", + "params": [ + { "paramname":"iApp", "paramtype":"AppId_t" }, + { + "array_count": "nFilters", + "paramname": "ppchFilters", + "paramtype": "MatchMakingKeyValuePair_t **" + }, + { "paramname":"nFilters", "paramtype":"uint32" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingServerListResponse *" } + ], + "returntype": "HServerListRequest" + }, + { + "methodname": "RequestHistoryServerList", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList", + "params": [ + { "paramname":"iApp", "paramtype":"AppId_t" }, + { + "array_count": "nFilters", + "paramname": "ppchFilters", + "paramtype": "MatchMakingKeyValuePair_t **" + }, + { "paramname":"nFilters", "paramtype":"uint32" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingServerListResponse *" } + ], + "returntype": "HServerListRequest" + }, + { + "methodname": "RequestSpectatorServerList", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList", + "params": [ + { "paramname":"iApp", "paramtype":"AppId_t" }, + { + "array_count": "nFilters", + "paramname": "ppchFilters", + "paramtype": "MatchMakingKeyValuePair_t **" + }, + { "paramname":"nFilters", "paramtype":"uint32" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingServerListResponse *" } + ], + "returntype": "HServerListRequest" + }, + { + "methodname": "ReleaseRequest", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_ReleaseRequest", + "params": [ + { "paramname":"hServerListRequest", "paramtype":"HServerListRequest" } + ], + "returntype": "void" + }, + { + "methodname": "GetServerDetails", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_GetServerDetails", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" }, + { "paramname":"iServer", "paramtype":"int" } + ], + "returntype": "gameserveritem_t *" + }, + { + "methodname": "CancelQuery", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_CancelQuery", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" } + ], + "returntype": "void" + }, + { + "methodname": "RefreshQuery", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RefreshQuery", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" } + ], + "returntype": "void" + }, + { + "methodname": "IsRefreshing", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_IsRefreshing", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" } + ], + "returntype": "bool" + }, + { + "methodname": "GetServerCount", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_GetServerCount", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" } + ], + "returntype": "int" + }, + { + "methodname": "RefreshServer", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_RefreshServer", + "params": [ + { "paramname":"hRequest", "paramtype":"HServerListRequest" }, + { "paramname":"iServer", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "PingServer", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_PingServer", + "params": [ + { "paramname":"unIP", "paramtype":"uint32" }, + { "paramname":"usPort", "paramtype":"uint16" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingPingResponse *" } + ], + "returntype": "HServerQuery" + }, + { + "methodname": "PlayerDetails", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_PlayerDetails", + "params": [ + { "paramname":"unIP", "paramtype":"uint32" }, + { "paramname":"usPort", "paramtype":"uint16" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingPlayersResponse *" } + ], + "returntype": "HServerQuery" + }, + { + "methodname": "ServerRules", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_ServerRules", + "params": [ + { "paramname":"unIP", "paramtype":"uint32" }, + { "paramname":"usPort", "paramtype":"uint16" }, + { "paramname":"pRequestServersResponse", "paramtype":"ISteamMatchmakingRulesResponse *" } + ], + "returntype": "HServerQuery" + }, + { + "methodname": "CancelServerQuery", + "methodname_flat": "SteamAPI_ISteamMatchmakingServers_CancelServerQuery", + "params": [ + { "paramname":"hServerQuery", "paramtype":"HServerQuery" } + ], + "returntype": "void" + } + ], + "version_string": "SteamMatchMakingServers002" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamGameSearch", + "name_flat": "SteamAPI_SteamGameSearch_v001" + } + ], + "classname": "ISteamGameSearch", + "fields": [], + "methods": [ + { + "methodname": "AddGameSearchParams", + "methodname_flat": "SteamAPI_ISteamGameSearch_AddGameSearchParams", + "params": [ + { "paramname":"pchKeyToFind", "paramtype":"const char *" }, + { "paramname":"pchValuesToFind", "paramtype":"const char *" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "SearchForGameWithLobby", + "methodname_flat": "SteamAPI_ISteamGameSearch_SearchForGameWithLobby", + "params": [ + { "paramname":"steamIDLobby", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"nPlayerMin", "paramtype":"int" }, + { "paramname":"nPlayerMax", "paramtype":"int" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "SearchForGameSolo", + "methodname_flat": "SteamAPI_ISteamGameSearch_SearchForGameSolo", + "params": [ + { "paramname":"nPlayerMin", "paramtype":"int" }, + { "paramname":"nPlayerMax", "paramtype":"int" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "AcceptGame", + "methodname_flat": "SteamAPI_ISteamGameSearch_AcceptGame", + "params": [], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "DeclineGame", + "methodname_flat": "SteamAPI_ISteamGameSearch_DeclineGame", + "params": [], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "RetrieveConnectionDetails", + "methodname_flat": "SteamAPI_ISteamGameSearch_RetrieveConnectionDetails", + "params": [ + { "paramname":"steamIDHost", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchConnectionDetails", "paramtype":"char *" }, + { "paramname":"cubConnectionDetails", "paramtype":"int" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "EndGameSearch", + "methodname_flat": "SteamAPI_ISteamGameSearch_EndGameSearch", + "params": [], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "SetGameHostParams", + "methodname_flat": "SteamAPI_ISteamGameSearch_SetGameHostParams", + "params": [ + { "paramname":"pchKey", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "SetConnectionDetails", + "methodname_flat": "SteamAPI_ISteamGameSearch_SetConnectionDetails", + "params": [ + { "paramname":"pchConnectionDetails", "paramtype":"const char *" }, + { "paramname":"cubConnectionDetails", "paramtype":"int" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "RequestPlayersForGame", + "methodname_flat": "SteamAPI_ISteamGameSearch_RequestPlayersForGame", + "params": [ + { "paramname":"nPlayerMin", "paramtype":"int" }, + { "paramname":"nPlayerMax", "paramtype":"int" }, + { "paramname":"nMaxTeamSize", "paramtype":"int" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "HostConfirmGameStart", + "methodname_flat": "SteamAPI_ISteamGameSearch_HostConfirmGameStart", + "params": [ + { "paramname":"ullUniqueGameID", "paramtype":"uint64" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "CancelRequestPlayersForGame", + "methodname_flat": "SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame", + "params": [], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "SubmitPlayerResult", + "methodname_flat": "SteamAPI_ISteamGameSearch_SubmitPlayerResult", + "params": [ + { "paramname":"ullUniqueGameID", "paramtype":"uint64" }, + { "paramname":"steamIDPlayer", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"EPlayerResult", "paramtype":"EPlayerResult_t" } + ], + "returntype": "EGameSearchErrorCode_t" + }, + { + "methodname": "EndGame", + "methodname_flat": "SteamAPI_ISteamGameSearch_EndGame", + "params": [ + { "paramname":"ullUniqueGameID", "paramtype":"uint64" } + ], + "returntype": "EGameSearchErrorCode_t" + } + ], + "version_string": "SteamMatchGameSearch001" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamParties", + "name_flat": "SteamAPI_SteamParties_v002" + } + ], + "classname": "ISteamParties", + "fields": [], + "methods": [ + { + "methodname": "GetNumActiveBeacons", + "methodname_flat": "SteamAPI_ISteamParties_GetNumActiveBeacons", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetBeaconByIndex", + "methodname_flat": "SteamAPI_ISteamParties_GetBeaconByIndex", + "params": [ + { "paramname":"unIndex", "paramtype":"uint32" } + ], + "returntype": "PartyBeaconID_t" + }, + { + "methodname": "GetBeaconDetails", + "methodname_flat": "SteamAPI_ISteamParties_GetBeaconDetails", + "params": [ + { "paramname":"ulBeaconID", "paramtype":"PartyBeaconID_t" }, + { "paramname":"pSteamIDBeaconOwner", "paramtype":"CSteamID *" }, + { + "out_struct": "", + "paramname": "pLocation", + "paramtype": "SteamPartyBeaconLocation_t *" + }, + { + "out_string_count": "cchMetadata", + "paramname": "pchMetadata", + "paramtype": "char *" + }, + { "paramname":"cchMetadata", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "callresult": "JoinPartyCallback_t", + "methodname": "JoinParty", + "methodname_flat": "SteamAPI_ISteamParties_JoinParty", + "params": [ + { "paramname":"ulBeaconID", "paramtype":"PartyBeaconID_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetNumAvailableBeaconLocations", + "methodname_flat": "SteamAPI_ISteamParties_GetNumAvailableBeaconLocations", + "params": [ + { "paramname":"puNumLocations", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAvailableBeaconLocations", + "methodname_flat": "SteamAPI_ISteamParties_GetAvailableBeaconLocations", + "params": [ + { "paramname":"pLocationList", "paramtype":"SteamPartyBeaconLocation_t *" }, + { "paramname":"uMaxNumLocations", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "callresult": "CreateBeaconCallback_t", + "methodname": "CreateBeacon", + "methodname_flat": "SteamAPI_ISteamParties_CreateBeacon", + "params": [ + { "paramname":"unOpenSlots", "paramtype":"uint32" }, + { "paramname":"pBeaconLocation", "paramtype":"SteamPartyBeaconLocation_t *" }, + { "paramname":"pchConnectString", "paramtype":"const char *" }, + { "paramname":"pchMetadata", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "OnReservationCompleted", + "methodname_flat": "SteamAPI_ISteamParties_OnReservationCompleted", + "params": [ + { "paramname":"ulBeacon", "paramtype":"PartyBeaconID_t" }, + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "CancelReservation", + "methodname_flat": "SteamAPI_ISteamParties_CancelReservation", + "params": [ + { "paramname":"ulBeacon", "paramtype":"PartyBeaconID_t" }, + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "callresult": "ChangeNumOpenSlotsCallback_t", + "methodname": "ChangeNumOpenSlots", + "methodname_flat": "SteamAPI_ISteamParties_ChangeNumOpenSlots", + "params": [ + { "paramname":"ulBeacon", "paramtype":"PartyBeaconID_t" }, + { "paramname":"unOpenSlots", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "DestroyBeacon", + "methodname_flat": "SteamAPI_ISteamParties_DestroyBeacon", + "params": [ + { "paramname":"ulBeacon", "paramtype":"PartyBeaconID_t" } + ], + "returntype": "bool" + }, + { + "methodname": "GetBeaconLocationData", + "methodname_flat": "SteamAPI_ISteamParties_GetBeaconLocationData", + "params": [ + { "paramname":"BeaconLocation", "paramtype":"SteamPartyBeaconLocation_t" }, + { "paramname":"eData", "paramtype":"ESteamPartyBeaconLocationData" }, + { + "out_string_count": "cchDataStringOut", + "paramname": "pchDataStringOut", + "paramtype": "char *" + }, + { "paramname":"cchDataStringOut", "paramtype":"int" } + ], + "returntype": "bool" + } + ], + "version_string": "SteamParties002" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamRemoteStorage", + "name_flat": "SteamAPI_SteamRemoteStorage_v016" + } + ], + "classname": "ISteamRemoteStorage", + "fields": [], + "methods": [ + { + "methodname": "FileWrite", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileWrite", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" }, + { "paramname":"pvData", "paramtype":"const void *" }, + { "paramname":"cubData", "paramtype":"int32" } + ], + "returntype": "bool" + }, + { + "methodname": "FileRead", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileRead", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" }, + { "paramname":"pvData", "paramtype":"void *" }, + { "paramname":"cubDataToRead", "paramtype":"int32" } + ], + "returntype": "int32" + }, + { + "callresult": "RemoteStorageFileWriteAsyncComplete_t", + "methodname": "FileWriteAsync", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileWriteAsync", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" }, + { "paramname":"pvData", "paramtype":"const void *" }, + { "paramname":"cubData", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageFileReadAsyncComplete_t", + "methodname": "FileReadAsync", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileReadAsync", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" }, + { "paramname":"nOffset", "paramtype":"uint32" }, + { "paramname":"cubToRead", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "FileReadAsyncComplete", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete", + "params": [ + { "paramname":"hReadCall", "paramtype":"SteamAPICall_t" }, + { "paramname":"pvBuffer", "paramtype":"void *" }, + { "paramname":"cubToRead", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "FileForget", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileForget", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "FileDelete", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileDelete", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "callresult": "RemoteStorageFileShareResult_t", + "methodname": "FileShare", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileShare", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "SetSyncPlatforms", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_SetSyncPlatforms", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" }, + { "paramname":"eRemoteStoragePlatform", "paramtype":"ERemoteStoragePlatform" } + ], + "returntype": "bool" + }, + { + "methodname": "FileWriteStreamOpen", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "UGCFileWriteStreamHandle_t" + }, + { + "methodname": "FileWriteStreamWriteChunk", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk", + "params": [ + { "paramname":"writeHandle", "paramtype":"UGCFileWriteStreamHandle_t" }, + { "paramname":"pvData", "paramtype":"const void *" }, + { "paramname":"cubData", "paramtype":"int32" } + ], + "returntype": "bool" + }, + { + "methodname": "FileWriteStreamClose", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileWriteStreamClose", + "params": [ + { "paramname":"writeHandle", "paramtype":"UGCFileWriteStreamHandle_t" } + ], + "returntype": "bool" + }, + { + "methodname": "FileWriteStreamCancel", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel", + "params": [ + { "paramname":"writeHandle", "paramtype":"UGCFileWriteStreamHandle_t" } + ], + "returntype": "bool" + }, + { + "methodname": "FileExists", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FileExists", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "FilePersisted", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_FilePersisted", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetFileSize", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetFileSize", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "int32" + }, + { + "methodname": "GetFileTimestamp", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetFileTimestamp", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "int64" + }, + { + "methodname": "GetSyncPlatforms", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetSyncPlatforms", + "params": [ + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "ERemoteStoragePlatform" + }, + { + "methodname": "GetFileCount", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetFileCount", + "params": [], + "returntype": "int32" + }, + { + "methodname": "GetFileNameAndSize", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetFileNameAndSize", + "params": [ + { "paramname":"iFile", "paramtype":"int" }, + { "paramname":"pnFileSizeInBytes", "paramtype":"int32 *" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetQuota", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetQuota", + "params": [ + { "paramname":"pnTotalBytes", "paramtype":"uint64 *" }, + { "paramname":"puAvailableBytes", "paramtype":"uint64 *" } + ], + "returntype": "bool" + }, + { + "methodname": "IsCloudEnabledForAccount", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount", + "params": [], + "returntype": "bool" + }, + { + "methodname": "IsCloudEnabledForApp", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetCloudEnabledForApp", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp", + "params": [ + { "paramname":"bEnabled", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "callresult": "RemoteStorageDownloadUGCResult_t", + "methodname": "UGCDownload", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UGCDownload", + "params": [ + { "paramname":"hContent", "paramtype":"UGCHandle_t" }, + { "paramname":"unPriority", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetUGCDownloadProgress", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress", + "params": [ + { "paramname":"hContent", "paramtype":"UGCHandle_t" }, + { "paramname":"pnBytesDownloaded", "paramtype":"int32 *" }, + { "paramname":"pnBytesExpected", "paramtype":"int32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetUGCDetails", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetUGCDetails", + "params": [ + { "paramname":"hContent", "paramtype":"UGCHandle_t" }, + { "paramname":"pnAppID", "paramtype":"AppId_t *" }, + { + "out_string": "", + "paramname": "ppchName", + "paramtype": "char **" + }, + { "paramname":"pnFileSizeInBytes", "paramtype":"int32 *" }, + { + "out_struct": "", + "paramname": "pSteamIDOwner", + "paramtype": "CSteamID *" + } + ], + "returntype": "bool" + }, + { + "methodname": "UGCRead", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UGCRead", + "params": [ + { "paramname":"hContent", "paramtype":"UGCHandle_t" }, + { "paramname":"pvData", "paramtype":"void *" }, + { "paramname":"cubDataToRead", "paramtype":"int32" }, + { "paramname":"cOffset", "paramtype":"uint32" }, + { "paramname":"eAction", "paramtype":"EUGCReadAction" } + ], + "returntype": "int32" + }, + { + "methodname": "GetCachedUGCCount", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetCachedUGCCount", + "params": [], + "returntype": "int32" + }, + { + "methodname": "GetCachedUGCHandle", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle", + "params": [ + { "paramname":"iCachedContent", "paramtype":"int32" } + ], + "returntype": "UGCHandle_t" + }, + { + "callresult": "RemoteStoragePublishFileProgress_t", + "methodname": "PublishWorkshopFile", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_PublishWorkshopFile", + "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":"SteamParamStringArray_t *" }, + { "paramname":"eWorkshopFileType", "paramtype":"EWorkshopFileType" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "CreatePublishedFileUpdateRequest", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" } + ], + "returntype": "PublishedFileUpdateHandle_t" + }, + { + "methodname": "UpdatePublishedFileFile", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"pchFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdatePublishedFilePreviewFile", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"pchPreviewFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdatePublishedFileTitle", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"pchTitle", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdatePublishedFileDescription", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"pchDescription", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdatePublishedFileVisibility", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"eVisibility", "paramtype":"ERemoteStoragePublishedFileVisibility" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdatePublishedFileTags", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"pTags", "paramtype":"SteamParamStringArray_t *" } + ], + "returntype": "bool" + }, + { + "callresult": "RemoteStorageUpdatePublishedFileResult_t", + "methodname": "CommitPublishedFileUpdate", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageGetPublishedFileDetailsResult_t", + "methodname": "GetPublishedFileDetails", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" }, + { "paramname":"unMaxSecondsOld", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageDeletePublishedFileResult_t", + "methodname": "DeletePublishedFile", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_DeletePublishedFile", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageEnumerateUserPublishedFilesResult_t", + "methodname": "EnumerateUserPublishedFiles", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles", + "params": [ + { "paramname":"unStartIndex", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageSubscribePublishedFileResult_t", + "methodname": "SubscribePublishedFile", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_SubscribePublishedFile", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageEnumerateUserSubscribedFilesResult_t", + "methodname": "EnumerateUserSubscribedFiles", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles", + "params": [ + { "paramname":"unStartIndex", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageUnsubscribePublishedFileResult_t", + "methodname": "UnsubscribePublishedFile", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "UpdatePublishedFileSetChangeDescription", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription", + "params": [ + { "paramname":"updateHandle", "paramtype":"PublishedFileUpdateHandle_t" }, + { "paramname":"pchChangeDescription", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "callresult": "RemoteStorageGetPublishedItemVoteDetailsResult_t", + "methodname": "GetPublishedItemVoteDetails", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageUpdateUserPublishedItemVoteResult_t", + "methodname": "UpdateUserPublishedItemVote", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" }, + { "paramname":"bVoteUp", "paramtype":"bool" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageGetPublishedItemVoteDetailsResult_t", + "methodname": "GetUserPublishedItemVoteDetails", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageEnumerateUserPublishedFilesResult_t", + "methodname": "EnumerateUserSharedWorkshopFiles", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles", + "params": [ + { "paramname":"steamId", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"unStartIndex", "paramtype":"uint32" }, + { "paramname":"pRequiredTags", "paramtype":"SteamParamStringArray_t *" }, + { "paramname":"pExcludedTags", "paramtype":"SteamParamStringArray_t *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStoragePublishFileProgress_t", + "methodname": "PublishVideo", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_PublishVideo", + "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":"SteamParamStringArray_t *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageSetUserPublishedFileActionResult_t", + "methodname": "SetUserPublishedFileAction", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction", + "params": [ + { "paramname":"unPublishedFileId", "paramtype":"PublishedFileId_t" }, + { "paramname":"eAction", "paramtype":"EWorkshopFileAction" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageEnumeratePublishedFilesByUserActionResult_t", + "methodname": "EnumeratePublishedFilesByUserAction", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction", + "params": [ + { "paramname":"eAction", "paramtype":"EWorkshopFileAction" }, + { "paramname":"unStartIndex", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageEnumerateWorkshopFilesResult_t", + "methodname": "EnumeratePublishedWorkshopFiles", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles", + "params": [ + { "paramname":"eEnumerationType", "paramtype":"EWorkshopEnumerationType" }, + { "paramname":"unStartIndex", "paramtype":"uint32" }, + { "paramname":"unCount", "paramtype":"uint32" }, + { "paramname":"unDays", "paramtype":"uint32" }, + { "paramname":"pTags", "paramtype":"SteamParamStringArray_t *" }, + { "paramname":"pUserTags", "paramtype":"SteamParamStringArray_t *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageDownloadUGCResult_t", + "methodname": "UGCDownloadToLocation", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation", + "params": [ + { "paramname":"hContent", "paramtype":"UGCHandle_t" }, + { "paramname":"pchLocation", "paramtype":"const char *" }, + { "paramname":"unPriority", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetLocalFileChangeCount", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetLocalFileChangeCount", + "params": [], + "returntype": "int32" + }, + { + "methodname": "GetLocalFileChange", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_GetLocalFileChange", + "params": [ + { "paramname":"iFile", "paramtype":"int" }, + { "paramname":"pEChangeType", "paramtype":"ERemoteStorageLocalFileChange *" }, + { "paramname":"pEFilePathType", "paramtype":"ERemoteStorageFilePathType *" } + ], + "returntype": "const char *" + }, + { + "methodname": "BeginFileWriteBatch", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch", + "params": [], + "returntype": "bool" + }, + { + "methodname": "EndFileWriteBatch", + "methodname_flat": "SteamAPI_ISteamRemoteStorage_EndFileWriteBatch", + "params": [], + "returntype": "bool" + } + ], + "version_string": "STEAMREMOTESTORAGE_INTERFACE_VERSION016" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamUserStats", + "name_flat": "SteamAPI_SteamUserStats_v012" + } + ], + "classname": "ISteamUserStats", + "fields": [], + "methods": [ + { + "callback": "UserStatsReceived_t", + "methodname": "RequestCurrentStats", + "methodname_flat": "SteamAPI_ISteamUserStats_RequestCurrentStats", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetStat", + "methodname_flat": "SteamAPI_ISteamUserStats_GetStatInt32", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"int32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetStat", + "methodname_flat": "SteamAPI_ISteamUserStats_GetStatFloat", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"float *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetStat", + "methodname_flat": "SteamAPI_ISteamUserStats_SetStatInt32", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"nData", "paramtype":"int32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetStat", + "methodname_flat": "SteamAPI_ISteamUserStats_SetStatFloat", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"fData", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateAvgRateStat", + "methodname_flat": "SteamAPI_ISteamUserStats_UpdateAvgRateStat", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"flCountThisSession", "paramtype":"float" }, + { "paramname":"dSessionLength", "paramtype":"double" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAchievement", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievement", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetAchievement", + "methodname_flat": "SteamAPI_ISteamUserStats_SetAchievement", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "ClearAchievement", + "methodname_flat": "SteamAPI_ISteamUserStats_ClearAchievement", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAchievementAndUnlockTime", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" }, + { "paramname":"punUnlockTime", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "StoreStats", + "methodname_flat": "SteamAPI_ISteamUserStats_StoreStats", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetAchievementIcon", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementIcon", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" } + ], + "returntype": "int" + }, + { + "methodname": "GetAchievementDisplayAttribute", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "const char *" + }, + { + "methodname": "IndicateAchievementProgress", + "methodname_flat": "SteamAPI_ISteamUserStats_IndicateAchievementProgress", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"nCurProgress", "paramtype":"uint32" }, + { "paramname":"nMaxProgress", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetNumAchievements", + "methodname_flat": "SteamAPI_ISteamUserStats_GetNumAchievements", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetAchievementName", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementName", + "params": [ + { "paramname":"iAchievement", "paramtype":"uint32" } + ], + "returntype": "const char *" + }, + { + "callresult": "UserStatsReceived_t", + "methodname": "RequestUserStats", + "methodname_flat": "SteamAPI_ISteamUserStats_RequestUserStats", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetUserStat", + "methodname_flat": "SteamAPI_ISteamUserStats_GetUserStatInt32", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"int32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetUserStat", + "methodname_flat": "SteamAPI_ISteamUserStats_GetUserStatFloat", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"float *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetUserAchievement", + "methodname_flat": "SteamAPI_ISteamUserStats_GetUserAchievement", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetUserAchievementAndUnlockTime", + "methodname_flat": "SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" }, + { "paramname":"punUnlockTime", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "ResetAllStats", + "methodname_flat": "SteamAPI_ISteamUserStats_ResetAllStats", + "params": [ + { "paramname":"bAchievementsToo", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "callresult": "LeaderboardFindResult_t", + "methodname": "FindOrCreateLeaderboard", + "methodname_flat": "SteamAPI_ISteamUserStats_FindOrCreateLeaderboard", + "params": [ + { "paramname":"pchLeaderboardName", "paramtype":"const char *" }, + { "paramname":"eLeaderboardSortMethod", "paramtype":"ELeaderboardSortMethod" }, + { "paramname":"eLeaderboardDisplayType", "paramtype":"ELeaderboardDisplayType" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "LeaderboardFindResult_t", + "methodname": "FindLeaderboard", + "methodname_flat": "SteamAPI_ISteamUserStats_FindLeaderboard", + "params": [ + { "paramname":"pchLeaderboardName", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetLeaderboardName", + "methodname_flat": "SteamAPI_ISteamUserStats_GetLeaderboardName", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetLeaderboardEntryCount", + "methodname_flat": "SteamAPI_ISteamUserStats_GetLeaderboardEntryCount", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" } + ], + "returntype": "int" + }, + { + "methodname": "GetLeaderboardSortMethod", + "methodname_flat": "SteamAPI_ISteamUserStats_GetLeaderboardSortMethod", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" } + ], + "returntype": "ELeaderboardSortMethod" + }, + { + "methodname": "GetLeaderboardDisplayType", + "methodname_flat": "SteamAPI_ISteamUserStats_GetLeaderboardDisplayType", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" } + ], + "returntype": "ELeaderboardDisplayType" + }, + { + "callresult": "LeaderboardScoresDownloaded_t", + "methodname": "DownloadLeaderboardEntries", + "methodname_flat": "SteamAPI_ISteamUserStats_DownloadLeaderboardEntries", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" }, + { "paramname":"eLeaderboardDataRequest", "paramtype":"ELeaderboardDataRequest" }, + { "paramname":"nRangeStart", "paramtype":"int" }, + { "paramname":"nRangeEnd", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "LeaderboardScoresDownloaded_t", + "methodname": "DownloadLeaderboardEntriesForUsers", + "methodname_flat": "SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" }, + { + "array_count": "cUsers", + "desc": "Array of users to retrieve", + "paramname": "prgUsers", + "paramtype": "CSteamID *" + }, + { "paramname":"cUsers", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetDownloadedLeaderboardEntry", + "methodname_flat": "SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry", + "params": [ + { "paramname":"hSteamLeaderboardEntries", "paramtype":"SteamLeaderboardEntries_t" }, + { "paramname":"index", "paramtype":"int" }, + { "paramname":"pLeaderboardEntry", "paramtype":"LeaderboardEntry_t *" }, + { "paramname":"pDetails", "paramtype":"int32 *" }, + { "paramname":"cDetailsMax", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "callresult": "LeaderboardScoreUploaded_t", + "methodname": "UploadLeaderboardScore", + "methodname_flat": "SteamAPI_ISteamUserStats_UploadLeaderboardScore", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" }, + { "paramname":"eLeaderboardUploadScoreMethod", "paramtype":"ELeaderboardUploadScoreMethod" }, + { "paramname":"nScore", "paramtype":"int32" }, + { "paramname":"pScoreDetails", "paramtype":"const int32 *" }, + { "paramname":"cScoreDetailsCount", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "LeaderboardUGCSet_t", + "methodname": "AttachLeaderboardUGC", + "methodname_flat": "SteamAPI_ISteamUserStats_AttachLeaderboardUGC", + "params": [ + { "paramname":"hSteamLeaderboard", "paramtype":"SteamLeaderboard_t" }, + { "paramname":"hUGC", "paramtype":"UGCHandle_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "NumberOfCurrentPlayers_t", + "methodname": "GetNumberOfCurrentPlayers", + "methodname_flat": "SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "GlobalAchievementPercentagesReady_t", + "methodname": "RequestGlobalAchievementPercentages", + "methodname_flat": "SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetMostAchievedAchievementInfo", + "methodname_flat": "SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo", + "params": [ + { "paramname":"pchName", "paramtype":"char *" }, + { "paramname":"unNameBufLen", "paramtype":"uint32" }, + { "paramname":"pflPercent", "paramtype":"float *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" } + ], + "returntype": "int" + }, + { + "methodname": "GetNextMostAchievedAchievementInfo", + "methodname_flat": "SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo", + "params": [ + { "paramname":"iIteratorPrevious", "paramtype":"int" }, + { "paramname":"pchName", "paramtype":"char *" }, + { "paramname":"unNameBufLen", "paramtype":"uint32" }, + { "paramname":"pflPercent", "paramtype":"float *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" } + ], + "returntype": "int" + }, + { + "methodname": "GetAchievementAchievedPercent", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementAchievedPercent", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pflPercent", "paramtype":"float *" } + ], + "returntype": "bool" + }, + { + "callresult": "GlobalStatsReceived_t", + "methodname": "RequestGlobalStats", + "methodname_flat": "SteamAPI_ISteamUserStats_RequestGlobalStats", + "params": [ + { "paramname":"nHistoryDays", "paramtype":"int" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetGlobalStat", + "methodname_flat": "SteamAPI_ISteamUserStats_GetGlobalStatInt64", + "params": [ + { "paramname":"pchStatName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"int64 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetGlobalStat", + "methodname_flat": "SteamAPI_ISteamUserStats_GetGlobalStatDouble", + "params": [ + { "paramname":"pchStatName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"double *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetGlobalStatHistory", + "methodname_flat": "SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64", + "params": [ + { "paramname":"pchStatName", "paramtype":"const char *" }, + { + "array_count": "cubData", + "paramname": "pData", + "paramtype": "int64 *" + }, + { "paramname":"cubData", "paramtype":"uint32" } + ], + "returntype": "int32" + }, + { + "methodname": "GetGlobalStatHistory", + "methodname_flat": "SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble", + "params": [ + { "paramname":"pchStatName", "paramtype":"const char *" }, + { + "array_count": "cubData", + "paramname": "pData", + "paramtype": "double *" + }, + { "paramname":"cubData", "paramtype":"uint32" } + ], + "returntype": "int32" + }, + { + "methodname": "GetAchievementProgressLimits", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementProgressLimitsInt32", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pnMinProgress", "paramtype":"int32 *" }, + { "paramname":"pnMaxProgress", "paramtype":"int32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAchievementProgressLimits", + "methodname_flat": "SteamAPI_ISteamUserStats_GetAchievementProgressLimitsFloat", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pfMinProgress", "paramtype":"float *" }, + { "paramname":"pfMaxProgress", "paramtype":"float *" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMUSERSTATS_INTERFACE_VERSION012" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamApps", + "name_flat": "SteamAPI_SteamApps_v008" + } + ], + "classname": "ISteamApps", + "fields": [], + "methods": [ + { + "methodname": "BIsSubscribed", + "methodname_flat": "SteamAPI_ISteamApps_BIsSubscribed", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsLowViolence", + "methodname_flat": "SteamAPI_ISteamApps_BIsLowViolence", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsCybercafe", + "methodname_flat": "SteamAPI_ISteamApps_BIsCybercafe", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsVACBanned", + "methodname_flat": "SteamAPI_ISteamApps_BIsVACBanned", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetCurrentGameLanguage", + "methodname_flat": "SteamAPI_ISteamApps_GetCurrentGameLanguage", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "GetAvailableGameLanguages", + "methodname_flat": "SteamAPI_ISteamApps_GetAvailableGameLanguages", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "BIsSubscribedApp", + "methodname_flat": "SteamAPI_ISteamApps_BIsSubscribedApp", + "params": [ + { "paramname":"appID", "paramtype":"AppId_t" } + ], + "returntype": "bool" + }, + { + "methodname": "BIsDlcInstalled", + "methodname_flat": "SteamAPI_ISteamApps_BIsDlcInstalled", + "params": [ + { "paramname":"appID", "paramtype":"AppId_t" } + ], + "returntype": "bool" + }, + { + "methodname": "GetEarliestPurchaseUnixTime", + "methodname_flat": "SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "uint32" + }, + { + "methodname": "BIsSubscribedFromFreeWeekend", + "methodname_flat": "SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetDLCCount", + "methodname_flat": "SteamAPI_ISteamApps_GetDLCCount", + "params": [], + "returntype": "int" + }, + { + "methodname": "BGetDLCDataByIndex", + "methodname_flat": "SteamAPI_ISteamApps_BGetDLCDataByIndex", + "params": [ + { "paramname":"iDLC", "paramtype":"int" }, + { "paramname":"pAppID", "paramtype":"AppId_t *" }, + { "paramname":"pbAvailable", "paramtype":"bool *" }, + { "paramname":"pchName", "paramtype":"char *" }, + { "paramname":"cchNameBufferSize", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "InstallDLC", + "methodname_flat": "SteamAPI_ISteamApps_InstallDLC", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "void" + }, + { + "methodname": "UninstallDLC", + "methodname_flat": "SteamAPI_ISteamApps_UninstallDLC", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "void" + }, + { + "methodname": "RequestAppProofOfPurchaseKey", + "methodname_flat": "SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetCurrentBetaName", + "methodname_flat": "SteamAPI_ISteamApps_GetCurrentBetaName", + "params": [ + { "paramname":"pchName", "paramtype":"char *" }, + { "paramname":"cchNameBufferSize", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "MarkContentCorrupt", + "methodname_flat": "SteamAPI_ISteamApps_MarkContentCorrupt", + "params": [ + { "paramname":"bMissingFilesOnly", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "GetInstalledDepots", + "methodname_flat": "SteamAPI_ISteamApps_GetInstalledDepots", + "params": [ + { "paramname":"appID", "paramtype":"AppId_t" }, + { "paramname":"pvecDepots", "paramtype":"DepotId_t *" }, + { "paramname":"cMaxDepots", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetAppInstallDir", + "methodname_flat": "SteamAPI_ISteamApps_GetAppInstallDir", + "params": [ + { "paramname":"appID", "paramtype":"AppId_t" }, + { "paramname":"pchFolder", "paramtype":"char *" }, + { "paramname":"cchFolderBufferSize", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "BIsAppInstalled", + "methodname_flat": "SteamAPI_ISteamApps_BIsAppInstalled", + "params": [ + { "paramname":"appID", "paramtype":"AppId_t" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAppOwner", + "methodname_flat": "SteamAPI_ISteamApps_GetAppOwner", + "params": [], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetLaunchQueryParam", + "methodname_flat": "SteamAPI_ISteamApps_GetLaunchQueryParam", + "params": [ + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetDlcDownloadProgress", + "methodname_flat": "SteamAPI_ISteamApps_GetDlcDownloadProgress", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" }, + { "paramname":"punBytesDownloaded", "paramtype":"uint64 *" }, + { "paramname":"punBytesTotal", "paramtype":"uint64 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetAppBuildId", + "methodname_flat": "SteamAPI_ISteamApps_GetAppBuildId", + "params": [], + "returntype": "int" + }, + { + "methodname": "RequestAllProofOfPurchaseKeys", + "methodname_flat": "SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys", + "params": [], + "returntype": "void" + }, + { + "callresult": "FileDetailsResult_t", + "methodname": "GetFileDetails", + "methodname_flat": "SteamAPI_ISteamApps_GetFileDetails", + "params": [ + { "paramname":"pszFileName", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetLaunchCommandLine", + "methodname_flat": "SteamAPI_ISteamApps_GetLaunchCommandLine", + "params": [ + { "paramname":"pszCommandLine", "paramtype":"char *" }, + { "paramname":"cubCommandLine", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "BIsSubscribedFromFamilySharing", + "methodname_flat": "SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsTimedTrial", + "methodname_flat": "SteamAPI_ISteamApps_BIsTimedTrial", + "params": [ + { "paramname":"punSecondsAllowed", "paramtype":"uint32 *" }, + { "paramname":"punSecondsPlayed", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetDlcContext", + "methodname_flat": "SteamAPI_ISteamApps_SetDlcContext", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMAPPS_INTERFACE_VERSION008" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamNetworking", + "name_flat": "SteamAPI_SteamNetworking_v006" + }, + { + "kind": "gameserver", + "name": "SteamGameServerNetworking", + "name_flat": "SteamAPI_SteamGameServerNetworking_v006" + } + ], + "classname": "ISteamNetworking", + "fields": [], + "methods": [ + { + "methodname": "SendP2PPacket", + "methodname_flat": "SteamAPI_ISteamNetworking_SendP2PPacket", + "params": [ + { "paramname":"steamIDRemote", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pubData", "paramtype":"const void *" }, + { "paramname":"cubData", "paramtype":"uint32" }, + { "paramname":"eP2PSendType", "paramtype":"EP2PSend" }, + { "paramname":"nChannel", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "IsP2PPacketAvailable", + "methodname_flat": "SteamAPI_ISteamNetworking_IsP2PPacketAvailable", + "params": [ + { "paramname":"pcubMsgSize", "paramtype":"uint32 *" }, + { "paramname":"nChannel", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "ReadP2PPacket", + "methodname_flat": "SteamAPI_ISteamNetworking_ReadP2PPacket", + "params": [ + { "paramname":"pubDest", "paramtype":"void *" }, + { "paramname":"cubDest", "paramtype":"uint32" }, + { "paramname":"pcubMsgSize", "paramtype":"uint32 *" }, + { "paramname":"psteamIDRemote", "paramtype":"CSteamID *" }, + { "paramname":"nChannel", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "AcceptP2PSessionWithUser", + "methodname_flat": "SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser", + "params": [ + { "paramname":"steamIDRemote", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "CloseP2PSessionWithUser", + "methodname_flat": "SteamAPI_ISteamNetworking_CloseP2PSessionWithUser", + "params": [ + { "paramname":"steamIDRemote", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "CloseP2PChannelWithUser", + "methodname_flat": "SteamAPI_ISteamNetworking_CloseP2PChannelWithUser", + "params": [ + { "paramname":"steamIDRemote", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"nChannel", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetP2PSessionState", + "methodname_flat": "SteamAPI_ISteamNetworking_GetP2PSessionState", + "params": [ + { "paramname":"steamIDRemote", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pConnectionState", "paramtype":"P2PSessionState_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "AllowP2PPacketRelay", + "methodname_flat": "SteamAPI_ISteamNetworking_AllowP2PPacketRelay", + "params": [ + { "paramname":"bAllow", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "CreateListenSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_CreateListenSocket", + "params": [ + { "paramname":"nVirtualP2PPort", "paramtype":"int" }, + { "paramname":"nIP", "paramtype":"SteamIPAddress_t" }, + { "paramname":"nPort", "paramtype":"uint16" }, + { "paramname":"bAllowUseOfPacketRelay", "paramtype":"bool" } + ], + "returntype": "SNetListenSocket_t" + }, + { + "methodname": "CreateP2PConnectionSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_CreateP2PConnectionSocket", + "params": [ + { "paramname":"steamIDTarget", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"nVirtualPort", "paramtype":"int" }, + { "paramname":"nTimeoutSec", "paramtype":"int" }, + { "paramname":"bAllowUseOfPacketRelay", "paramtype":"bool" } + ], + "returntype": "SNetSocket_t" + }, + { + "methodname": "CreateConnectionSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_CreateConnectionSocket", + "params": [ + { "paramname":"nIP", "paramtype":"SteamIPAddress_t" }, + { "paramname":"nPort", "paramtype":"uint16" }, + { "paramname":"nTimeoutSec", "paramtype":"int" } + ], + "returntype": "SNetSocket_t" + }, + { + "methodname": "DestroySocket", + "methodname_flat": "SteamAPI_ISteamNetworking_DestroySocket", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" }, + { "paramname":"bNotifyRemoteEnd", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "DestroyListenSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_DestroyListenSocket", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetListenSocket_t" }, + { "paramname":"bNotifyRemoteEnd", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SendDataOnSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_SendDataOnSocket", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" }, + { "paramname":"pubData", "paramtype":"void *" }, + { "paramname":"cubData", "paramtype":"uint32" }, + { "paramname":"bReliable", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "IsDataAvailableOnSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_IsDataAvailableOnSocket", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" }, + { "paramname":"pcubMsgSize", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "RetrieveDataFromSocket", + "methodname_flat": "SteamAPI_ISteamNetworking_RetrieveDataFromSocket", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" }, + { "paramname":"pubDest", "paramtype":"void *" }, + { "paramname":"cubDest", "paramtype":"uint32" }, + { "paramname":"pcubMsgSize", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "IsDataAvailable", + "methodname_flat": "SteamAPI_ISteamNetworking_IsDataAvailable", + "params": [ + { "paramname":"hListenSocket", "paramtype":"SNetListenSocket_t" }, + { "paramname":"pcubMsgSize", "paramtype":"uint32 *" }, + { "paramname":"phSocket", "paramtype":"SNetSocket_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "RetrieveData", + "methodname_flat": "SteamAPI_ISteamNetworking_RetrieveData", + "params": [ + { "paramname":"hListenSocket", "paramtype":"SNetListenSocket_t" }, + { "paramname":"pubDest", "paramtype":"void *" }, + { "paramname":"cubDest", "paramtype":"uint32" }, + { "paramname":"pcubMsgSize", "paramtype":"uint32 *" }, + { "paramname":"phSocket", "paramtype":"SNetSocket_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetSocketInfo", + "methodname_flat": "SteamAPI_ISteamNetworking_GetSocketInfo", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" }, + { "paramname":"pSteamIDRemote", "paramtype":"CSteamID *" }, + { "paramname":"peSocketStatus", "paramtype":"int *" }, + { "paramname":"punIPRemote", "paramtype":"SteamIPAddress_t *" }, + { "paramname":"punPortRemote", "paramtype":"uint16 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetListenSocketInfo", + "methodname_flat": "SteamAPI_ISteamNetworking_GetListenSocketInfo", + "params": [ + { "paramname":"hListenSocket", "paramtype":"SNetListenSocket_t" }, + { "paramname":"pnIP", "paramtype":"SteamIPAddress_t *" }, + { "paramname":"pnPort", "paramtype":"uint16 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetSocketConnectionType", + "methodname_flat": "SteamAPI_ISteamNetworking_GetSocketConnectionType", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" } + ], + "returntype": "ESNetSocketConnectionType" + }, + { + "methodname": "GetMaxPacketSize", + "methodname_flat": "SteamAPI_ISteamNetworking_GetMaxPacketSize", + "params": [ + { "paramname":"hSocket", "paramtype":"SNetSocket_t" } + ], + "returntype": "int" + } + ], + "version_string": "SteamNetworking006" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamScreenshots", + "name_flat": "SteamAPI_SteamScreenshots_v003" + } + ], + "classname": "ISteamScreenshots", + "fields": [], + "methods": [ + { + "methodname": "WriteScreenshot", + "methodname_flat": "SteamAPI_ISteamScreenshots_WriteScreenshot", + "params": [ + { "paramname":"pubRGB", "paramtype":"void *" }, + { "paramname":"cubRGB", "paramtype":"uint32" }, + { "paramname":"nWidth", "paramtype":"int" }, + { "paramname":"nHeight", "paramtype":"int" } + ], + "returntype": "ScreenshotHandle" + }, + { + "methodname": "AddScreenshotToLibrary", + "methodname_flat": "SteamAPI_ISteamScreenshots_AddScreenshotToLibrary", + "params": [ + { "paramname":"pchFilename", "paramtype":"const char *" }, + { "paramname":"pchThumbnailFilename", "paramtype":"const char *" }, + { "paramname":"nWidth", "paramtype":"int" }, + { "paramname":"nHeight", "paramtype":"int" } + ], + "returntype": "ScreenshotHandle" + }, + { + "methodname": "TriggerScreenshot", + "methodname_flat": "SteamAPI_ISteamScreenshots_TriggerScreenshot", + "params": [], + "returntype": "void" + }, + { + "methodname": "HookScreenshots", + "methodname_flat": "SteamAPI_ISteamScreenshots_HookScreenshots", + "params": [ + { "paramname":"bHook", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "SetLocation", + "methodname_flat": "SteamAPI_ISteamScreenshots_SetLocation", + "params": [ + { "paramname":"hScreenshot", "paramtype":"ScreenshotHandle" }, + { "paramname":"pchLocation", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "TagUser", + "methodname_flat": "SteamAPI_ISteamScreenshots_TagUser", + "params": [ + { "paramname":"hScreenshot", "paramtype":"ScreenshotHandle" }, + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "TagPublishedFile", + "methodname_flat": "SteamAPI_ISteamScreenshots_TagPublishedFile", + "params": [ + { "paramname":"hScreenshot", "paramtype":"ScreenshotHandle" }, + { "paramname":"unPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "bool" + }, + { + "methodname": "IsScreenshotsHooked", + "methodname_flat": "SteamAPI_ISteamScreenshots_IsScreenshotsHooked", + "params": [], + "returntype": "bool" + }, + { + "methodname": "AddVRScreenshotToLibrary", + "methodname_flat": "SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary", + "params": [ + { "paramname":"eType", "paramtype":"EVRScreenshotType" }, + { "paramname":"pchFilename", "paramtype":"const char *" }, + { "paramname":"pchVRFilename", "paramtype":"const char *" } + ], + "returntype": "ScreenshotHandle" + } + ], + "version_string": "STEAMSCREENSHOTS_INTERFACE_VERSION003" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamMusic", + "name_flat": "SteamAPI_SteamMusic_v001" + } + ], + "classname": "ISteamMusic", + "fields": [], + "methods": [ + { + "methodname": "BIsEnabled", + "methodname_flat": "SteamAPI_ISteamMusic_BIsEnabled", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsPlaying", + "methodname_flat": "SteamAPI_ISteamMusic_BIsPlaying", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetPlaybackStatus", + "methodname_flat": "SteamAPI_ISteamMusic_GetPlaybackStatus", + "params": [], + "returntype": "AudioPlayback_Status" + }, + { + "methodname": "Play", + "methodname_flat": "SteamAPI_ISteamMusic_Play", + "params": [], + "returntype": "void" + }, + { + "methodname": "Pause", + "methodname_flat": "SteamAPI_ISteamMusic_Pause", + "params": [], + "returntype": "void" + }, + { + "methodname": "PlayPrevious", + "methodname_flat": "SteamAPI_ISteamMusic_PlayPrevious", + "params": [], + "returntype": "void" + }, + { + "methodname": "PlayNext", + "methodname_flat": "SteamAPI_ISteamMusic_PlayNext", + "params": [], + "returntype": "void" + }, + { + "methodname": "SetVolume", + "methodname_flat": "SteamAPI_ISteamMusic_SetVolume", + "params": [ + { "paramname":"flVolume", "paramtype":"float" } + ], + "returntype": "void" + }, + { + "methodname": "GetVolume", + "methodname_flat": "SteamAPI_ISteamMusic_GetVolume", + "params": [], + "returntype": "float" + } + ], + "version_string": "STEAMMUSIC_INTERFACE_VERSION001" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamMusicRemote", + "name_flat": "SteamAPI_SteamMusicRemote_v001" + } + ], + "classname": "ISteamMusicRemote", + "fields": [], + "methods": [ + { + "methodname": "RegisterSteamMusicRemote", + "methodname_flat": "SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote", + "params": [ + { "paramname":"pchName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "DeregisterSteamMusicRemote", + "methodname_flat": "SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsCurrentMusicRemote", + "methodname_flat": "SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BActivationSuccess", + "methodname_flat": "SteamAPI_ISteamMusicRemote_BActivationSuccess", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetDisplayName", + "methodname_flat": "SteamAPI_ISteamMusicRemote_SetDisplayName", + "params": [ + { "paramname":"pchDisplayName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetPNGIcon_64x64", + "methodname_flat": "SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64", + "params": [ + { "paramname":"pvBuffer", "paramtype":"void *" }, + { "paramname":"cbBufferLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "EnablePlayPrevious", + "methodname_flat": "SteamAPI_ISteamMusicRemote_EnablePlayPrevious", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "EnablePlayNext", + "methodname_flat": "SteamAPI_ISteamMusicRemote_EnablePlayNext", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "EnableShuffled", + "methodname_flat": "SteamAPI_ISteamMusicRemote_EnableShuffled", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "EnableLooped", + "methodname_flat": "SteamAPI_ISteamMusicRemote_EnableLooped", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "EnableQueue", + "methodname_flat": "SteamAPI_ISteamMusicRemote_EnableQueue", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "EnablePlaylists", + "methodname_flat": "SteamAPI_ISteamMusicRemote_EnablePlaylists", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdatePlaybackStatus", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus", + "params": [ + { "paramname":"nStatus", "paramtype":"AudioPlayback_Status" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateShuffled", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdateShuffled", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateLooped", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdateLooped", + "params": [ + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateVolume", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdateVolume", + "params": [ + { "paramname":"flValue", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "CurrentEntryWillChange", + "methodname_flat": "SteamAPI_ISteamMusicRemote_CurrentEntryWillChange", + "params": [], + "returntype": "bool" + }, + { + "methodname": "CurrentEntryIsAvailable", + "methodname_flat": "SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable", + "params": [ + { "paramname":"bAvailable", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateCurrentEntryText", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText", + "params": [ + { "paramname":"pchText", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateCurrentEntryElapsedSeconds", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds", + "params": [ + { "paramname":"nValue", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateCurrentEntryCoverArt", + "methodname_flat": "SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt", + "params": [ + { "paramname":"pvBuffer", "paramtype":"void *" }, + { "paramname":"cbBufferLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "CurrentEntryDidChange", + "methodname_flat": "SteamAPI_ISteamMusicRemote_CurrentEntryDidChange", + "params": [], + "returntype": "bool" + }, + { + "methodname": "QueueWillChange", + "methodname_flat": "SteamAPI_ISteamMusicRemote_QueueWillChange", + "params": [], + "returntype": "bool" + }, + { + "methodname": "ResetQueueEntries", + "methodname_flat": "SteamAPI_ISteamMusicRemote_ResetQueueEntries", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetQueueEntry", + "methodname_flat": "SteamAPI_ISteamMusicRemote_SetQueueEntry", + "params": [ + { "paramname":"nID", "paramtype":"int" }, + { "paramname":"nPosition", "paramtype":"int" }, + { "paramname":"pchEntryText", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetCurrentQueueEntry", + "methodname_flat": "SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry", + "params": [ + { "paramname":"nID", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "QueueDidChange", + "methodname_flat": "SteamAPI_ISteamMusicRemote_QueueDidChange", + "params": [], + "returntype": "bool" + }, + { + "methodname": "PlaylistWillChange", + "methodname_flat": "SteamAPI_ISteamMusicRemote_PlaylistWillChange", + "params": [], + "returntype": "bool" + }, + { + "methodname": "ResetPlaylistEntries", + "methodname_flat": "SteamAPI_ISteamMusicRemote_ResetPlaylistEntries", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetPlaylistEntry", + "methodname_flat": "SteamAPI_ISteamMusicRemote_SetPlaylistEntry", + "params": [ + { "paramname":"nID", "paramtype":"int" }, + { "paramname":"nPosition", "paramtype":"int" }, + { "paramname":"pchEntryText", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetCurrentPlaylistEntry", + "methodname_flat": "SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry", + "params": [ + { "paramname":"nID", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "PlaylistDidChange", + "methodname_flat": "SteamAPI_ISteamMusicRemote_PlaylistDidChange", + "params": [], + "returntype": "bool" + } + ], + "version_string": "STEAMMUSICREMOTE_INTERFACE_VERSION001" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamHTTP", + "name_flat": "SteamAPI_SteamHTTP_v003" + }, + { + "kind": "gameserver", + "name": "SteamGameServerHTTP", + "name_flat": "SteamAPI_SteamGameServerHTTP_v003" + } + ], + "classname": "ISteamHTTP", + "fields": [], + "methods": [ + { + "methodname": "CreateHTTPRequest", + "methodname_flat": "SteamAPI_ISteamHTTP_CreateHTTPRequest", + "params": [ + { "paramname":"eHTTPRequestMethod", "paramtype":"EHTTPMethod" }, + { "paramname":"pchAbsoluteURL", "paramtype":"const char *" } + ], + "returntype": "HTTPRequestHandle" + }, + { + "methodname": "SetHTTPRequestContextValue", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestContextValue", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"ulContextValue", "paramtype":"uint64" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestNetworkActivityTimeout", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"unTimeoutSeconds", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestHeaderValue", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pchHeaderName", "paramtype":"const char *" }, + { "paramname":"pchHeaderValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestGetOrPostParameter", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pchParamName", "paramtype":"const char *" }, + { "paramname":"pchParamValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SendHTTPRequest", + "methodname_flat": "SteamAPI_ISteamHTTP_SendHTTPRequest", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pCallHandle", "paramtype":"SteamAPICall_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "SendHTTPRequestAndStreamResponse", + "methodname_flat": "SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pCallHandle", "paramtype":"SteamAPICall_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "DeferHTTPRequest", + "methodname_flat": "SteamAPI_ISteamHTTP_DeferHTTPRequest", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" } + ], + "returntype": "bool" + }, + { + "methodname": "PrioritizeHTTPRequest", + "methodname_flat": "SteamAPI_ISteamHTTP_PrioritizeHTTPRequest", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPResponseHeaderSize", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pchHeaderName", "paramtype":"const char *" }, + { "paramname":"unResponseHeaderSize", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPResponseHeaderValue", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pchHeaderName", "paramtype":"const char *" }, + { "paramname":"pHeaderValueBuffer", "paramtype":"uint8 *" }, + { "paramname":"unBufferSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPResponseBodySize", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPResponseBodySize", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"unBodySize", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPResponseBodyData", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPResponseBodyData", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pBodyDataBuffer", "paramtype":"uint8 *" }, + { "paramname":"unBufferSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPStreamingResponseBodyData", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"cOffset", "paramtype":"uint32" }, + { "paramname":"pBodyDataBuffer", "paramtype":"uint8 *" }, + { "paramname":"unBufferSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "ReleaseHTTPRequest", + "methodname_flat": "SteamAPI_ISteamHTTP_ReleaseHTTPRequest", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPDownloadProgressPct", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pflPercentOut", "paramtype":"float *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestRawPostBody", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pchContentType", "paramtype":"const char *" }, + { "paramname":"pubBody", "paramtype":"uint8 *" }, + { "paramname":"unBodyLen", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "CreateCookieContainer", + "methodname_flat": "SteamAPI_ISteamHTTP_CreateCookieContainer", + "params": [ + { "paramname":"bAllowResponsesToModify", "paramtype":"bool" } + ], + "returntype": "HTTPCookieContainerHandle" + }, + { + "methodname": "ReleaseCookieContainer", + "methodname_flat": "SteamAPI_ISteamHTTP_ReleaseCookieContainer", + "params": [ + { "paramname":"hCookieContainer", "paramtype":"HTTPCookieContainerHandle" } + ], + "returntype": "bool" + }, + { + "methodname": "SetCookie", + "methodname_flat": "SteamAPI_ISteamHTTP_SetCookie", + "params": [ + { "paramname":"hCookieContainer", "paramtype":"HTTPCookieContainerHandle" }, + { "paramname":"pchHost", "paramtype":"const char *" }, + { "paramname":"pchUrl", "paramtype":"const char *" }, + { "paramname":"pchCookie", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestCookieContainer", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"hCookieContainer", "paramtype":"HTTPCookieContainerHandle" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestUserAgentInfo", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pchUserAgentInfo", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestRequiresVerifiedCertificate", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"bRequireVerifiedCertificate", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetHTTPRequestAbsoluteTimeoutMS", + "methodname_flat": "SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"unMilliseconds", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetHTTPRequestWasTimedOut", + "methodname_flat": "SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut", + "params": [ + { "paramname":"hRequest", "paramtype":"HTTPRequestHandle" }, + { "paramname":"pbWasTimedOut", "paramtype":"bool *" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMHTTP_INTERFACE_VERSION003" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamInput", + "name_flat": "SteamAPI_SteamInput_v006" + } + ], + "classname": "ISteamInput", + "fields": [], + "methods": [ + { + "methodname": "Init", + "methodname_flat": "SteamAPI_ISteamInput_Init", + "params": [ + { "paramname":"bExplicitlyCallRunFrame", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "Shutdown", + "methodname_flat": "SteamAPI_ISteamInput_Shutdown", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetInputActionManifestFilePath", + "methodname_flat": "SteamAPI_ISteamInput_SetInputActionManifestFilePath", + "params": [ + { "paramname":"pchInputActionManifestAbsolutePath", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "RunFrame", + "methodname_flat": "SteamAPI_ISteamInput_RunFrame", + "params": [ + { "paramname":"bReservedValue", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "BWaitForData", + "methodname_flat": "SteamAPI_ISteamInput_BWaitForData", + "params": [ + { "paramname":"bWaitForever", "paramtype":"bool" }, + { "paramname":"unTimeout", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "BNewDataAvailable", + "methodname_flat": "SteamAPI_ISteamInput_BNewDataAvailable", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetConnectedControllers", + "methodname_flat": "SteamAPI_ISteamInput_GetConnectedControllers", + "params": [ + { + "desc": "Receives list of connected controllers", + "out_array_count": "STEAM_INPUT_MAX_COUNT", + "paramname": "handlesOut", + "paramtype": "InputHandle_t *" + } + ], + "returntype": "int" + }, + { + "callback": "SteamInputConfigurationLoaded_t", + "methodname": "EnableDeviceCallbacks", + "methodname_flat": "SteamAPI_ISteamInput_EnableDeviceCallbacks", + "params": [], + "returntype": "void" + }, + { + "callback": "SteamInputGamepadSlotChange_t", + "methodname": "EnableActionEventCallbacks", + "methodname_flat": "SteamAPI_ISteamInput_EnableActionEventCallbacks", + "params": [ + { "paramname":"pCallback", "paramtype":"SteamInputActionEventCallbackPointer" } + ], + "returntype": "void" + }, + { + "methodname": "GetActionSetHandle", + "methodname_flat": "SteamAPI_ISteamInput_GetActionSetHandle", + "params": [ + { "paramname":"pszActionSetName", "paramtype":"const char *" } + ], + "returntype": "InputActionSetHandle_t" + }, + { + "methodname": "ActivateActionSet", + "methodname_flat": "SteamAPI_ISteamInput_ActivateActionSet", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"actionSetHandle", "paramtype":"InputActionSetHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetCurrentActionSet", + "methodname_flat": "SteamAPI_ISteamInput_GetCurrentActionSet", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "InputActionSetHandle_t" + }, + { + "methodname": "ActivateActionSetLayer", + "methodname_flat": "SteamAPI_ISteamInput_ActivateActionSetLayer", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"actionSetLayerHandle", "paramtype":"InputActionSetHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "DeactivateActionSetLayer", + "methodname_flat": "SteamAPI_ISteamInput_DeactivateActionSetLayer", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"actionSetLayerHandle", "paramtype":"InputActionSetHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "DeactivateAllActionSetLayers", + "methodname_flat": "SteamAPI_ISteamInput_DeactivateAllActionSetLayers", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetActiveActionSetLayers", + "methodname_flat": "SteamAPI_ISteamInput_GetActiveActionSetLayers", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { + "desc": "Receives list of active layers", + "out_array_count": "STEAM_INPUT_MAX_ACTIVE_LAYERS", + "paramname": "handlesOut", + "paramtype": "InputActionSetHandle_t *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetDigitalActionHandle", + "methodname_flat": "SteamAPI_ISteamInput_GetDigitalActionHandle", + "params": [ + { "paramname":"pszActionName", "paramtype":"const char *" } + ], + "returntype": "InputDigitalActionHandle_t" + }, + { + "methodname": "GetDigitalActionData", + "methodname_flat": "SteamAPI_ISteamInput_GetDigitalActionData", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"digitalActionHandle", "paramtype":"InputDigitalActionHandle_t" } + ], + "returntype": "InputDigitalActionData_t" + }, + { + "methodname": "GetDigitalActionOrigins", + "methodname_flat": "SteamAPI_ISteamInput_GetDigitalActionOrigins", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"actionSetHandle", "paramtype":"InputActionSetHandle_t" }, + { "paramname":"digitalActionHandle", "paramtype":"InputDigitalActionHandle_t" }, + { + "desc": "Receives list of action origins", + "out_array_count": "STEAM_INPUT_MAX_ORIGINS", + "paramname": "originsOut", + "paramtype": "EInputActionOrigin *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetStringForDigitalActionName", + "methodname_flat": "SteamAPI_ISteamInput_GetStringForDigitalActionName", + "params": [ + { "paramname":"eActionHandle", "paramtype":"InputDigitalActionHandle_t" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetAnalogActionHandle", + "methodname_flat": "SteamAPI_ISteamInput_GetAnalogActionHandle", + "params": [ + { "paramname":"pszActionName", "paramtype":"const char *" } + ], + "returntype": "InputAnalogActionHandle_t" + }, + { + "methodname": "GetAnalogActionData", + "methodname_flat": "SteamAPI_ISteamInput_GetAnalogActionData", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"analogActionHandle", "paramtype":"InputAnalogActionHandle_t" } + ], + "returntype": "InputAnalogActionData_t" + }, + { + "methodname": "GetAnalogActionOrigins", + "methodname_flat": "SteamAPI_ISteamInput_GetAnalogActionOrigins", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"actionSetHandle", "paramtype":"InputActionSetHandle_t" }, + { "paramname":"analogActionHandle", "paramtype":"InputAnalogActionHandle_t" }, + { + "desc": "Receives list of action origins", + "out_array_count": "STEAM_INPUT_MAX_ORIGINS", + "paramname": "originsOut", + "paramtype": "EInputActionOrigin *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetGlyphPNGForActionOrigin", + "methodname_flat": "SteamAPI_ISteamInput_GetGlyphPNGForActionOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EInputActionOrigin" }, + { "paramname":"eSize", "paramtype":"ESteamInputGlyphSize" }, + { "paramname":"unFlags", "paramtype":"uint32" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetGlyphSVGForActionOrigin", + "methodname_flat": "SteamAPI_ISteamInput_GetGlyphSVGForActionOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EInputActionOrigin" }, + { "paramname":"unFlags", "paramtype":"uint32" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetGlyphForActionOrigin_Legacy", + "methodname_flat": "SteamAPI_ISteamInput_GetGlyphForActionOrigin_Legacy", + "params": [ + { "paramname":"eOrigin", "paramtype":"EInputActionOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetStringForActionOrigin", + "methodname_flat": "SteamAPI_ISteamInput_GetStringForActionOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EInputActionOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetStringForAnalogActionName", + "methodname_flat": "SteamAPI_ISteamInput_GetStringForAnalogActionName", + "params": [ + { "paramname":"eActionHandle", "paramtype":"InputAnalogActionHandle_t" } + ], + "returntype": "const char *" + }, + { + "methodname": "StopAnalogActionMomentum", + "methodname_flat": "SteamAPI_ISteamInput_StopAnalogActionMomentum", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"eAction", "paramtype":"InputAnalogActionHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetMotionData", + "methodname_flat": "SteamAPI_ISteamInput_GetMotionData", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "InputMotionData_t" + }, + { + "methodname": "TriggerVibration", + "methodname_flat": "SteamAPI_ISteamInput_TriggerVibration", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"usLeftSpeed", "paramtype":"unsigned short" }, + { "paramname":"usRightSpeed", "paramtype":"unsigned short" } + ], + "returntype": "void" + }, + { + "methodname": "TriggerVibrationExtended", + "methodname_flat": "SteamAPI_ISteamInput_TriggerVibrationExtended", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"usLeftSpeed", "paramtype":"unsigned short" }, + { "paramname":"usRightSpeed", "paramtype":"unsigned short" }, + { "paramname":"usLeftTriggerSpeed", "paramtype":"unsigned short" }, + { "paramname":"usRightTriggerSpeed", "paramtype":"unsigned short" } + ], + "returntype": "void" + }, + { + "methodname": "TriggerSimpleHapticEvent", + "methodname_flat": "SteamAPI_ISteamInput_TriggerSimpleHapticEvent", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"eHapticLocation", "paramtype":"EControllerHapticLocation" }, + { "paramname":"nIntensity", "paramtype":"uint8" }, + { "paramname":"nGainDB", "paramtype":"char" }, + { "paramname":"nOtherIntensity", "paramtype":"uint8" }, + { "paramname":"nOtherGainDB", "paramtype":"char" } + ], + "returntype": "void" + }, + { + "methodname": "SetLEDColor", + "methodname_flat": "SteamAPI_ISteamInput_SetLEDColor", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"nColorR", "paramtype":"uint8" }, + { "paramname":"nColorG", "paramtype":"uint8" }, + { "paramname":"nColorB", "paramtype":"uint8" }, + { "paramname":"nFlags", "paramtype":"unsigned int" } + ], + "returntype": "void" + }, + { + "methodname": "Legacy_TriggerHapticPulse", + "methodname_flat": "SteamAPI_ISteamInput_Legacy_TriggerHapticPulse", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"eTargetPad", "paramtype":"ESteamControllerPad" }, + { "paramname":"usDurationMicroSec", "paramtype":"unsigned short" } + ], + "returntype": "void" + }, + { + "methodname": "Legacy_TriggerRepeatedHapticPulse", + "methodname_flat": "SteamAPI_ISteamInput_Legacy_TriggerRepeatedHapticPulse", + "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" } + ], + "returntype": "void" + }, + { + "methodname": "ShowBindingPanel", + "methodname_flat": "SteamAPI_ISteamInput_ShowBindingPanel", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "bool" + }, + { + "methodname": "GetInputTypeForHandle", + "methodname_flat": "SteamAPI_ISteamInput_GetInputTypeForHandle", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "ESteamInputType" + }, + { + "methodname": "GetControllerForGamepadIndex", + "methodname_flat": "SteamAPI_ISteamInput_GetControllerForGamepadIndex", + "params": [ + { "paramname":"nIndex", "paramtype":"int" } + ], + "returntype": "InputHandle_t" + }, + { + "methodname": "GetGamepadIndexForController", + "methodname_flat": "SteamAPI_ISteamInput_GetGamepadIndexForController", + "params": [ + { "paramname":"ulinputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "int" + }, + { + "methodname": "GetStringForXboxOrigin", + "methodname_flat": "SteamAPI_ISteamInput_GetStringForXboxOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EXboxOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetGlyphForXboxOrigin", + "methodname_flat": "SteamAPI_ISteamInput_GetGlyphForXboxOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EXboxOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetActionOriginFromXboxOrigin", + "methodname_flat": "SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"eOrigin", "paramtype":"EXboxOrigin" } + ], + "returntype": "EInputActionOrigin" + }, + { + "methodname": "TranslateActionOrigin", + "methodname_flat": "SteamAPI_ISteamInput_TranslateActionOrigin", + "params": [ + { "paramname":"eDestinationInputType", "paramtype":"ESteamInputType" }, + { "paramname":"eSourceOrigin", "paramtype":"EInputActionOrigin" } + ], + "returntype": "EInputActionOrigin" + }, + { + "methodname": "GetDeviceBindingRevision", + "methodname_flat": "SteamAPI_ISteamInput_GetDeviceBindingRevision", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"pMajor", "paramtype":"int *" }, + { "paramname":"pMinor", "paramtype":"int *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetRemotePlaySessionID", + "methodname_flat": "SteamAPI_ISteamInput_GetRemotePlaySessionID", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetSessionInputConfigurationSettings", + "methodname_flat": "SteamAPI_ISteamInput_GetSessionInputConfigurationSettings", + "params": [], + "returntype": "uint16" + }, + { + "methodname": "SetDualSenseTriggerEffect", + "methodname_flat": "SteamAPI_ISteamInput_SetDualSenseTriggerEffect", + "params": [ + { "paramname":"inputHandle", "paramtype":"InputHandle_t" }, + { "paramname":"pParam", "paramtype":"const ScePadTriggerEffectParam *" } + ], + "returntype": "void" + } + ], + "version_string": "SteamInput006" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamController", + "name_flat": "SteamAPI_SteamController_v008" + } + ], + "classname": "ISteamController", + "fields": [], + "methods": [ + { + "methodname": "Init", + "methodname_flat": "SteamAPI_ISteamController_Init", + "params": [], + "returntype": "bool" + }, + { + "methodname": "Shutdown", + "methodname_flat": "SteamAPI_ISteamController_Shutdown", + "params": [], + "returntype": "bool" + }, + { + "methodname": "RunFrame", + "methodname_flat": "SteamAPI_ISteamController_RunFrame", + "params": [], + "returntype": "void" + }, + { + "methodname": "GetConnectedControllers", + "methodname_flat": "SteamAPI_ISteamController_GetConnectedControllers", + "params": [ + { + "desc": "Receives list of connected controllers", + "out_array_count": "STEAM_CONTROLLER_MAX_COUNT", + "paramname": "handlesOut", + "paramtype": "ControllerHandle_t *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetActionSetHandle", + "methodname_flat": "SteamAPI_ISteamController_GetActionSetHandle", + "params": [ + { "paramname":"pszActionSetName", "paramtype":"const char *" } + ], + "returntype": "ControllerActionSetHandle_t" + }, + { + "methodname": "ActivateActionSet", + "methodname_flat": "SteamAPI_ISteamController_ActivateActionSet", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"actionSetHandle", "paramtype":"ControllerActionSetHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetCurrentActionSet", + "methodname_flat": "SteamAPI_ISteamController_GetCurrentActionSet", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" } + ], + "returntype": "ControllerActionSetHandle_t" + }, + { + "methodname": "ActivateActionSetLayer", + "methodname_flat": "SteamAPI_ISteamController_ActivateActionSetLayer", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"actionSetLayerHandle", "paramtype":"ControllerActionSetHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "DeactivateActionSetLayer", + "methodname_flat": "SteamAPI_ISteamController_DeactivateActionSetLayer", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"actionSetLayerHandle", "paramtype":"ControllerActionSetHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "DeactivateAllActionSetLayers", + "methodname_flat": "SteamAPI_ISteamController_DeactivateAllActionSetLayers", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetActiveActionSetLayers", + "methodname_flat": "SteamAPI_ISteamController_GetActiveActionSetLayers", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { + "desc": "Receives list of active layers", + "out_array_count": "STEAM_CONTROLLER_MAX_ACTIVE_LAYERS", + "paramname": "handlesOut", + "paramtype": "ControllerActionSetHandle_t *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetDigitalActionHandle", + "methodname_flat": "SteamAPI_ISteamController_GetDigitalActionHandle", + "params": [ + { "paramname":"pszActionName", "paramtype":"const char *" } + ], + "returntype": "ControllerDigitalActionHandle_t" + }, + { + "methodname": "GetDigitalActionData", + "methodname_flat": "SteamAPI_ISteamController_GetDigitalActionData", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"digitalActionHandle", "paramtype":"ControllerDigitalActionHandle_t" } + ], + "returntype": "InputDigitalActionData_t" + }, + { + "methodname": "GetDigitalActionOrigins", + "methodname_flat": "SteamAPI_ISteamController_GetDigitalActionOrigins", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"actionSetHandle", "paramtype":"ControllerActionSetHandle_t" }, + { "paramname":"digitalActionHandle", "paramtype":"ControllerDigitalActionHandle_t" }, + { + "desc": "Receives list of aciton origins", + "out_array_count": "STEAM_CONTROLLER_MAX_ORIGINS", + "paramname": "originsOut", + "paramtype": "EControllerActionOrigin *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetAnalogActionHandle", + "methodname_flat": "SteamAPI_ISteamController_GetAnalogActionHandle", + "params": [ + { "paramname":"pszActionName", "paramtype":"const char *" } + ], + "returntype": "ControllerAnalogActionHandle_t" + }, + { + "methodname": "GetAnalogActionData", + "methodname_flat": "SteamAPI_ISteamController_GetAnalogActionData", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"analogActionHandle", "paramtype":"ControllerAnalogActionHandle_t" } + ], + "returntype": "InputAnalogActionData_t" + }, + { + "methodname": "GetAnalogActionOrigins", + "methodname_flat": "SteamAPI_ISteamController_GetAnalogActionOrigins", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"actionSetHandle", "paramtype":"ControllerActionSetHandle_t" }, + { "paramname":"analogActionHandle", "paramtype":"ControllerAnalogActionHandle_t" }, + { + "desc": "Receives list of action origins", + "out_array_count": "STEAM_CONTROLLER_MAX_ORIGINS", + "paramname": "originsOut", + "paramtype": "EControllerActionOrigin *" + } + ], + "returntype": "int" + }, + { + "methodname": "GetGlyphForActionOrigin", + "methodname_flat": "SteamAPI_ISteamController_GetGlyphForActionOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EControllerActionOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetStringForActionOrigin", + "methodname_flat": "SteamAPI_ISteamController_GetStringForActionOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EControllerActionOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "StopAnalogActionMomentum", + "methodname_flat": "SteamAPI_ISteamController_StopAnalogActionMomentum", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"eAction", "paramtype":"ControllerAnalogActionHandle_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetMotionData", + "methodname_flat": "SteamAPI_ISteamController_GetMotionData", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" } + ], + "returntype": "InputMotionData_t" + }, + { + "methodname": "TriggerHapticPulse", + "methodname_flat": "SteamAPI_ISteamController_TriggerHapticPulse", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"eTargetPad", "paramtype":"ESteamControllerPad" }, + { "paramname":"usDurationMicroSec", "paramtype":"unsigned short" } + ], + "returntype": "void" + }, + { + "methodname": "TriggerRepeatedHapticPulse", + "methodname_flat": "SteamAPI_ISteamController_TriggerRepeatedHapticPulse", + "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" } + ], + "returntype": "void" + }, + { + "methodname": "TriggerVibration", + "methodname_flat": "SteamAPI_ISteamController_TriggerVibration", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"usLeftSpeed", "paramtype":"unsigned short" }, + { "paramname":"usRightSpeed", "paramtype":"unsigned short" } + ], + "returntype": "void" + }, + { + "methodname": "SetLEDColor", + "methodname_flat": "SteamAPI_ISteamController_SetLEDColor", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"nColorR", "paramtype":"uint8" }, + { "paramname":"nColorG", "paramtype":"uint8" }, + { "paramname":"nColorB", "paramtype":"uint8" }, + { "paramname":"nFlags", "paramtype":"unsigned int" } + ], + "returntype": "void" + }, + { + "methodname": "ShowBindingPanel", + "methodname_flat": "SteamAPI_ISteamController_ShowBindingPanel", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" } + ], + "returntype": "bool" + }, + { + "methodname": "GetInputTypeForHandle", + "methodname_flat": "SteamAPI_ISteamController_GetInputTypeForHandle", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" } + ], + "returntype": "ESteamInputType" + }, + { + "methodname": "GetControllerForGamepadIndex", + "methodname_flat": "SteamAPI_ISteamController_GetControllerForGamepadIndex", + "params": [ + { "paramname":"nIndex", "paramtype":"int" } + ], + "returntype": "ControllerHandle_t" + }, + { + "methodname": "GetGamepadIndexForController", + "methodname_flat": "SteamAPI_ISteamController_GetGamepadIndexForController", + "params": [ + { "paramname":"ulControllerHandle", "paramtype":"ControllerHandle_t" } + ], + "returntype": "int" + }, + { + "methodname": "GetStringForXboxOrigin", + "methodname_flat": "SteamAPI_ISteamController_GetStringForXboxOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EXboxOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetGlyphForXboxOrigin", + "methodname_flat": "SteamAPI_ISteamController_GetGlyphForXboxOrigin", + "params": [ + { "paramname":"eOrigin", "paramtype":"EXboxOrigin" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetActionOriginFromXboxOrigin", + "methodname_flat": "SteamAPI_ISteamController_GetActionOriginFromXboxOrigin", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"eOrigin", "paramtype":"EXboxOrigin" } + ], + "returntype": "EControllerActionOrigin" + }, + { + "methodname": "TranslateActionOrigin", + "methodname_flat": "SteamAPI_ISteamController_TranslateActionOrigin", + "params": [ + { "paramname":"eDestinationInputType", "paramtype":"ESteamInputType" }, + { "paramname":"eSourceOrigin", "paramtype":"EControllerActionOrigin" } + ], + "returntype": "EControllerActionOrigin" + }, + { + "methodname": "GetControllerBindingRevision", + "methodname_flat": "SteamAPI_ISteamController_GetControllerBindingRevision", + "params": [ + { "paramname":"controllerHandle", "paramtype":"ControllerHandle_t" }, + { "paramname":"pMajor", "paramtype":"int *" }, + { "paramname":"pMinor", "paramtype":"int *" } + ], + "returntype": "bool" + } + ], + "version_string": "SteamController008" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamUGC", + "name_flat": "SteamAPI_SteamUGC_v017" + }, + { + "kind": "gameserver", + "name": "SteamGameServerUGC", + "name_flat": "SteamAPI_SteamGameServerUGC_v017" + } + ], + "classname": "ISteamUGC", + "fields": [], + "methods": [ + { + "methodname": "CreateQueryUserUGCRequest", + "methodname_flat": "SteamAPI_ISteamUGC_CreateQueryUserUGCRequest", + "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" } + ], + "returntype": "UGCQueryHandle_t" + }, + { + "methodname": "CreateQueryAllUGCRequest", + "methodname_flat": "SteamAPI_ISteamUGC_CreateQueryAllUGCRequestPage", + "params": [ + { "paramname":"eQueryType", "paramtype":"EUGCQuery" }, + { "paramname":"eMatchingeMatchingUGCTypeFileType", "paramtype":"EUGCMatchingUGCType" }, + { "paramname":"nCreatorAppID", "paramtype":"AppId_t" }, + { "paramname":"nConsumerAppID", "paramtype":"AppId_t" }, + { "paramname":"unPage", "paramtype":"uint32" } + ], + "returntype": "UGCQueryHandle_t" + }, + { + "methodname": "CreateQueryAllUGCRequest", + "methodname_flat": "SteamAPI_ISteamUGC_CreateQueryAllUGCRequestCursor", + "params": [ + { "paramname":"eQueryType", "paramtype":"EUGCQuery" }, + { "paramname":"eMatchingeMatchingUGCTypeFileType", "paramtype":"EUGCMatchingUGCType" }, + { "paramname":"nCreatorAppID", "paramtype":"AppId_t" }, + { "paramname":"nConsumerAppID", "paramtype":"AppId_t" }, + { "paramname":"pchCursor", "paramtype":"const char *" } + ], + "returntype": "UGCQueryHandle_t" + }, + { + "methodname": "CreateQueryUGCDetailsRequest", + "methodname_flat": "SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest", + "params": [ + { "paramname":"pvecPublishedFileID", "paramtype":"PublishedFileId_t *" }, + { "paramname":"unNumPublishedFileIDs", "paramtype":"uint32" } + ], + "returntype": "UGCQueryHandle_t" + }, + { + "callresult": "SteamUGCQueryCompleted_t", + "methodname": "SendQueryUGCRequest", + "methodname_flat": "SteamAPI_ISteamUGC_SendQueryUGCRequest", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetQueryUGCResult", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCResult", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"pDetails", "paramtype":"SteamUGCDetails_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCNumTags", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCNumTags", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetQueryUGCTag", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"indexTag", "paramtype":"uint32" }, + { + "out_string_count": "cchValueSize", + "paramname": "pchValue", + "paramtype": "char *" + }, + { "paramname":"cchValueSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCTagDisplayName", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCTagDisplayName", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"indexTag", "paramtype":"uint32" }, + { + "out_string_count": "cchValueSize", + "paramname": "pchValue", + "paramtype": "char *" + }, + { "paramname":"cchValueSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCPreviewURL", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCPreviewURL", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { + "out_string_count": "cchURLSize", + "paramname": "pchURL", + "paramtype": "char *" + }, + { "paramname":"cchURLSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCMetadata", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCMetadata", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { + "out_string_count": "cchMetadatasize", + "paramname": "pchMetadata", + "paramtype": "char *" + }, + { "paramname":"cchMetadatasize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCChildren", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCChildren", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"pvecPublishedFileID", "paramtype":"PublishedFileId_t *" }, + { "paramname":"cMaxEntries", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCStatistic", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCStatistic", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"eStatType", "paramtype":"EItemStatistic" }, + { "paramname":"pStatValue", "paramtype":"uint64 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCNumAdditionalPreviews", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetQueryUGCAdditionalPreview", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"previewIndex", "paramtype":"uint32" }, + { + "out_string_count": "cchURLSize", + "paramname": "pchURLOrVideoID", + "paramtype": "char *" + }, + { "paramname":"cchURLSize", "paramtype":"uint32" }, + { + "out_string_count": "cchURLSize", + "paramname": "pchOriginalFileName", + "paramtype": "char *" + }, + { "paramname":"cchOriginalFileNameSize", "paramtype":"uint32" }, + { "paramname":"pPreviewType", "paramtype":"EItemPreviewType *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCNumKeyValueTags", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetQueryUGCKeyValueTag", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"keyValueTagIndex", "paramtype":"uint32" }, + { + "out_string_count": "cchKeySize", + "paramname": "pchKey", + "paramtype": "char *" + }, + { "paramname":"cchKeySize", "paramtype":"uint32" }, + { + "out_string_count": "cchValueSize", + "paramname": "pchValue", + "paramtype": "char *" + }, + { "paramname":"cchValueSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCKeyValueTag", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryFirstUGCKeyValueTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"pchKey", "paramtype":"const char *" }, + { + "out_string_count": "cchValueSize", + "paramname": "pchValue", + "paramtype": "char *" + }, + { "paramname":"cchValueSize", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetQueryUGCContentDescriptors", + "methodname_flat": "SteamAPI_ISteamUGC_GetQueryUGCContentDescriptors", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"pvecDescriptors", "paramtype":"EUGCContentDescriptorID *" }, + { "paramname":"cMaxEntries", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "ReleaseQueryUGCRequest", + "methodname_flat": "SteamAPI_ISteamUGC_ReleaseQueryUGCRequest", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" } + ], + "returntype": "bool" + }, + { + "methodname": "AddRequiredTag", + "methodname_flat": "SteamAPI_ISteamUGC_AddRequiredTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pTagName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "AddRequiredTagGroup", + "methodname_flat": "SteamAPI_ISteamUGC_AddRequiredTagGroup", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pTagGroups", "paramtype":"const SteamParamStringArray_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "AddExcludedTag", + "methodname_flat": "SteamAPI_ISteamUGC_AddExcludedTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pTagName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnOnlyIDs", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnOnlyIDs", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnOnlyIDs", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnKeyValueTags", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnKeyValueTags", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnKeyValueTags", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnLongDescription", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnLongDescription", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnLongDescription", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnMetadata", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnMetadata", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnMetadata", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnChildren", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnChildren", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnChildren", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnAdditionalPreviews", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnAdditionalPreviews", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnAdditionalPreviews", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnTotalOnly", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnTotalOnly", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bReturnTotalOnly", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetReturnPlaytimeStats", + "methodname_flat": "SteamAPI_ISteamUGC_SetReturnPlaytimeStats", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"unDays", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetLanguage", + "methodname_flat": "SteamAPI_ISteamUGC_SetLanguage", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pchLanguage", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetAllowCachedResponse", + "methodname_flat": "SteamAPI_ISteamUGC_SetAllowCachedResponse", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"unMaxAgeSeconds", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetCloudFileNameFilter", + "methodname_flat": "SteamAPI_ISteamUGC_SetCloudFileNameFilter", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pMatchCloudFileName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetMatchAnyTag", + "methodname_flat": "SteamAPI_ISteamUGC_SetMatchAnyTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"bMatchAnyTag", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetSearchText", + "methodname_flat": "SteamAPI_ISteamUGC_SetSearchText", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pSearchText", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetRankedByTrendDays", + "methodname_flat": "SteamAPI_ISteamUGC_SetRankedByTrendDays", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"unDays", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetTimeCreatedDateRange", + "methodname_flat": "SteamAPI_ISteamUGC_SetTimeCreatedDateRange", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"rtStart", "paramtype":"RTime32" }, + { "paramname":"rtEnd", "paramtype":"RTime32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetTimeUpdatedDateRange", + "methodname_flat": "SteamAPI_ISteamUGC_SetTimeUpdatedDateRange", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"rtStart", "paramtype":"RTime32" }, + { "paramname":"rtEnd", "paramtype":"RTime32" } + ], + "returntype": "bool" + }, + { + "methodname": "AddRequiredKeyValueTag", + "methodname_flat": "SteamAPI_ISteamUGC_AddRequiredKeyValueTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCQueryHandle_t" }, + { "paramname":"pKey", "paramtype":"const char *" }, + { "paramname":"pValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "callresult": "SteamUGCRequestUGCDetailsResult_t", + "methodname": "RequestUGCDetails", + "methodname_flat": "SteamAPI_ISteamUGC_RequestUGCDetails", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"unMaxAgeSeconds", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "CreateItemResult_t", + "methodname": "CreateItem", + "methodname_flat": "SteamAPI_ISteamUGC_CreateItem", + "params": [ + { "paramname":"nConsumerAppId", "paramtype":"AppId_t" }, + { "paramname":"eFileType", "paramtype":"EWorkshopFileType" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "StartItemUpdate", + "methodname_flat": "SteamAPI_ISteamUGC_StartItemUpdate", + "params": [ + { "paramname":"nConsumerAppId", "paramtype":"AppId_t" }, + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "UGCUpdateHandle_t" + }, + { + "methodname": "SetItemTitle", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemTitle", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchTitle", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemDescription", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemDescription", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchDescription", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemUpdateLanguage", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemUpdateLanguage", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchLanguage", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemMetadata", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemMetadata", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchMetaData", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemVisibility", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemVisibility", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"eVisibility", "paramtype":"ERemoteStoragePublishedFileVisibility" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemTags", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemTags", + "params": [ + { "paramname":"updateHandle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pTags", "paramtype":"const SteamParamStringArray_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemContent", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemContent", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pszContentFolder", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetItemPreview", + "methodname_flat": "SteamAPI_ISteamUGC_SetItemPreview", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pszPreviewFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetAllowLegacyUpload", + "methodname_flat": "SteamAPI_ISteamUGC_SetAllowLegacyUpload", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"bAllowLegacyUpload", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "RemoveAllItemKeyValueTags", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" } + ], + "returntype": "bool" + }, + { + "methodname": "RemoveItemKeyValueTags", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveItemKeyValueTags", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchKey", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "AddItemKeyValueTag", + "methodname_flat": "SteamAPI_ISteamUGC_AddItemKeyValueTag", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchKey", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "AddItemPreviewFile", + "methodname_flat": "SteamAPI_ISteamUGC_AddItemPreviewFile", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pszPreviewFile", "paramtype":"const char *" }, + { "paramname":"type", "paramtype":"EItemPreviewType" } + ], + "returntype": "bool" + }, + { + "methodname": "AddItemPreviewVideo", + "methodname_flat": "SteamAPI_ISteamUGC_AddItemPreviewVideo", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pszVideoID", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateItemPreviewFile", + "methodname_flat": "SteamAPI_ISteamUGC_UpdateItemPreviewFile", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"pszPreviewFile", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateItemPreviewVideo", + "methodname_flat": "SteamAPI_ISteamUGC_UpdateItemPreviewVideo", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"index", "paramtype":"uint32" }, + { "paramname":"pszVideoID", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "RemoveItemPreview", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveItemPreview", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"index", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "AddContentDescriptor", + "methodname_flat": "SteamAPI_ISteamUGC_AddContentDescriptor", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"descid", "paramtype":"EUGCContentDescriptorID" } + ], + "returntype": "bool" + }, + { + "methodname": "RemoveContentDescriptor", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveContentDescriptor", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"descid", "paramtype":"EUGCContentDescriptorID" } + ], + "returntype": "bool" + }, + { + "callresult": "SubmitItemUpdateResult_t", + "methodname": "SubmitItemUpdate", + "methodname_flat": "SteamAPI_ISteamUGC_SubmitItemUpdate", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"pchChangeNote", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetItemUpdateProgress", + "methodname_flat": "SteamAPI_ISteamUGC_GetItemUpdateProgress", + "params": [ + { "paramname":"handle", "paramtype":"UGCUpdateHandle_t" }, + { "paramname":"punBytesProcessed", "paramtype":"uint64 *" }, + { "paramname":"punBytesTotal", "paramtype":"uint64 *" } + ], + "returntype": "EItemUpdateStatus" + }, + { + "callresult": "SetUserItemVoteResult_t", + "methodname": "SetUserItemVote", + "methodname_flat": "SteamAPI_ISteamUGC_SetUserItemVote", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"bVoteUp", "paramtype":"bool" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "GetUserItemVoteResult_t", + "methodname": "GetUserItemVote", + "methodname_flat": "SteamAPI_ISteamUGC_GetUserItemVote", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "UserFavoriteItemsListChanged_t", + "methodname": "AddItemToFavorites", + "methodname_flat": "SteamAPI_ISteamUGC_AddItemToFavorites", + "params": [ + { "paramname":"nAppId", "paramtype":"AppId_t" }, + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "UserFavoriteItemsListChanged_t", + "methodname": "RemoveItemFromFavorites", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveItemFromFavorites", + "params": [ + { "paramname":"nAppId", "paramtype":"AppId_t" }, + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageSubscribePublishedFileResult_t", + "methodname": "SubscribeItem", + "methodname_flat": "SteamAPI_ISteamUGC_SubscribeItem", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoteStorageUnsubscribePublishedFileResult_t", + "methodname": "UnsubscribeItem", + "methodname_flat": "SteamAPI_ISteamUGC_UnsubscribeItem", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetNumSubscribedItems", + "methodname_flat": "SteamAPI_ISteamUGC_GetNumSubscribedItems", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetSubscribedItems", + "methodname_flat": "SteamAPI_ISteamUGC_GetSubscribedItems", + "params": [ + { "paramname":"pvecPublishedFileID", "paramtype":"PublishedFileId_t *" }, + { "paramname":"cMaxEntries", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetItemState", + "methodname_flat": "SteamAPI_ISteamUGC_GetItemState", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetItemInstallInfo", + "methodname_flat": "SteamAPI_ISteamUGC_GetItemInstallInfo", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"punSizeOnDisk", "paramtype":"uint64 *" }, + { + "out_string_count": "cchFolderSize", + "paramname": "pchFolder", + "paramtype": "char *" + }, + { "paramname":"cchFolderSize", "paramtype":"uint32" }, + { "paramname":"punTimeStamp", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetItemDownloadInfo", + "methodname_flat": "SteamAPI_ISteamUGC_GetItemDownloadInfo", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"punBytesDownloaded", "paramtype":"uint64 *" }, + { "paramname":"punBytesTotal", "paramtype":"uint64 *" } + ], + "returntype": "bool" + }, + { + "methodname": "DownloadItem", + "methodname_flat": "SteamAPI_ISteamUGC_DownloadItem", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"bHighPriority", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "BInitWorkshopForGameServer", + "methodname_flat": "SteamAPI_ISteamUGC_BInitWorkshopForGameServer", + "params": [ + { "paramname":"unWorkshopDepotID", "paramtype":"DepotId_t" }, + { "paramname":"pszFolder", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SuspendDownloads", + "methodname_flat": "SteamAPI_ISteamUGC_SuspendDownloads", + "params": [ + { "paramname":"bSuspend", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "callresult": "StartPlaytimeTrackingResult_t", + "methodname": "StartPlaytimeTracking", + "methodname_flat": "SteamAPI_ISteamUGC_StartPlaytimeTracking", + "params": [ + { "paramname":"pvecPublishedFileID", "paramtype":"PublishedFileId_t *" }, + { "paramname":"unNumPublishedFileIDs", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "StopPlaytimeTrackingResult_t", + "methodname": "StopPlaytimeTracking", + "methodname_flat": "SteamAPI_ISteamUGC_StopPlaytimeTracking", + "params": [ + { "paramname":"pvecPublishedFileID", "paramtype":"PublishedFileId_t *" }, + { "paramname":"unNumPublishedFileIDs", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "StopPlaytimeTrackingResult_t", + "methodname": "StopPlaytimeTrackingForAllItems", + "methodname_flat": "SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "AddUGCDependencyResult_t", + "methodname": "AddDependency", + "methodname_flat": "SteamAPI_ISteamUGC_AddDependency", + "params": [ + { "paramname":"nParentPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"nChildPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoveUGCDependencyResult_t", + "methodname": "RemoveDependency", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveDependency", + "params": [ + { "paramname":"nParentPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"nChildPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "AddAppDependencyResult_t", + "methodname": "AddAppDependency", + "methodname_flat": "SteamAPI_ISteamUGC_AddAppDependency", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "RemoveAppDependencyResult_t", + "methodname": "RemoveAppDependency", + "methodname_flat": "SteamAPI_ISteamUGC_RemoveAppDependency", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" }, + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "GetAppDependenciesResult_t", + "methodname": "GetAppDependencies", + "methodname_flat": "SteamAPI_ISteamUGC_GetAppDependencies", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "DeleteItemResult_t", + "methodname": "DeleteItem", + "methodname_flat": "SteamAPI_ISteamUGC_DeleteItem", + "params": [ + { "paramname":"nPublishedFileID", "paramtype":"PublishedFileId_t" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "ShowWorkshopEULA", + "methodname_flat": "SteamAPI_ISteamUGC_ShowWorkshopEULA", + "params": [], + "returntype": "bool" + }, + { + "callresult": "WorkshopEULAStatus_t", + "methodname": "GetWorkshopEULAStatus", + "methodname_flat": "SteamAPI_ISteamUGC_GetWorkshopEULAStatus", + "params": [], + "returntype": "SteamAPICall_t" + } + ], + "version_string": "STEAMUGC_INTERFACE_VERSION017" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamAppList", + "name_flat": "SteamAPI_SteamAppList_v001" + } + ], + "classname": "ISteamAppList", + "fields": [], + "methods": [ + { + "methodname": "GetNumInstalledApps", + "methodname_flat": "SteamAPI_ISteamAppList_GetNumInstalledApps", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetInstalledApps", + "methodname_flat": "SteamAPI_ISteamAppList_GetInstalledApps", + "params": [ + { "paramname":"pvecAppID", "paramtype":"AppId_t *" }, + { "paramname":"unMaxAppIDs", "paramtype":"uint32" } + ], + "returntype": "uint32" + }, + { + "methodname": "GetAppName", + "methodname_flat": "SteamAPI_ISteamAppList_GetAppName", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" }, + { + "out_string": "", + "paramname": "pchName", + "paramtype": "char *" + }, + { "paramname":"cchNameMax", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "GetAppInstallDir", + "methodname_flat": "SteamAPI_ISteamAppList_GetAppInstallDir", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" }, + { "paramname":"pchDirectory", "paramtype":"char *" }, + { "paramname":"cchNameMax", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "GetAppBuildId", + "methodname_flat": "SteamAPI_ISteamAppList_GetAppBuildId", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "int" + } + ], + "version_string": "STEAMAPPLIST_INTERFACE_VERSION001" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamHTMLSurface", + "name_flat": "SteamAPI_SteamHTMLSurface_v005" + } + ], + "classname": "ISteamHTMLSurface", + "enums": [ + { + "enumname": "EHTMLMouseButton", + "fqname": "ISteamHTMLSurface::EHTMLMouseButton", + "values": [ + { "name":"eHTMLMouseButton_Left", "value":"0" }, + { "name":"eHTMLMouseButton_Right", "value":"1" }, + { "name":"eHTMLMouseButton_Middle", "value":"2" } + ] + }, + { + "enumname": "EMouseCursor", + "fqname": "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": "EHTMLKeyModifiers", + "fqname": "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" } + ] + } + ], + "fields": [], + "methods": [ + { + "methodname": "Init", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_Init", + "params": [], + "returntype": "bool" + }, + { + "methodname": "Shutdown", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_Shutdown", + "params": [], + "returntype": "bool" + }, + { + "callresult": "HTML_BrowserReady_t", + "methodname": "CreateBrowser", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_CreateBrowser", + "params": [ + { "paramname":"pchUserAgent", "paramtype":"const char *" }, + { "paramname":"pchUserCSS", "paramtype":"const char *" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "RemoveBrowser", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_RemoveBrowser", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "LoadURL", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_LoadURL", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"pchURL", "paramtype":"const char *" }, + { "paramname":"pchPostData", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetSize", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetSize", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"unWidth", "paramtype":"uint32" }, + { "paramname":"unHeight", "paramtype":"uint32" } + ], + "returntype": "void" + }, + { + "methodname": "StopLoad", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_StopLoad", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "Reload", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_Reload", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "GoBack", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_GoBack", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "GoForward", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_GoForward", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "AddHeader", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_AddHeader", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"pchKey", "paramtype":"const char *" }, + { "paramname":"pchValue", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "ExecuteJavascript", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_ExecuteJavascript", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"pchScript", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "MouseUp", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_MouseUp", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"eMouseButton", "paramtype":"ISteamHTMLSurface::EHTMLMouseButton" } + ], + "returntype": "void" + }, + { + "methodname": "MouseDown", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_MouseDown", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"eMouseButton", "paramtype":"ISteamHTMLSurface::EHTMLMouseButton" } + ], + "returntype": "void" + }, + { + "methodname": "MouseDoubleClick", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_MouseDoubleClick", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"eMouseButton", "paramtype":"ISteamHTMLSurface::EHTMLMouseButton" } + ], + "returntype": "void" + }, + { + "methodname": "MouseMove", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_MouseMove", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"x", "paramtype":"int" }, + { "paramname":"y", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "MouseWheel", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_MouseWheel", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"nDelta", "paramtype":"int32" } + ], + "returntype": "void" + }, + { + "methodname": "KeyDown", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_KeyDown", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"nNativeKeyCode", "paramtype":"uint32" }, + { "paramname":"eHTMLKeyModifiers", "paramtype":"ISteamHTMLSurface::EHTMLKeyModifiers" }, + { "paramname":"bIsSystemKey", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "KeyUp", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_KeyUp", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"nNativeKeyCode", "paramtype":"uint32" }, + { "paramname":"eHTMLKeyModifiers", "paramtype":"ISteamHTMLSurface::EHTMLKeyModifiers" } + ], + "returntype": "void" + }, + { + "methodname": "KeyChar", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_KeyChar", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"cUnicodeChar", "paramtype":"uint32" }, + { "paramname":"eHTMLKeyModifiers", "paramtype":"ISteamHTMLSurface::EHTMLKeyModifiers" } + ], + "returntype": "void" + }, + { + "methodname": "SetHorizontalScroll", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetHorizontalScroll", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"nAbsolutePixelScroll", "paramtype":"uint32" } + ], + "returntype": "void" + }, + { + "methodname": "SetVerticalScroll", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetVerticalScroll", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"nAbsolutePixelScroll", "paramtype":"uint32" } + ], + "returntype": "void" + }, + { + "methodname": "SetKeyFocus", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetKeyFocus", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"bHasKeyFocus", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "ViewSource", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_ViewSource", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "CopyToClipboard", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_CopyToClipboard", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "PasteFromClipboard", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_PasteFromClipboard", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "Find", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_Find", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"pchSearchStr", "paramtype":"const char *" }, + { "paramname":"bCurrentlyInFind", "paramtype":"bool" }, + { "paramname":"bReverse", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "StopFind", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_StopFind", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "GetLinkAtPosition", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_GetLinkAtPosition", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"x", "paramtype":"int" }, + { "paramname":"y", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "SetCookie", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetCookie", + "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" } + ], + "returntype": "void" + }, + { + "methodname": "SetPageScaleFactor", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetPageScaleFactor", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"flZoom", "paramtype":"float" }, + { "paramname":"nPointX", "paramtype":"int" }, + { "paramname":"nPointY", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "SetBackgroundMode", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetBackgroundMode", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"bBackgroundMode", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "SetDPIScalingFactor", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"flDPIScaling", "paramtype":"float" } + ], + "returntype": "void" + }, + { + "methodname": "OpenDeveloperTools", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_OpenDeveloperTools", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" } + ], + "returntype": "void" + }, + { + "methodname": "AllowStartRequest", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_AllowStartRequest", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"bAllowed", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "JSDialogResponse", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_JSDialogResponse", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"bResult", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "FileLoadDialogResponse", + "methodname_flat": "SteamAPI_ISteamHTMLSurface_FileLoadDialogResponse", + "params": [ + { "paramname":"unBrowserHandle", "paramtype":"HHTMLBrowser" }, + { "paramname":"pchSelectedFiles", "paramtype":"const char **" } + ], + "returntype": "void" + } + ], + "version_string": "STEAMHTMLSURFACE_INTERFACE_VERSION_005" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamInventory", + "name_flat": "SteamAPI_SteamInventory_v003" + }, + { + "kind": "gameserver", + "name": "SteamGameServerInventory", + "name_flat": "SteamAPI_SteamGameServerInventory_v003" + } + ], + "classname": "ISteamInventory", + "fields": [], + "methods": [ + { + "methodname": "GetResultStatus", + "methodname_flat": "SteamAPI_ISteamInventory_GetResultStatus", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" } + ], + "returntype": "EResult" + }, + { + "methodname": "GetResultItems", + "methodname_flat": "SteamAPI_ISteamInventory_GetResultItems", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" }, + { + "desc": "Output array", + "out_array_count": "punOutItemsArraySize", + "paramname": "pOutItemsArray", + "paramtype": "SteamItemDetails_t *" + }, + { "paramname":"punOutItemsArraySize", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetResultItemProperty", + "methodname_flat": "SteamAPI_ISteamInventory_GetResultItemProperty", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" }, + { "paramname":"unItemIndex", "paramtype":"uint32" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" }, + { + "out_string_count": "punValueBufferSizeOut", + "paramname": "pchValueBuffer", + "paramtype": "char *" + }, + { "paramname":"punValueBufferSizeOut", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetResultTimestamp", + "methodname_flat": "SteamAPI_ISteamInventory_GetResultTimestamp", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" } + ], + "returntype": "uint32" + }, + { + "methodname": "CheckResultSteamID", + "methodname_flat": "SteamAPI_ISteamInventory_CheckResultSteamID", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" }, + { "paramname":"steamIDExpected", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "DestroyResult", + "methodname_flat": "SteamAPI_ISteamInventory_DestroyResult", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetAllItems", + "methodname_flat": "SteamAPI_ISteamInventory_GetAllItems", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetItemsByID", + "methodname_flat": "SteamAPI_ISteamInventory_GetItemsByID", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { + "array_count": "unCountInstanceIDs", + "paramname": "pInstanceIDs", + "paramtype": "const SteamItemInstanceID_t *" + }, + { "paramname":"unCountInstanceIDs", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "SerializeResult", + "methodname_flat": "SteamAPI_ISteamInventory_SerializeResult", + "params": [ + { "paramname":"resultHandle", "paramtype":"SteamInventoryResult_t" }, + { + "out_buffer_count": "punOutBufferSize", + "paramname": "pOutBuffer", + "paramtype": "void *" + }, + { "paramname":"punOutBufferSize", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "DeserializeResult", + "methodname_flat": "SteamAPI_ISteamInventory_DeserializeResult", + "params": [ + { "paramname":"pOutResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { + "buffer_count": "punOutBufferSize", + "paramname": "pBuffer", + "paramtype": "const void *" + }, + { "paramname":"unBufferSize", "paramtype":"uint32" }, + { "paramname":"bRESERVED_MUST_BE_FALSE", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "GenerateItems", + "methodname_flat": "SteamAPI_ISteamInventory_GenerateItems", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { + "array_count": "unArrayLength", + "paramname": "pArrayItemDefs", + "paramtype": "const SteamItemDef_t *" + }, + { + "array_count": "unArrayLength", + "paramname": "punArrayQuantity", + "paramtype": "const uint32 *" + }, + { "paramname":"unArrayLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GrantPromoItems", + "methodname_flat": "SteamAPI_ISteamInventory_GrantPromoItems", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "AddPromoItem", + "methodname_flat": "SteamAPI_ISteamInventory_AddPromoItem", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { "paramname":"itemDef", "paramtype":"SteamItemDef_t" } + ], + "returntype": "bool" + }, + { + "methodname": "AddPromoItems", + "methodname_flat": "SteamAPI_ISteamInventory_AddPromoItems", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { + "array_count": "unArrayLength", + "paramname": "pArrayItemDefs", + "paramtype": "const SteamItemDef_t *" + }, + { "paramname":"unArrayLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "ConsumeItem", + "methodname_flat": "SteamAPI_ISteamInventory_ConsumeItem", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { "paramname":"itemConsume", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"unQuantity", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "ExchangeItems", + "methodname_flat": "SteamAPI_ISteamInventory_ExchangeItems", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { + "array_count": "unArrayGenerateLength", + "paramname": "pArrayGenerate", + "paramtype": "const SteamItemDef_t *" + }, + { + "array_count": "unArrayGenerateLength", + "paramname": "punArrayGenerateQuantity", + "paramtype": "const uint32 *" + }, + { "paramname":"unArrayGenerateLength", "paramtype":"uint32" }, + { + "array_count": "unArrayDestroyLength", + "paramname": "pArrayDestroy", + "paramtype": "const SteamItemInstanceID_t *" + }, + { + "array_count": "unArrayDestroyLength", + "paramname": "punArrayDestroyQuantity", + "paramtype": "const uint32 *" + }, + { "paramname":"unArrayDestroyLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "TransferItemQuantity", + "methodname_flat": "SteamAPI_ISteamInventory_TransferItemQuantity", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { "paramname":"itemIdSource", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"unQuantity", "paramtype":"uint32" }, + { "paramname":"itemIdDest", "paramtype":"SteamItemInstanceID_t" } + ], + "returntype": "bool" + }, + { + "methodname": "SendItemDropHeartbeat", + "methodname_flat": "SteamAPI_ISteamInventory_SendItemDropHeartbeat", + "params": [], + "returntype": "void" + }, + { + "methodname": "TriggerItemDrop", + "methodname_flat": "SteamAPI_ISteamInventory_TriggerItemDrop", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { "paramname":"dropListDefinition", "paramtype":"SteamItemDef_t" } + ], + "returntype": "bool" + }, + { + "methodname": "TradeItems", + "methodname_flat": "SteamAPI_ISteamInventory_TradeItems", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { "paramname":"steamIDTradePartner", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { + "array_count": "nArrayGiveLength", + "paramname": "pArrayGive", + "paramtype": "const SteamItemInstanceID_t *" + }, + { + "array_count": "nArrayGiveLength", + "paramname": "pArrayGiveQuantity", + "paramtype": "const uint32 *" + }, + { "paramname":"nArrayGiveLength", "paramtype":"uint32" }, + { + "array_count": "nArrayGetLength", + "paramname": "pArrayGet", + "paramtype": "const SteamItemInstanceID_t *" + }, + { + "array_count": "nArrayGetLength", + "paramname": "pArrayGetQuantity", + "paramtype": "const uint32 *" + }, + { "paramname":"nArrayGetLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "LoadItemDefinitions", + "methodname_flat": "SteamAPI_ISteamInventory_LoadItemDefinitions", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetItemDefinitionIDs", + "methodname_flat": "SteamAPI_ISteamInventory_GetItemDefinitionIDs", + "params": [ + { + "desc": "List of item definition IDs", + "out_array_count": "punItemDefIDsArraySize", + "paramname": "pItemDefIDs", + "paramtype": "SteamItemDef_t *" + }, + { + "desc": "Size of array is passed in and actual size used is returned in this param", + "paramname": "punItemDefIDsArraySize", + "paramtype": "uint32 *" + } + ], + "returntype": "bool" + }, + { + "methodname": "GetItemDefinitionProperty", + "methodname_flat": "SteamAPI_ISteamInventory_GetItemDefinitionProperty", + "params": [ + { "paramname":"iDefinition", "paramtype":"SteamItemDef_t" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" }, + { + "out_string_count": "punValueBufferSizeOut", + "paramname": "pchValueBuffer", + "paramtype": "char *" + }, + { "paramname":"punValueBufferSizeOut", "paramtype":"uint32 *" } + ], + "returntype": "bool" + }, + { + "callresult": "SteamInventoryEligiblePromoItemDefIDs_t", + "methodname": "RequestEligiblePromoItemDefinitionsIDs", + "methodname_flat": "SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetEligiblePromoItemDefinitionIDs", + "methodname_flat": "SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { + "desc": "List of item definition IDs", + "out_array_count": "punItemDefIDsArraySize", + "paramname": "pItemDefIDs", + "paramtype": "SteamItemDef_t *" + }, + { + "desc": "Size of array is passed in and actual size used is returned in this param", + "paramname": "punItemDefIDsArraySize", + "paramtype": "uint32 *" + } + ], + "returntype": "bool" + }, + { + "callresult": "SteamInventoryStartPurchaseResult_t", + "methodname": "StartPurchase", + "methodname_flat": "SteamAPI_ISteamInventory_StartPurchase", + "params": [ + { + "array_count": "unArrayLength", + "paramname": "pArrayItemDefs", + "paramtype": "const SteamItemDef_t *" + }, + { + "array_count": "unArrayLength", + "paramname": "punArrayQuantity", + "paramtype": "const uint32 *" + }, + { "paramname":"unArrayLength", "paramtype":"uint32" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "SteamInventoryRequestPricesResult_t", + "methodname": "RequestPrices", + "methodname_flat": "SteamAPI_ISteamInventory_RequestPrices", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetNumItemsWithPrices", + "methodname_flat": "SteamAPI_ISteamInventory_GetNumItemsWithPrices", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetItemsWithPrices", + "methodname_flat": "SteamAPI_ISteamInventory_GetItemsWithPrices", + "params": [ + { + "array_count": "unArrayLength", + "desc": "Items with prices", + "out_array_count": "pArrayItemDefs", + "paramname": "pArrayItemDefs", + "paramtype": "SteamItemDef_t *" + }, + { + "array_count": "unArrayLength", + "desc": "List of prices for the given item defs", + "out_array_count": "pPrices", + "paramname": "pCurrentPrices", + "paramtype": "uint64 *" + }, + { + "array_count": "unArrayLength", + "desc": "List of prices for the given item defs", + "out_array_count": "pPrices", + "paramname": "pBasePrices", + "paramtype": "uint64 *" + }, + { "paramname":"unArrayLength", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetItemPrice", + "methodname_flat": "SteamAPI_ISteamInventory_GetItemPrice", + "params": [ + { "paramname":"iDefinition", "paramtype":"SteamItemDef_t" }, + { "paramname":"pCurrentPrice", "paramtype":"uint64 *" }, + { "paramname":"pBasePrice", "paramtype":"uint64 *" } + ], + "returntype": "bool" + }, + { + "methodname": "StartUpdateProperties", + "methodname_flat": "SteamAPI_ISteamInventory_StartUpdateProperties", + "params": [], + "returntype": "SteamInventoryUpdateHandle_t" + }, + { + "methodname": "RemoveProperty", + "methodname_flat": "SteamAPI_ISteamInventory_RemoveProperty", + "params": [ + { "paramname":"handle", "paramtype":"SteamInventoryUpdateHandle_t" }, + { "paramname":"nItemID", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetProperty", + "methodname_flat": "SteamAPI_ISteamInventory_SetPropertyString", + "params": [ + { "paramname":"handle", "paramtype":"SteamInventoryUpdateHandle_t" }, + { "paramname":"nItemID", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" }, + { "paramname":"pchPropertyValue", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetProperty", + "methodname_flat": "SteamAPI_ISteamInventory_SetPropertyBool", + "params": [ + { "paramname":"handle", "paramtype":"SteamInventoryUpdateHandle_t" }, + { "paramname":"nItemID", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" }, + { "paramname":"bValue", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "SetProperty", + "methodname_flat": "SteamAPI_ISteamInventory_SetPropertyInt64", + "params": [ + { "paramname":"handle", "paramtype":"SteamInventoryUpdateHandle_t" }, + { "paramname":"nItemID", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" }, + { "paramname":"nValue", "paramtype":"int64" } + ], + "returntype": "bool" + }, + { + "methodname": "SetProperty", + "methodname_flat": "SteamAPI_ISteamInventory_SetPropertyFloat", + "params": [ + { "paramname":"handle", "paramtype":"SteamInventoryUpdateHandle_t" }, + { "paramname":"nItemID", "paramtype":"SteamItemInstanceID_t" }, + { "paramname":"pchPropertyName", "paramtype":"const char *" }, + { "paramname":"flValue", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "SubmitUpdateProperties", + "methodname_flat": "SteamAPI_ISteamInventory_SubmitUpdateProperties", + "params": [ + { "paramname":"handle", "paramtype":"SteamInventoryUpdateHandle_t" }, + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "InspectItem", + "methodname_flat": "SteamAPI_ISteamInventory_InspectItem", + "params": [ + { "paramname":"pResultHandle", "paramtype":"SteamInventoryResult_t *" }, + { "paramname":"pchItemToken", "paramtype":"const char *" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMINVENTORY_INTERFACE_V003" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamVideo", + "name_flat": "SteamAPI_SteamVideo_v002" + } + ], + "classname": "ISteamVideo", + "fields": [], + "methods": [ + { + "methodname": "GetVideoURL", + "methodname_flat": "SteamAPI_ISteamVideo_GetVideoURL", + "params": [ + { "paramname":"unVideoAppID", "paramtype":"AppId_t" } + ], + "returntype": "void" + }, + { + "methodname": "IsBroadcasting", + "methodname_flat": "SteamAPI_ISteamVideo_IsBroadcasting", + "params": [ + { "paramname":"pnNumViewers", "paramtype":"int *" } + ], + "returntype": "bool" + }, + { + "callback": "GetOPFSettingsResult_t", + "methodname": "GetOPFSettings", + "methodname_flat": "SteamAPI_ISteamVideo_GetOPFSettings", + "params": [ + { "paramname":"unVideoAppID", "paramtype":"AppId_t" } + ], + "returntype": "void" + }, + { + "methodname": "GetOPFStringForApp", + "methodname_flat": "SteamAPI_ISteamVideo_GetOPFStringForApp", + "params": [ + { "paramname":"unVideoAppID", "paramtype":"AppId_t" }, + { "paramname":"pchBuffer", "paramtype":"char *" }, + { "paramname":"pnBufferSize", "paramtype":"int32 *" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMVIDEO_INTERFACE_V002" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamParentalSettings", + "name_flat": "SteamAPI_SteamParentalSettings_v001" + } + ], + "classname": "ISteamParentalSettings", + "fields": [], + "methods": [ + { + "methodname": "BIsParentalLockEnabled", + "methodname_flat": "SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsParentalLockLocked", + "methodname_flat": "SteamAPI_ISteamParentalSettings_BIsParentalLockLocked", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BIsAppBlocked", + "methodname_flat": "SteamAPI_ISteamParentalSettings_BIsAppBlocked", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "bool" + }, + { + "methodname": "BIsAppInBlockList", + "methodname_flat": "SteamAPI_ISteamParentalSettings_BIsAppInBlockList", + "params": [ + { "paramname":"nAppID", "paramtype":"AppId_t" } + ], + "returntype": "bool" + }, + { + "methodname": "BIsFeatureBlocked", + "methodname_flat": "SteamAPI_ISteamParentalSettings_BIsFeatureBlocked", + "params": [ + { "paramname":"eFeature", "paramtype":"EParentalFeature" } + ], + "returntype": "bool" + }, + { + "methodname": "BIsFeatureInBlockList", + "methodname_flat": "SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList", + "params": [ + { "paramname":"eFeature", "paramtype":"EParentalFeature" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMPARENTALSETTINGS_INTERFACE_VERSION001" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamRemotePlay", + "name_flat": "SteamAPI_SteamRemotePlay_v001" + } + ], + "classname": "ISteamRemotePlay", + "fields": [], + "methods": [ + { + "methodname": "GetSessionCount", + "methodname_flat": "SteamAPI_ISteamRemotePlay_GetSessionCount", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetSessionID", + "methodname_flat": "SteamAPI_ISteamRemotePlay_GetSessionID", + "params": [ + { "paramname":"iSessionIndex", "paramtype":"int" } + ], + "returntype": "RemotePlaySessionID_t" + }, + { + "methodname": "GetSessionSteamID", + "methodname_flat": "SteamAPI_ISteamRemotePlay_GetSessionSteamID", + "params": [ + { "paramname":"unSessionID", "paramtype":"RemotePlaySessionID_t" } + ], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "GetSessionClientName", + "methodname_flat": "SteamAPI_ISteamRemotePlay_GetSessionClientName", + "params": [ + { "paramname":"unSessionID", "paramtype":"RemotePlaySessionID_t" } + ], + "returntype": "const char *" + }, + { + "methodname": "GetSessionClientFormFactor", + "methodname_flat": "SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor", + "params": [ + { "paramname":"unSessionID", "paramtype":"RemotePlaySessionID_t" } + ], + "returntype": "ESteamDeviceFormFactor" + }, + { + "methodname": "BGetSessionClientResolution", + "methodname_flat": "SteamAPI_ISteamRemotePlay_BGetSessionClientResolution", + "params": [ + { "paramname":"unSessionID", "paramtype":"RemotePlaySessionID_t" }, + { "paramname":"pnResolutionX", "paramtype":"int *" }, + { "paramname":"pnResolutionY", "paramtype":"int *" } + ], + "returntype": "bool" + }, + { + "methodname": "BSendRemotePlayTogetherInvite", + "methodname_flat": "SteamAPI_ISteamRemotePlay_BSendRemotePlayTogetherInvite", + "params": [ + { "paramname":"steamIDFriend", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + } + ], + "version_string": "STEAMREMOTEPLAY_INTERFACE_VERSION001" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamNetworkingMessages_SteamAPI", + "name_flat": "SteamAPI_SteamNetworkingMessages_SteamAPI_v002" + }, + { + "kind": "gameserver", + "name": "SteamGameServerNetworkingMessages_SteamAPI", + "name_flat": "SteamAPI_SteamGameServerNetworkingMessages_SteamAPI_v002" + } + ], + "classname": "ISteamNetworkingMessages", + "fields": [], + "methods": [ + { + "methodname": "SendMessageToUser", + "methodname_flat": "SteamAPI_ISteamNetworkingMessages_SendMessageToUser", + "params": [ + { "paramname":"identityRemote", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"pubData", "paramtype":"const void *" }, + { "paramname":"cubData", "paramtype":"uint32" }, + { "paramname":"nSendFlags", "paramtype":"int" }, + { "paramname":"nRemoteChannel", "paramtype":"int" } + ], + "returntype": "EResult" + }, + { + "methodname": "ReceiveMessagesOnChannel", + "methodname_flat": "SteamAPI_ISteamNetworkingMessages_ReceiveMessagesOnChannel", + "params": [ + { "paramname":"nLocalChannel", "paramtype":"int" }, + { "paramname":"ppOutMessages", "paramtype":"SteamNetworkingMessage_t **" }, + { "paramname":"nMaxMessages", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "AcceptSessionWithUser", + "methodname_flat": "SteamAPI_ISteamNetworkingMessages_AcceptSessionWithUser", + "params": [ + { "paramname":"identityRemote", "paramtype":"const SteamNetworkingIdentity &" } + ], + "returntype": "bool" + }, + { + "methodname": "CloseSessionWithUser", + "methodname_flat": "SteamAPI_ISteamNetworkingMessages_CloseSessionWithUser", + "params": [ + { "paramname":"identityRemote", "paramtype":"const SteamNetworkingIdentity &" } + ], + "returntype": "bool" + }, + { + "methodname": "CloseChannelWithUser", + "methodname_flat": "SteamAPI_ISteamNetworkingMessages_CloseChannelWithUser", + "params": [ + { "paramname":"identityRemote", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"nLocalChannel", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetSessionConnectionInfo", + "methodname_flat": "SteamAPI_ISteamNetworkingMessages_GetSessionConnectionInfo", + "params": [ + { "paramname":"identityRemote", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"pConnectionInfo", "paramtype":"SteamNetConnectionInfo_t *" }, + { "paramname":"pQuickStatus", "paramtype":"SteamNetConnectionRealTimeStatus_t *" } + ], + "returntype": "ESteamNetworkingConnectionState" + } + ], + "version_string": "SteamNetworkingMessages002" + }, + { + "accessors": [ + { + "kind": "user", + "name": "SteamNetworkingSockets_SteamAPI", + "name_flat": "SteamAPI_SteamNetworkingSockets_SteamAPI_v012" + }, + { + "kind": "gameserver", + "name": "SteamGameServerNetworkingSockets_SteamAPI", + "name_flat": "SteamAPI_SteamGameServerNetworkingSockets_SteamAPI_v012" + } + ], + "classname": "ISteamNetworkingSockets", + "fields": [], + "methods": [ + { + "methodname": "CreateListenSocketIP", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP", + "params": [ + { "paramname":"localAddress", "paramtype":"const SteamNetworkingIPAddr &" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamListenSocket" + }, + { + "methodname": "ConnectByIPAddress", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress", + "params": [ + { "paramname":"address", "paramtype":"const SteamNetworkingIPAddr &" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamNetConnection" + }, + { + "methodname": "CreateListenSocketP2P", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2P", + "params": [ + { "paramname":"nLocalVirtualPort", "paramtype":"int" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamListenSocket" + }, + { + "methodname": "ConnectP2P", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ConnectP2P", + "params": [ + { "paramname":"identityRemote", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"nRemoteVirtualPort", "paramtype":"int" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamNetConnection" + }, + { + "methodname": "AcceptConnection", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_AcceptConnection", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" } + ], + "returntype": "EResult" + }, + { + "methodname": "CloseConnection", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CloseConnection", + "params": [ + { "paramname":"hPeer", "paramtype":"HSteamNetConnection" }, + { "paramname":"nReason", "paramtype":"int" }, + { "paramname":"pszDebug", "paramtype":"const char *" }, + { "paramname":"bEnableLinger", "paramtype":"bool" } + ], + "returntype": "bool" + }, + { + "methodname": "CloseListenSocket", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CloseListenSocket", + "params": [ + { "paramname":"hSocket", "paramtype":"HSteamListenSocket" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConnectionUserData", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_SetConnectionUserData", + "params": [ + { "paramname":"hPeer", "paramtype":"HSteamNetConnection" }, + { "paramname":"nUserData", "paramtype":"int64" } + ], + "returntype": "bool" + }, + { + "methodname": "GetConnectionUserData", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetConnectionUserData", + "params": [ + { "paramname":"hPeer", "paramtype":"HSteamNetConnection" } + ], + "returntype": "int64" + }, + { + "methodname": "SetConnectionName", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_SetConnectionName", + "params": [ + { "paramname":"hPeer", "paramtype":"HSteamNetConnection" }, + { "paramname":"pszName", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "GetConnectionName", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetConnectionName", + "params": [ + { "paramname":"hPeer", "paramtype":"HSteamNetConnection" }, + { "paramname":"pszName", "paramtype":"char *" }, + { "paramname":"nMaxLen", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "SendMessageToConnection", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_SendMessageToConnection", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"pData", "paramtype":"const void *" }, + { "paramname":"cbData", "paramtype":"uint32" }, + { "paramname":"nSendFlags", "paramtype":"int" }, + { "paramname":"pOutMessageNumber", "paramtype":"int64 *" } + ], + "returntype": "EResult" + }, + { + "methodname": "SendMessages", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_SendMessages", + "params": [ + { "paramname":"nMessages", "paramtype":"int" }, + { "paramname":"pMessages", "paramtype":"SteamNetworkingMessage_t *const *" }, + { "paramname":"pOutMessageNumberOrResult", "paramtype":"int64 *" } + ], + "returntype": "void" + }, + { + "methodname": "FlushMessagesOnConnection", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_FlushMessagesOnConnection", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" } + ], + "returntype": "EResult" + }, + { + "methodname": "ReceiveMessagesOnConnection", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"ppOutMessages", "paramtype":"SteamNetworkingMessage_t **" }, + { "paramname":"nMaxMessages", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "GetConnectionInfo", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetConnectionInfo", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"pInfo", "paramtype":"SteamNetConnectionInfo_t *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetConnectionRealTimeStatus", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetConnectionRealTimeStatus", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"pStatus", "paramtype":"SteamNetConnectionRealTimeStatus_t *" }, + { "paramname":"nLanes", "paramtype":"int" }, + { "paramname":"pLanes", "paramtype":"SteamNetConnectionRealTimeLaneStatus_t *" } + ], + "returntype": "EResult" + }, + { + "methodname": "GetDetailedConnectionStatus", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetDetailedConnectionStatus", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"pszBuf", "paramtype":"char *" }, + { "paramname":"cbBuf", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "GetListenSocketAddress", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetListenSocketAddress", + "params": [ + { "paramname":"hSocket", "paramtype":"HSteamListenSocket" }, + { "paramname":"address", "paramtype":"SteamNetworkingIPAddr *" } + ], + "returntype": "bool" + }, + { + "methodname": "CreateSocketPair", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreateSocketPair", + "params": [ + { "paramname":"pOutConnection1", "paramtype":"HSteamNetConnection *" }, + { "paramname":"pOutConnection2", "paramtype":"HSteamNetConnection *" }, + { "paramname":"bUseNetworkLoopback", "paramtype":"bool" }, + { "paramname":"pIdentity1", "paramtype":"const SteamNetworkingIdentity *" }, + { "paramname":"pIdentity2", "paramtype":"const SteamNetworkingIdentity *" } + ], + "returntype": "bool" + }, + { + "methodname": "ConfigureConnectionLanes", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ConfigureConnectionLanes", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"nNumLanes", "paramtype":"int" }, + { "paramname":"pLanePriorities", "paramtype":"const int *" }, + { "paramname":"pLaneWeights", "paramtype":"const uint16 *" } + ], + "returntype": "EResult" + }, + { + "methodname": "GetIdentity", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetIdentity", + "params": [ + { "paramname":"pIdentity", "paramtype":"SteamNetworkingIdentity *" } + ], + "returntype": "bool" + }, + { + "methodname": "InitAuthentication", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_InitAuthentication", + "params": [], + "returntype": "ESteamNetworkingAvailability" + }, + { + "methodname": "GetAuthenticationStatus", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetAuthenticationStatus", + "params": [ + { "paramname":"pDetails", "paramtype":"SteamNetAuthenticationStatus_t *" } + ], + "returntype": "ESteamNetworkingAvailability" + }, + { + "methodname": "CreatePollGroup", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreatePollGroup", + "params": [], + "returntype": "HSteamNetPollGroup" + }, + { + "methodname": "DestroyPollGroup", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_DestroyPollGroup", + "params": [ + { "paramname":"hPollGroup", "paramtype":"HSteamNetPollGroup" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConnectionPollGroup", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"hPollGroup", "paramtype":"HSteamNetPollGroup" } + ], + "returntype": "bool" + }, + { + "methodname": "ReceiveMessagesOnPollGroup", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup", + "params": [ + { "paramname":"hPollGroup", "paramtype":"HSteamNetPollGroup" }, + { "paramname":"ppOutMessages", "paramtype":"SteamNetworkingMessage_t **" }, + { "paramname":"nMaxMessages", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "ReceivedRelayAuthTicket", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ReceivedRelayAuthTicket", + "params": [ + { "paramname":"pvTicket", "paramtype":"const void *" }, + { "paramname":"cbTicket", "paramtype":"int" }, + { "paramname":"pOutParsedTicket", "paramtype":"SteamDatagramRelayAuthTicket *" } + ], + "returntype": "bool" + }, + { + "methodname": "FindRelayAuthTicketForServer", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_FindRelayAuthTicketForServer", + "params": [ + { "paramname":"identityGameServer", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"nRemoteVirtualPort", "paramtype":"int" }, + { "paramname":"pOutParsedTicket", "paramtype":"SteamDatagramRelayAuthTicket *" } + ], + "returntype": "int" + }, + { + "methodname": "ConnectToHostedDedicatedServer", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ConnectToHostedDedicatedServer", + "params": [ + { "paramname":"identityTarget", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"nRemoteVirtualPort", "paramtype":"int" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamNetConnection" + }, + { + "methodname": "GetHostedDedicatedServerPort", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPort", + "params": [], + "returntype": "uint16" + }, + { + "methodname": "GetHostedDedicatedServerPOPID", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPOPID", + "params": [], + "returntype": "SteamNetworkingPOPID" + }, + { + "methodname": "GetHostedDedicatedServerAddress", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerAddress", + "params": [ + { "paramname":"pRouting", "paramtype":"SteamDatagramHostedAddress *" } + ], + "returntype": "EResult" + }, + { + "methodname": "CreateHostedDedicatedServerListenSocket", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreateHostedDedicatedServerListenSocket", + "params": [ + { "paramname":"nLocalVirtualPort", "paramtype":"int" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamListenSocket" + }, + { + "methodname": "GetGameCoordinatorServerLogin", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetGameCoordinatorServerLogin", + "params": [ + { "paramname":"pLoginInfo", "paramtype":"SteamDatagramGameCoordinatorServerLogin *" }, + { "paramname":"pcbSignedBlob", "paramtype":"int *" }, + { "paramname":"pBlob", "paramtype":"void *" } + ], + "returntype": "EResult" + }, + { + "methodname": "ConnectP2PCustomSignaling", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling", + "params": [ + { "paramname":"pSignaling", "paramtype":"ISteamNetworkingConnectionSignaling *" }, + { "paramname":"pPeerIdentity", "paramtype":"const SteamNetworkingIdentity *" }, + { "paramname":"nRemoteVirtualPort", "paramtype":"int" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamNetConnection" + }, + { + "methodname": "ReceivedP2PCustomSignal", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ReceivedP2PCustomSignal", + "params": [ + { "paramname":"pMsg", "paramtype":"const void *" }, + { "paramname":"cbMsg", "paramtype":"int" }, + { "paramname":"pContext", "paramtype":"ISteamNetworkingSignalingRecvContext *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetCertificateRequest", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetCertificateRequest", + "params": [ + { "paramname":"pcbBlob", "paramtype":"int *" }, + { "paramname":"pBlob", "paramtype":"void *" }, + { "paramname":"errMsg", "paramtype":"SteamNetworkingErrMsg &" } + ], + "returntype": "bool" + }, + { + "methodname": "SetCertificate", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_SetCertificate", + "params": [ + { "paramname":"pCertificate", "paramtype":"const void *" }, + { "paramname":"cbCertificate", "paramtype":"int" }, + { "paramname":"errMsg", "paramtype":"SteamNetworkingErrMsg &" } + ], + "returntype": "bool" + }, + { + "methodname": "ResetIdentity", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_ResetIdentity", + "params": [ + { "paramname":"pIdentity", "paramtype":"const SteamNetworkingIdentity *" } + ], + "returntype": "void" + }, + { + "methodname": "RunCallbacks", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_RunCallbacks", + "params": [], + "returntype": "void" + }, + { + "methodname": "BeginAsyncRequestFakeIP", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_BeginAsyncRequestFakeIP", + "params": [ + { "paramname":"nNumPorts", "paramtype":"int" } + ], + "returntype": "bool" + }, + { + "methodname": "GetFakeIP", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetFakeIP", + "params": [ + { "paramname":"idxFirstPort", "paramtype":"int" }, + { "paramname":"pInfo", "paramtype":"SteamNetworkingFakeIPResult_t *" } + ], + "returntype": "void" + }, + { + "methodname": "CreateListenSocketP2PFakeIP", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2PFakeIP", + "params": [ + { "paramname":"idxFakePort", "paramtype":"int" }, + { "paramname":"nOptions", "paramtype":"int" }, + { "paramname":"pOptions", "paramtype":"const SteamNetworkingConfigValue_t *" } + ], + "returntype": "HSteamListenSocket" + }, + { + "methodname": "GetRemoteFakeIPForConnection", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_GetRemoteFakeIPForConnection", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"pOutAddr", "paramtype":"SteamNetworkingIPAddr *" } + ], + "returntype": "EResult" + }, + { + "methodname": "CreateFakeUDPPort", + "methodname_flat": "SteamAPI_ISteamNetworkingSockets_CreateFakeUDPPort", + "params": [ + { "paramname":"idxFakeServerPort", "paramtype":"int" } + ], + "returntype": "ISteamNetworkingFakeUDPPort *" + } + ], + "version_string": "SteamNetworkingSockets012" + }, + { + "accessors": [ + { + "kind": "global", + "name": "SteamNetworkingUtils_SteamAPI", + "name_flat": "SteamAPI_SteamNetworkingUtils_SteamAPI_v004" + } + ], + "classname": "ISteamNetworkingUtils", + "fields": [], + "methods": [ + { + "methodname": "AllocateMessage", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_AllocateMessage", + "params": [ + { "paramname":"cbAllocateBuffer", "paramtype":"int" } + ], + "returntype": "SteamNetworkingMessage_t *" + }, + { + "methodname": "InitRelayNetworkAccess", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_InitRelayNetworkAccess", + "params": [], + "returntype": "void" + }, + { + "methodname": "GetRelayNetworkStatus", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetRelayNetworkStatus", + "params": [ + { "paramname":"pDetails", "paramtype":"SteamRelayNetworkStatus_t *" } + ], + "returntype": "ESteamNetworkingAvailability" + }, + { + "methodname": "GetLocalPingLocation", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetLocalPingLocation", + "params": [ + { "paramname":"result", "paramtype":"SteamNetworkPingLocation_t &" } + ], + "returntype": "float" + }, + { + "methodname": "EstimatePingTimeBetweenTwoLocations", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_EstimatePingTimeBetweenTwoLocations", + "params": [ + { "paramname":"location1", "paramtype":"const SteamNetworkPingLocation_t &" }, + { "paramname":"location2", "paramtype":"const SteamNetworkPingLocation_t &" } + ], + "returntype": "int" + }, + { + "methodname": "EstimatePingTimeFromLocalHost", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_EstimatePingTimeFromLocalHost", + "params": [ + { "paramname":"remoteLocation", "paramtype":"const SteamNetworkPingLocation_t &" } + ], + "returntype": "int" + }, + { + "methodname": "ConvertPingLocationToString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_ConvertPingLocationToString", + "params": [ + { "paramname":"location", "paramtype":"const SteamNetworkPingLocation_t &" }, + { "paramname":"pszBuf", "paramtype":"char *" }, + { "paramname":"cchBufSize", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "ParsePingLocationString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_ParsePingLocationString", + "params": [ + { "paramname":"pszString", "paramtype":"const char *" }, + { "paramname":"result", "paramtype":"SteamNetworkPingLocation_t &" } + ], + "returntype": "bool" + }, + { + "methodname": "CheckPingDataUpToDate", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_CheckPingDataUpToDate", + "params": [ + { "paramname":"flMaxAgeSeconds", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "GetPingToDataCenter", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetPingToDataCenter", + "params": [ + { "paramname":"popID", "paramtype":"SteamNetworkingPOPID" }, + { "paramname":"pViaRelayPoP", "paramtype":"SteamNetworkingPOPID *" } + ], + "returntype": "int" + }, + { + "methodname": "GetDirectPingToPOP", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetDirectPingToPOP", + "params": [ + { "paramname":"popID", "paramtype":"SteamNetworkingPOPID" } + ], + "returntype": "int" + }, + { + "methodname": "GetPOPCount", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetPOPCount", + "params": [], + "returntype": "int" + }, + { + "methodname": "GetPOPList", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetPOPList", + "params": [ + { "paramname":"list", "paramtype":"SteamNetworkingPOPID *" }, + { "paramname":"nListSz", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "GetLocalTimestamp", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetLocalTimestamp", + "params": [], + "returntype": "SteamNetworkingMicroseconds" + }, + { + "methodname": "SetDebugOutputFunction", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction", + "params": [ + { "paramname":"eDetailLevel", "paramtype":"ESteamNetworkingSocketsDebugOutputType" }, + { "paramname":"pfnFunc", "paramtype":"FSteamNetworkingSocketsDebugOutput" } + ], + "returntype": "void" + }, + { + "methodname": "IsFakeIPv4", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_IsFakeIPv4", + "params": [ + { "paramname":"nIPv4", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetIPv4FakeIPType", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetIPv4FakeIPType", + "params": [ + { "paramname":"nIPv4", "paramtype":"uint32" } + ], + "returntype": "ESteamNetworkingFakeIPType" + }, + { + "methodname": "GetRealIdentityForFakeIP", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetRealIdentityForFakeIP", + "params": [ + { "paramname":"fakeIP", "paramtype":"const SteamNetworkingIPAddr &" }, + { "paramname":"pOutRealIdentity", "paramtype":"SteamNetworkingIdentity *" } + ], + "returntype": "EResult" + }, + { + "methodname": "SetGlobalConfigValueInt32", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueInt32", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"int32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalConfigValueFloat", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueFloat", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalConfigValueString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueString", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalConfigValuePtr", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValuePtr", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"void *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConnectionConfigValueInt32", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueInt32", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"int32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConnectionConfigValueFloat", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueFloat", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConnectionConfigValueString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueString", + "params": [ + { "paramname":"hConn", "paramtype":"HSteamNetConnection" }, + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"val", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalCallback_SteamNetConnectionStatusChanged", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged", + "params": [ + { "paramname":"fnCallback", "paramtype":"FnSteamNetConnectionStatusChanged" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalCallback_SteamNetAuthenticationStatusChanged", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetAuthenticationStatusChanged", + "params": [ + { "paramname":"fnCallback", "paramtype":"FnSteamNetAuthenticationStatusChanged" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalCallback_SteamRelayNetworkStatusChanged", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamRelayNetworkStatusChanged", + "params": [ + { "paramname":"fnCallback", "paramtype":"FnSteamRelayNetworkStatusChanged" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalCallback_FakeIPResult", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_FakeIPResult", + "params": [ + { "paramname":"fnCallback", "paramtype":"FnSteamNetworkingFakeIPResult" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalCallback_MessagesSessionRequest", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionRequest", + "params": [ + { "paramname":"fnCallback", "paramtype":"FnSteamNetworkingMessagesSessionRequest" } + ], + "returntype": "bool" + }, + { + "methodname": "SetGlobalCallback_MessagesSessionFailed", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionFailed", + "params": [ + { "paramname":"fnCallback", "paramtype":"FnSteamNetworkingMessagesSessionFailed" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConfigValue", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetConfigValue", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"eScopeType", "paramtype":"ESteamNetworkingConfigScope" }, + { "paramname":"scopeObj", "paramtype":"intptr_t" }, + { "paramname":"eDataType", "paramtype":"ESteamNetworkingConfigDataType" }, + { "paramname":"pArg", "paramtype":"const void *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetConfigValueStruct", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SetConfigValueStruct", + "params": [ + { "paramname":"opt", "paramtype":"const SteamNetworkingConfigValue_t &" }, + { "paramname":"eScopeType", "paramtype":"ESteamNetworkingConfigScope" }, + { "paramname":"scopeObj", "paramtype":"intptr_t" } + ], + "returntype": "bool" + }, + { + "methodname": "GetConfigValue", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetConfigValue", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"eScopeType", "paramtype":"ESteamNetworkingConfigScope" }, + { "paramname":"scopeObj", "paramtype":"intptr_t" }, + { "paramname":"pOutDataType", "paramtype":"ESteamNetworkingConfigDataType *" }, + { "paramname":"pResult", "paramtype":"void *" }, + { "paramname":"cbResult", "paramtype":"size_t *" } + ], + "returntype": "ESteamNetworkingGetConfigValueResult" + }, + { + "methodname": "GetConfigValueInfo", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_GetConfigValueInfo", + "params": [ + { "paramname":"eValue", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"pOutDataType", "paramtype":"ESteamNetworkingConfigDataType *" }, + { "paramname":"pOutScope", "paramtype":"ESteamNetworkingConfigScope *" } + ], + "returntype": "const char *" + }, + { + "methodname": "IterateGenericEditableConfigValues", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_IterateGenericEditableConfigValues", + "params": [ + { "paramname":"eCurrent", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"bEnumerateDevVars", "paramtype":"bool" } + ], + "returntype": "ESteamNetworkingConfigValue" + }, + { + "methodname": "SteamNetworkingIPAddr_ToString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_ToString", + "params": [ + { "paramname":"addr", "paramtype":"const SteamNetworkingIPAddr &" }, + { "paramname":"buf", "paramtype":"char *" }, + { "paramname":"cbBuf", "paramtype":"uint32" }, + { "paramname":"bWithPort", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "SteamNetworkingIPAddr_ParseString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_ParseString", + "params": [ + { "paramname":"pAddr", "paramtype":"SteamNetworkingIPAddr *" }, + { "paramname":"pszStr", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "SteamNetworkingIPAddr_GetFakeIPType", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_GetFakeIPType", + "params": [ + { "paramname":"addr", "paramtype":"const SteamNetworkingIPAddr &" } + ], + "returntype": "ESteamNetworkingFakeIPType" + }, + { + "methodname": "SteamNetworkingIdentity_ToString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SteamNetworkingIdentity_ToString", + "params": [ + { "paramname":"identity", "paramtype":"const SteamNetworkingIdentity &" }, + { "paramname":"buf", "paramtype":"char *" }, + { "paramname":"cbBuf", "paramtype":"uint32" } + ], + "returntype": "void" + }, + { + "methodname": "SteamNetworkingIdentity_ParseString", + "methodname_flat": "SteamAPI_ISteamNetworkingUtils_SteamNetworkingIdentity_ParseString", + "params": [ + { "paramname":"pIdentity", "paramtype":"SteamNetworkingIdentity *" }, + { "paramname":"pszStr", "paramtype":"const char *" } + ], + "returntype": "bool" + } + ], + "version_string": "SteamNetworkingUtils004" + }, + { + "accessors": [ + { + "kind": "gameserver", + "name": "SteamGameServer", + "name_flat": "SteamAPI_SteamGameServer_v015" + } + ], + "classname": "ISteamGameServer", + "fields": [], + "methods": [ + { + "methodname": "SetProduct", + "methodname_flat": "SteamAPI_ISteamGameServer_SetProduct", + "params": [ + { "paramname":"pszProduct", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetGameDescription", + "methodname_flat": "SteamAPI_ISteamGameServer_SetGameDescription", + "params": [ + { "paramname":"pszGameDescription", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetModDir", + "methodname_flat": "SteamAPI_ISteamGameServer_SetModDir", + "params": [ + { "paramname":"pszModDir", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetDedicatedServer", + "methodname_flat": "SteamAPI_ISteamGameServer_SetDedicatedServer", + "params": [ + { "paramname":"bDedicated", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "LogOn", + "methodname_flat": "SteamAPI_ISteamGameServer_LogOn", + "params": [ + { "paramname":"pszToken", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "LogOnAnonymous", + "methodname_flat": "SteamAPI_ISteamGameServer_LogOnAnonymous", + "params": [], + "returntype": "void" + }, + { + "methodname": "LogOff", + "methodname_flat": "SteamAPI_ISteamGameServer_LogOff", + "params": [], + "returntype": "void" + }, + { + "methodname": "BLoggedOn", + "methodname_flat": "SteamAPI_ISteamGameServer_BLoggedOn", + "params": [], + "returntype": "bool" + }, + { + "methodname": "BSecure", + "methodname_flat": "SteamAPI_ISteamGameServer_BSecure", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetSteamID", + "methodname_flat": "SteamAPI_ISteamGameServer_GetSteamID", + "params": [], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "WasRestartRequested", + "methodname_flat": "SteamAPI_ISteamGameServer_WasRestartRequested", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetMaxPlayerCount", + "methodname_flat": "SteamAPI_ISteamGameServer_SetMaxPlayerCount", + "params": [ + { "paramname":"cPlayersMax", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "SetBotPlayerCount", + "methodname_flat": "SteamAPI_ISteamGameServer_SetBotPlayerCount", + "params": [ + { "paramname":"cBotplayers", "paramtype":"int" } + ], + "returntype": "void" + }, + { + "methodname": "SetServerName", + "methodname_flat": "SteamAPI_ISteamGameServer_SetServerName", + "params": [ + { "paramname":"pszServerName", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetMapName", + "methodname_flat": "SteamAPI_ISteamGameServer_SetMapName", + "params": [ + { "paramname":"pszMapName", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetPasswordProtected", + "methodname_flat": "SteamAPI_ISteamGameServer_SetPasswordProtected", + "params": [ + { "paramname":"bPasswordProtected", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "SetSpectatorPort", + "methodname_flat": "SteamAPI_ISteamGameServer_SetSpectatorPort", + "params": [ + { "paramname":"unSpectatorPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "SetSpectatorServerName", + "methodname_flat": "SteamAPI_ISteamGameServer_SetSpectatorServerName", + "params": [ + { "paramname":"pszSpectatorServerName", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "ClearAllKeyValues", + "methodname_flat": "SteamAPI_ISteamGameServer_ClearAllKeyValues", + "params": [], + "returntype": "void" + }, + { + "methodname": "SetKeyValue", + "methodname_flat": "SteamAPI_ISteamGameServer_SetKeyValue", + "params": [ + { "paramname":"pKey", "paramtype":"const char *" }, + { "paramname":"pValue", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetGameTags", + "methodname_flat": "SteamAPI_ISteamGameServer_SetGameTags", + "params": [ + { "paramname":"pchGameTags", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetGameData", + "methodname_flat": "SteamAPI_ISteamGameServer_SetGameData", + "params": [ + { "paramname":"pchGameData", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetRegion", + "methodname_flat": "SteamAPI_ISteamGameServer_SetRegion", + "params": [ + { "paramname":"pszRegion", "paramtype":"const char *" } + ], + "returntype": "void" + }, + { + "methodname": "SetAdvertiseServerActive", + "methodname_flat": "SteamAPI_ISteamGameServer_SetAdvertiseServerActive", + "params": [ + { "paramname":"bActive", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "GetAuthSessionTicket", + "methodname_flat": "SteamAPI_ISteamGameServer_GetAuthSessionTicket", + "params": [ + { "paramname":"pTicket", "paramtype":"void *" }, + { "paramname":"cbMaxTicket", "paramtype":"int" }, + { "paramname":"pcbTicket", "paramtype":"uint32 *" }, + { "paramname":"pSnid", "paramtype":"const SteamNetworkingIdentity *" } + ], + "returntype": "HAuthTicket" + }, + { + "methodname": "BeginAuthSession", + "methodname_flat": "SteamAPI_ISteamGameServer_BeginAuthSession", + "params": [ + { "paramname":"pAuthTicket", "paramtype":"const void *" }, + { "paramname":"cbAuthTicket", "paramtype":"int" }, + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "EBeginAuthSessionResult" + }, + { + "methodname": "EndAuthSession", + "methodname_flat": "SteamAPI_ISteamGameServer_EndAuthSession", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "CancelAuthTicket", + "methodname_flat": "SteamAPI_ISteamGameServer_CancelAuthTicket", + "params": [ + { "paramname":"hAuthTicket", "paramtype":"HAuthTicket" } + ], + "returntype": "void" + }, + { + "methodname": "UserHasLicenseForApp", + "methodname_flat": "SteamAPI_ISteamGameServer_UserHasLicenseForApp", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"appID", "paramtype":"AppId_t" } + ], + "returntype": "EUserHasLicenseForAppResult" + }, + { + "methodname": "RequestUserGroupStatus", + "methodname_flat": "SteamAPI_ISteamGameServer_RequestUserGroupStatus", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"steamIDGroup", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "bool" + }, + { + "methodname": "GetGameplayStats", + "methodname_flat": "SteamAPI_ISteamGameServer_GetGameplayStats", + "params": [], + "returntype": "void" + }, + { + "callresult": "GSReputation_t", + "methodname": "GetServerReputation", + "methodname_flat": "SteamAPI_ISteamGameServer_GetServerReputation", + "params": [], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetPublicIP", + "methodname_flat": "SteamAPI_ISteamGameServer_GetPublicIP", + "params": [], + "returntype": "SteamIPAddress_t" + }, + { + "methodname": "HandleIncomingPacket", + "methodname_flat": "SteamAPI_ISteamGameServer_HandleIncomingPacket", + "params": [ + { "paramname":"pData", "paramtype":"const void *" }, + { "paramname":"cbData", "paramtype":"int" }, + { "paramname":"srcIP", "paramtype":"uint32" }, + { "paramname":"srcPort", "paramtype":"uint16" } + ], + "returntype": "bool" + }, + { + "methodname": "GetNextOutgoingPacket", + "methodname_flat": "SteamAPI_ISteamGameServer_GetNextOutgoingPacket", + "params": [ + { "paramname":"pOut", "paramtype":"void *" }, + { "paramname":"cbMaxOut", "paramtype":"int" }, + { "paramname":"pNetAdr", "paramtype":"uint32 *" }, + { "paramname":"pPort", "paramtype":"uint16 *" } + ], + "returntype": "int" + }, + { + "callresult": "AssociateWithClanResult_t", + "methodname": "AssociateWithClan", + "methodname_flat": "SteamAPI_ISteamGameServer_AssociateWithClan", + "params": [ + { "paramname":"steamIDClan", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "callresult": "ComputeNewPlayerCompatibilityResult_t", + "methodname": "ComputeNewPlayerCompatibility", + "methodname_flat": "SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility", + "params": [ + { "paramname":"steamIDNewPlayer", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "SendUserConnectAndAuthenticate_DEPRECATED", + "methodname_flat": "SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate_DEPRECATED", + "params": [ + { "paramname":"unIPClient", "paramtype":"uint32" }, + { "paramname":"pvAuthBlob", "paramtype":"const void *" }, + { "paramname":"cubAuthBlobSize", "paramtype":"uint32" }, + { "paramname":"pSteamIDUser", "paramtype":"CSteamID *" } + ], + "returntype": "bool" + }, + { + "methodname": "CreateUnauthenticatedUserConnection", + "methodname_flat": "SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection", + "params": [], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "SendUserDisconnect_DEPRECATED", + "methodname_flat": "SteamAPI_ISteamGameServer_SendUserDisconnect_DEPRECATED", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "BUpdateUserData", + "methodname_flat": "SteamAPI_ISteamGameServer_BUpdateUserData", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchPlayerName", "paramtype":"const char *" }, + { "paramname":"uScore", "paramtype":"uint32" } + ], + "returntype": "bool" + } + ], + "version_string": "SteamGameServer015" + }, + { + "accessors": [ + { + "kind": "gameserver", + "name": "SteamGameServerStats", + "name_flat": "SteamAPI_SteamGameServerStats_v001" + } + ], + "classname": "ISteamGameServerStats", + "fields": [], + "methods": [ + { + "callresult": "GSStatsReceived_t", + "methodname": "RequestUserStats", + "methodname_flat": "SteamAPI_ISteamGameServerStats_RequestUserStats", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + }, + { + "methodname": "GetUserStat", + "methodname_flat": "SteamAPI_ISteamGameServerStats_GetUserStatInt32", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"int32 *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetUserStat", + "methodname_flat": "SteamAPI_ISteamGameServerStats_GetUserStatFloat", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pData", "paramtype":"float *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetUserAchievement", + "methodname_flat": "SteamAPI_ISteamGameServerStats_GetUserAchievement", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"pbAchieved", "paramtype":"bool *" } + ], + "returntype": "bool" + }, + { + "methodname": "SetUserStat", + "methodname_flat": "SteamAPI_ISteamGameServerStats_SetUserStatInt32", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"nData", "paramtype":"int32" } + ], + "returntype": "bool" + }, + { + "methodname": "SetUserStat", + "methodname_flat": "SteamAPI_ISteamGameServerStats_SetUserStatFloat", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"fData", "paramtype":"float" } + ], + "returntype": "bool" + }, + { + "methodname": "UpdateUserAvgRateStat", + "methodname_flat": "SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" }, + { "paramname":"flCountThisSession", "paramtype":"float" }, + { "paramname":"dSessionLength", "paramtype":"double" } + ], + "returntype": "bool" + }, + { + "methodname": "SetUserAchievement", + "methodname_flat": "SteamAPI_ISteamGameServerStats_SetUserAchievement", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "ClearUserAchievement", + "methodname_flat": "SteamAPI_ISteamGameServerStats_ClearUserAchievement", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" }, + { "paramname":"pchName", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "callresult": "GSStatsStored_t", + "methodname": "StoreUserStats", + "methodname_flat": "SteamAPI_ISteamGameServerStats_StoreUserStats", + "params": [ + { "paramname":"steamIDUser", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "SteamAPICall_t" + } + ], + "version_string": "SteamGameServerStats001" + }, + { + "classname": "ISteamNetworkingFakeUDPPort", + "fields": [], + "methods": [ + { + "methodname": "DestroyFakeUDPPort", + "methodname_flat": "SteamAPI_ISteamNetworkingFakeUDPPort_DestroyFakeUDPPort", + "params": [], + "returntype": "void" + }, + { + "methodname": "SendMessageToFakeIP", + "methodname_flat": "SteamAPI_ISteamNetworkingFakeUDPPort_SendMessageToFakeIP", + "params": [ + { "paramname":"remoteAddress", "paramtype":"const SteamNetworkingIPAddr &" }, + { "paramname":"pData", "paramtype":"const void *" }, + { "paramname":"cbData", "paramtype":"uint32" }, + { "paramname":"nSendFlags", "paramtype":"int" } + ], + "returntype": "EResult" + }, + { + "methodname": "ReceiveMessages", + "methodname_flat": "SteamAPI_ISteamNetworkingFakeUDPPort_ReceiveMessages", + "params": [ + { "paramname":"ppOutMessages", "paramtype":"SteamNetworkingMessage_t **" }, + { "paramname":"nMaxMessages", "paramtype":"int" } + ], + "returntype": "int" + }, + { + "methodname": "ScheduleCleanup", + "methodname_flat": "SteamAPI_ISteamNetworkingFakeUDPPort_ScheduleCleanup", + "params": [ + { "paramname":"remoteAddress", "paramtype":"const SteamNetworkingIPAddr &" } + ], + "returntype": "void" + } + ] + } + ], + "structs": [ + { + "fields": [ + { "fieldname":"m_rgubIPv6", "fieldtype":"uint8 [16]" }, + { "fieldname":"m_eType", "fieldtype":"ESteamIPType" } + ], + "methods": [ + { + "methodname": "IsSet", + "methodname_flat": "SteamAPI_SteamIPAddress_t_IsSet", + "params": [], + "returntype": "bool" + } + ], + "struct": "SteamIPAddress_t" + }, + { + "fields": [ + { "fieldname":"m_gameID", "fieldtype":"CGameID" }, + { "fieldname":"m_unGameIP", "fieldtype":"uint32" }, + { "fieldname":"m_usGamePort", "fieldtype":"uint16" }, + { "fieldname":"m_usQueryPort", "fieldtype":"uint16" }, + { "fieldname":"m_steamIDLobby", "fieldtype":"CSteamID" } + ], + "struct": "FriendGameInfo_t" + }, + { + "fields": [ + { "fieldname":"m_szKey", "fieldtype":"char [256]" }, + { "fieldname":"m_szValue", "fieldtype":"char [256]" } + ], + "methods": [ + { + "methodname": "Construct", + "methodname_flat": "SteamAPI_MatchMakingKeyValuePair_t_Construct", + "params": [], + "returntype": "void" + } + ], + "struct": "MatchMakingKeyValuePair_t" + }, + { + "fields": [ + { + "fieldname": "m_usConnectionPort", + "fieldtype": "uint16", + "private": true + }, + { + "fieldname": "m_usQueryPort", + "fieldtype": "uint16", + "private": true + }, + { + "fieldname": "m_unIP", + "fieldtype": "uint32", + "private": true + } + ], + "methods": [ + { + "methodname": "Construct", + "methodname_flat": "SteamAPI_servernetadr_t_Construct", + "params": [], + "returntype": "void" + }, + { + "methodname": "Init", + "methodname_flat": "SteamAPI_servernetadr_t_Init", + "params": [ + { "paramname":"ip", "paramtype":"unsigned int" }, + { "paramname":"usQueryPort", "paramtype":"uint16" }, + { "paramname":"usConnectionPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "GetQueryPort", + "methodname_flat": "SteamAPI_servernetadr_t_GetQueryPort", + "params": [], + "returntype": "uint16" + }, + { + "methodname": "SetQueryPort", + "methodname_flat": "SteamAPI_servernetadr_t_SetQueryPort", + "params": [ + { "paramname":"usPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "GetConnectionPort", + "methodname_flat": "SteamAPI_servernetadr_t_GetConnectionPort", + "params": [], + "returntype": "uint16" + }, + { + "methodname": "SetConnectionPort", + "methodname_flat": "SteamAPI_servernetadr_t_SetConnectionPort", + "params": [ + { "paramname":"usPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "GetIP", + "methodname_flat": "SteamAPI_servernetadr_t_GetIP", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "SetIP", + "methodname_flat": "SteamAPI_servernetadr_t_SetIP", + "params": [ + { "paramname":"unIP", "paramtype":"uint32" } + ], + "returntype": "void" + }, + { + "methodname": "GetConnectionAddressString", + "methodname_flat": "SteamAPI_servernetadr_t_GetConnectionAddressString", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "GetQueryAddressString", + "methodname_flat": "SteamAPI_servernetadr_t_GetQueryAddressString", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "operator<", + "methodname_flat": "SteamAPI_servernetadr_t_IsLessThan", + "params": [ + { "paramname":"netadr", "paramtype":"const servernetadr_t &" } + ], + "returntype": "bool" + }, + { + "methodname": "operator=", + "methodname_flat": "SteamAPI_servernetadr_t_Assign", + "params": [ + { "paramname":"that", "paramtype":"const servernetadr_t &" } + ], + "returntype": "void" + } + ], + "struct": "servernetadr_t" + }, + { + "fields": [ + { "fieldname":"m_NetAdr", "fieldtype":"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]", + "private": true + }, + { "fieldname":"m_szGameTags", "fieldtype":"char [128]" }, + { "fieldname":"m_steamID", "fieldtype":"CSteamID" } + ], + "methods": [ + { + "methodname": "Construct", + "methodname_flat": "SteamAPI_gameserveritem_t_Construct", + "params": [], + "returntype": "void" + }, + { + "methodname": "GetName", + "methodname_flat": "SteamAPI_gameserveritem_t_GetName", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "SetName", + "methodname_flat": "SteamAPI_gameserveritem_t_SetName", + "params": [ + { "paramname":"pName", "paramtype":"const char *" } + ], + "returntype": "void" + } + ], + "struct": "gameserveritem_t" + }, + { + "fields": [ + { "fieldname":"m_eType", "fieldtype":"ESteamPartyBeaconLocationType" }, + { "fieldname":"m_ulLocationID", "fieldtype":"uint64" } + ], + "struct": "SteamPartyBeaconLocation_t" + }, + { + "fields": [ + { "fieldname":"m_ppStrings", "fieldtype":"const char **" }, + { "fieldname":"m_nNumStrings", "fieldtype":"int32" } + ], + "struct": "SteamParamStringArray_t" + }, + { + "fields": [ + { "fieldname":"m_steamIDUser", "fieldtype":"CSteamID" }, + { "fieldname":"m_nGlobalRank", "fieldtype":"int32" }, + { "fieldname":"m_nScore", "fieldtype":"int32" }, + { "fieldname":"m_cDetails", "fieldtype":"int32" }, + { "fieldname":"m_hUGC", "fieldtype":"UGCHandle_t" } + ], + "struct": "LeaderboardEntry_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": "P2PSessionState_t" + }, + { + "fields": [ + { "fieldname":"eMode", "fieldtype":"EInputSourceMode" }, + { "fieldname":"x", "fieldtype":"float" }, + { "fieldname":"y", "fieldtype":"float" }, + { "fieldname":"bActive", "fieldtype":"bool" } + ], + "struct": "InputAnalogActionData_t" + }, + { + "fields": [ + { "fieldname":"bState", "fieldtype":"bool" }, + { "fieldname":"bActive", "fieldtype":"bool" } + ], + "struct": "InputDigitalActionData_t" + }, + { + "fields": [ + { "fieldname":"rotQuatX", "fieldtype":"float" }, + { "fieldname":"rotQuatY", "fieldtype":"float" }, + { "fieldname":"rotQuatZ", "fieldtype":"float" }, + { "fieldname":"rotQuatW", "fieldtype":"float" }, + { "fieldname":"posAccelX", "fieldtype":"float" }, + { "fieldname":"posAccelY", "fieldtype":"float" }, + { "fieldname":"posAccelZ", "fieldtype":"float" }, + { "fieldname":"rotVelX", "fieldtype":"float" }, + { "fieldname":"rotVelY", "fieldtype":"float" }, + { "fieldname":"rotVelZ", "fieldtype":"float" } + ], + "struct": "InputMotionData_t" + }, + { + "fields": [ + { "fieldname":"driftCorrectedQuatX", "fieldtype":"float" }, + { "fieldname":"driftCorrectedQuatY", "fieldtype":"float" }, + { "fieldname":"driftCorrectedQuatZ", "fieldtype":"float" }, + { "fieldname":"driftCorrectedQuatW", "fieldtype":"float" }, + { "fieldname":"sensorFusionQuatX", "fieldtype":"float" }, + { "fieldname":"sensorFusionQuatY", "fieldtype":"float" }, + { "fieldname":"sensorFusionQuatZ", "fieldtype":"float" }, + { "fieldname":"sensorFusionQuatW", "fieldtype":"float" }, + { "fieldname":"deferredSensorFusionQuatX", "fieldtype":"float" }, + { "fieldname":"deferredSensorFusionQuatY", "fieldtype":"float" }, + { "fieldname":"deferredSensorFusionQuatZ", "fieldtype":"float" }, + { "fieldname":"deferredSensorFusionQuatW", "fieldtype":"float" }, + { "fieldname":"gravityX", "fieldtype":"float" }, + { "fieldname":"gravityY", "fieldtype":"float" }, + { "fieldname":"gravityZ", "fieldtype":"float" }, + { "fieldname":"degreesPerSecondX", "fieldtype":"float" }, + { "fieldname":"degreesPerSecondY", "fieldtype":"float" }, + { "fieldname":"degreesPerSecondZ", "fieldtype":"float" } + ], + "struct": "InputMotionDataV2_t" + }, + { + "fields": [ + { "fieldname":"controllerHandle", "fieldtype":"InputHandle_t" }, + { "fieldname":"eEventType", "fieldtype":"ESteamInputActionEventType" }, + { "fieldname":"analogAction", "fieldtype":"SteamInputActionEvent_t::AnalogAction_t" } + ], + "struct": "SteamInputActionEvent_t" + }, + { + "fields": [ + { "fieldname":"m_nPublishedFileId", "fieldtype":"PublishedFileId_t" }, + { "fieldname":"m_eResult", "fieldtype":"EResult" }, + { "fieldname":"m_eFileType", "fieldtype":"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":"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": "SteamUGCDetails_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": "SteamItemDetails_t" + }, + { + "consts": [ + { "constname":"k_cchMaxString", "consttype":"int", "constval":"48" } + ], + "fields": [ + { "fieldname":"m_ipv6", "fieldtype":"uint8 [16]" }, + { "fieldname":"m_port", "fieldtype":"uint16" } + ], + "methods": [ + { + "methodname": "Clear", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_Clear", + "params": [], + "returntype": "void" + }, + { + "methodname": "IsIPv6AllZeros", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_IsIPv6AllZeros", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetIPv6", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_SetIPv6", + "params": [ + { "paramname":"ipv6", "paramtype":"const uint8 *" }, + { "paramname":"nPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "SetIPv4", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_SetIPv4", + "params": [ + { "paramname":"nIP", "paramtype":"uint32" }, + { "paramname":"nPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "IsIPv4", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_IsIPv4", + "params": [], + "returntype": "bool" + }, + { + "methodname": "GetIPv4", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_GetIPv4", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "SetIPv6LocalHost", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost", + "params": [ + { "paramname":"nPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "IsLocalHost", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_IsLocalHost", + "params": [], + "returntype": "bool" + }, + { + "methodname": "ToString", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_ToString", + "params": [ + { "paramname":"buf", "paramtype":"char *" }, + { "paramname":"cbBuf", "paramtype":"uint32" }, + { "paramname":"bWithPort", "paramtype":"bool" } + ], + "returntype": "void" + }, + { + "methodname": "ParseString", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_ParseString", + "params": [ + { "paramname":"pszStr", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "operator==", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_IsEqualTo", + "params": [ + { "paramname":"x", "paramtype":"const SteamNetworkingIPAddr &" } + ], + "returntype": "bool" + }, + { + "methodname": "GetFakeIPType", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_GetFakeIPType", + "params": [], + "returntype": "ESteamNetworkingFakeIPType" + }, + { + "methodname": "IsFakeIP", + "methodname_flat": "SteamAPI_SteamNetworkingIPAddr_IsFakeIP", + "params": [], + "returntype": "bool" + } + ], + "struct": "SteamNetworkingIPAddr" + }, + { + "consts": [ + { "constname":"k_cchMaxString", "consttype":"int", "constval":"128" }, + { "constname":"k_cchMaxGenericString", "consttype":"int", "constval":"32" }, + { "constname":"k_cchMaxXboxPairwiseID", "consttype":"int", "constval":"33" }, + { "constname":"k_cbMaxGenericBytes", "consttype":"int", "constval":"32" } + ], + "fields": [ + { "fieldname":"m_eType", "fieldtype":"ESteamNetworkingIdentityType" }, + { "fieldname":"m_cbSize", "fieldtype":"int" }, + { "fieldname":"m_szUnknownRawString", "fieldtype":"char [128]" } + ], + "methods": [ + { + "methodname": "Clear", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_Clear", + "params": [], + "returntype": "void" + }, + { + "methodname": "IsInvalid", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_IsInvalid", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetSteamID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetSteamID", + "params": [ + { "paramname":"steamID", "paramtype":"CSteamID", "paramtype_flat":"uint64_steamid" } + ], + "returntype": "void" + }, + { + "methodname": "GetSteamID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetSteamID", + "params": [], + "returntype": "CSteamID", + "returntype_flat": "uint64_steamid" + }, + { + "methodname": "SetSteamID64", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetSteamID64", + "params": [ + { "paramname":"steamID", "paramtype":"uint64" } + ], + "returntype": "void" + }, + { + "methodname": "GetSteamID64", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetSteamID64", + "params": [], + "returntype": "uint64" + }, + { + "methodname": "SetXboxPairwiseID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetXboxPairwiseID", + "params": [ + { "paramname":"pszString", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetXboxPairwiseID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetXboxPairwiseID", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "SetPSNID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetPSNID", + "params": [ + { "paramname":"id", "paramtype":"uint64" } + ], + "returntype": "void" + }, + { + "methodname": "GetPSNID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetPSNID", + "params": [], + "returntype": "uint64" + }, + { + "methodname": "SetStadiaID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetStadiaID", + "params": [ + { "paramname":"id", "paramtype":"uint64" } + ], + "returntype": "void" + }, + { + "methodname": "GetStadiaID", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetStadiaID", + "params": [], + "returntype": "uint64" + }, + { + "methodname": "SetIPAddr", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetIPAddr", + "params": [ + { "paramname":"addr", "paramtype":"const SteamNetworkingIPAddr &" } + ], + "returntype": "void" + }, + { + "methodname": "GetIPAddr", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetIPAddr", + "params": [], + "returntype": "const SteamNetworkingIPAddr *" + }, + { + "methodname": "SetIPv4Addr", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetIPv4Addr", + "params": [ + { "paramname":"nIPv4", "paramtype":"uint32" }, + { "paramname":"nPort", "paramtype":"uint16" } + ], + "returntype": "void" + }, + { + "methodname": "GetIPv4", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetIPv4", + "params": [], + "returntype": "uint32" + }, + { + "methodname": "GetFakeIPType", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetFakeIPType", + "params": [], + "returntype": "ESteamNetworkingFakeIPType" + }, + { + "methodname": "IsFakeIP", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_IsFakeIP", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetLocalHost", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetLocalHost", + "params": [], + "returntype": "void" + }, + { + "methodname": "IsLocalHost", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_IsLocalHost", + "params": [], + "returntype": "bool" + }, + { + "methodname": "SetGenericString", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetGenericString", + "params": [ + { "paramname":"pszString", "paramtype":"const char *" } + ], + "returntype": "bool" + }, + { + "methodname": "GetGenericString", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetGenericString", + "params": [], + "returntype": "const char *" + }, + { + "methodname": "SetGenericBytes", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_SetGenericBytes", + "params": [ + { "paramname":"data", "paramtype":"const void *" }, + { "paramname":"cbLen", "paramtype":"uint32" } + ], + "returntype": "bool" + }, + { + "methodname": "GetGenericBytes", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_GetGenericBytes", + "params": [ + { "paramname":"cbLen", "paramtype":"int &" } + ], + "returntype": "const uint8 *" + }, + { + "methodname": "operator==", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_IsEqualTo", + "params": [ + { "paramname":"x", "paramtype":"const SteamNetworkingIdentity &" } + ], + "returntype": "bool" + }, + { + "methodname": "ToString", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_ToString", + "params": [ + { "paramname":"buf", "paramtype":"char *" }, + { "paramname":"cbBuf", "paramtype":"uint32" } + ], + "returntype": "void" + }, + { + "methodname": "ParseString", + "methodname_flat": "SteamAPI_SteamNetworkingIdentity_ParseString", + "params": [ + { "paramname":"pszStr", "paramtype":"const char *" } + ], + "returntype": "bool" + } + ], + "struct": "SteamNetworkingIdentity" + }, + { + "fields": [ + { "fieldname":"m_identityRemote", "fieldtype":"SteamNetworkingIdentity" }, + { "fieldname":"m_nUserData", "fieldtype":"int64" }, + { "fieldname":"m_hListenSocket", "fieldtype":"HSteamListenSocket" }, + { "fieldname":"m_addrRemote", "fieldtype":"SteamNetworkingIPAddr" }, + { "fieldname":"m__pad1", "fieldtype":"uint16" }, + { "fieldname":"m_idPOPRemote", "fieldtype":"SteamNetworkingPOPID" }, + { "fieldname":"m_idPOPRelay", "fieldtype":"SteamNetworkingPOPID" }, + { "fieldname":"m_eState", "fieldtype":"ESteamNetworkingConnectionState" }, + { "fieldname":"m_eEndReason", "fieldtype":"int" }, + { "fieldname":"m_szEndDebug", "fieldtype":"char [128]" }, + { "fieldname":"m_szConnectionDescription", "fieldtype":"char [128]" }, + { "fieldname":"m_nFlags", "fieldtype":"int" }, + { "fieldname":"reserved", "fieldtype":"uint32 [63]" } + ], + "struct": "SteamNetConnectionInfo_t" + }, + { + "fields": [ + { "fieldname":"m_eState", "fieldtype":"ESteamNetworkingConnectionState" }, + { "fieldname":"m_nPing", "fieldtype":"int" }, + { "fieldname":"m_flConnectionQualityLocal", "fieldtype":"float" }, + { "fieldname":"m_flConnectionQualityRemote", "fieldtype":"float" }, + { "fieldname":"m_flOutPacketsPerSec", "fieldtype":"float" }, + { "fieldname":"m_flOutBytesPerSec", "fieldtype":"float" }, + { "fieldname":"m_flInPacketsPerSec", "fieldtype":"float" }, + { "fieldname":"m_flInBytesPerSec", "fieldtype":"float" }, + { "fieldname":"m_nSendRateBytesPerSecond", "fieldtype":"int" }, + { "fieldname":"m_cbPendingUnreliable", "fieldtype":"int" }, + { "fieldname":"m_cbPendingReliable", "fieldtype":"int" }, + { "fieldname":"m_cbSentUnackedReliable", "fieldtype":"int" }, + { "fieldname":"m_usecQueueTime", "fieldtype":"SteamNetworkingMicroseconds" }, + { "fieldname":"reserved", "fieldtype":"uint32 [16]" } + ], + "struct": "SteamNetConnectionRealTimeStatus_t" + }, + { + "fields": [ + { "fieldname":"m_cbPendingUnreliable", "fieldtype":"int" }, + { "fieldname":"m_cbPendingReliable", "fieldtype":"int" }, + { "fieldname":"m_cbSentUnackedReliable", "fieldtype":"int" }, + { "fieldname":"_reservePad1", "fieldtype":"int" }, + { "fieldname":"m_usecQueueTime", "fieldtype":"SteamNetworkingMicroseconds" }, + { "fieldname":"reserved", "fieldtype":"uint32 [10]" } + ], + "struct": "SteamNetConnectionRealTimeLaneStatus_t" + }, + { + "fields": [ + { "fieldname":"m_pData", "fieldtype":"void *" }, + { "fieldname":"m_cbSize", "fieldtype":"int" }, + { "fieldname":"m_conn", "fieldtype":"HSteamNetConnection" }, + { "fieldname":"m_identityPeer", "fieldtype":"SteamNetworkingIdentity" }, + { "fieldname":"m_nConnUserData", "fieldtype":"int64" }, + { "fieldname":"m_usecTimeReceived", "fieldtype":"SteamNetworkingMicroseconds" }, + { "fieldname":"m_nMessageNumber", "fieldtype":"int64" }, + { "fieldname":"m_pfnFreeData", "fieldtype":"void (*)(SteamNetworkingMessage_t *)" }, + { "fieldname":"m_pfnRelease", "fieldtype":"void (*)(SteamNetworkingMessage_t *)" }, + { "fieldname":"m_nChannel", "fieldtype":"int" }, + { "fieldname":"m_nFlags", "fieldtype":"int" }, + { "fieldname":"m_nUserData", "fieldtype":"int64" }, + { "fieldname":"m_idxLane", "fieldtype":"uint16" }, + { "fieldname":"_pad1__", "fieldtype":"uint16" } + ], + "methods": [ + { + "methodname": "Release", + "methodname_flat": "SteamAPI_SteamNetworkingMessage_t_Release", + "params": [], + "returntype": "void" + } + ], + "struct": "SteamNetworkingMessage_t" + }, + { + "fields": [ + { "fieldname":"m_data", "fieldtype":"uint8 [512]" } + ], + "struct": "SteamNetworkPingLocation_t" + }, + { + "fields": [ + { "fieldname":"m_eValue", "fieldtype":"ESteamNetworkingConfigValue" }, + { "fieldname":"m_eDataType", "fieldtype":"ESteamNetworkingConfigDataType" }, + { "fieldname":"m_int64", "fieldtype":"int64_t" } + ], + "methods": [ + { + "methodname": "SetInt32", + "methodname_flat": "SteamAPI_SteamNetworkingConfigValue_t_SetInt32", + "params": [ + { "paramname":"eVal", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"data", "paramtype":"int32_t" } + ], + "returntype": "void" + }, + { + "methodname": "SetInt64", + "methodname_flat": "SteamAPI_SteamNetworkingConfigValue_t_SetInt64", + "params": [ + { "paramname":"eVal", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"data", "paramtype":"int64_t" } + ], + "returntype": "void" + }, + { + "methodname": "SetFloat", + "methodname_flat": "SteamAPI_SteamNetworkingConfigValue_t_SetFloat", + "params": [ + { "paramname":"eVal", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"data", "paramtype":"float" } + ], + "returntype": "void" + }, + { + "methodname": "SetPtr", + "methodname_flat": "SteamAPI_SteamNetworkingConfigValue_t_SetPtr", + "params": [ + { "paramname":"eVal", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"data", "paramtype":"void *" } + ], + "returntype": "void" + }, + { + "methodname": "SetString", + "methodname_flat": "SteamAPI_SteamNetworkingConfigValue_t_SetString", + "params": [ + { "paramname":"eVal", "paramtype":"ESteamNetworkingConfigValue" }, + { "paramname":"data", "paramtype":"const char *" } + ], + "returntype": "void" + } + ], + "struct": "SteamNetworkingConfigValue_t" + }, + { + "fields": [ + { "fieldname":"m_cbSize", "fieldtype":"int" }, + { "fieldname":"m_data", "fieldtype":"char [128]" } + ], + "methods": [ + { + "methodname": "Clear", + "methodname_flat": "SteamAPI_SteamDatagramHostedAddress_Clear", + "params": [], + "returntype": "void" + }, + { + "methodname": "GetPopID", + "methodname_flat": "SteamAPI_SteamDatagramHostedAddress_GetPopID", + "params": [], + "returntype": "SteamNetworkingPOPID" + }, + { + "methodname": "SetDevAddress", + "methodname_flat": "SteamAPI_SteamDatagramHostedAddress_SetDevAddress", + "params": [ + { "paramname":"nIP", "paramtype":"uint32" }, + { "paramname":"nPort", "paramtype":"uint16" }, + { "paramname":"popid", "paramtype":"SteamNetworkingPOPID" } + ], + "returntype": "void" + } + ], + "struct": "SteamDatagramHostedAddress" + }, + { + "fields": [ + { "fieldname":"m_identity", "fieldtype":"SteamNetworkingIdentity" }, + { "fieldname":"m_routing", "fieldtype":"SteamDatagramHostedAddress" }, + { "fieldname":"m_nAppID", "fieldtype":"AppId_t" }, + { "fieldname":"m_rtime", "fieldtype":"RTime32" }, + { "fieldname":"m_cbAppData", "fieldtype":"int" }, + { "fieldname":"m_appData", "fieldtype":"char [2048]" } + ], + "struct": "SteamDatagramGameCoordinatorServerLogin" + } + ], + "typedefs": [ + { "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":"long long" }, + { "typedef":"ulint64", "type":"unsigned long long" }, + { "typedef":"intp", "type":"long long" }, + { "typedef":"uintp", "type":"unsigned long long" }, + { "typedef":"AppId_t", "type":"unsigned int" }, + { "typedef":"DepotId_t", "type":"unsigned int" }, + { "typedef":"RTime32", "type":"unsigned int" }, + { "typedef":"SteamAPICall_t", "type":"unsigned long long" }, + { "typedef":"AccountID_t", "type":"unsigned int" }, + { "typedef":"PartyBeaconID_t", "type":"unsigned long long" }, + { "typedef":"HAuthTicket", "type":"unsigned int" }, + { "typedef":"PFNPreMinidumpCallback", "type":"void (*)(void *)" }, + { "typedef":"HSteamPipe", "type":"int" }, + { "typedef":"HSteamUser", "type":"int" }, + { "typedef":"FriendsGroupID_t", "type":"short" }, + { "typedef":"HServerListRequest", "type":"void *" }, + { "typedef":"HServerQuery", "type":"int" }, + { "typedef":"UGCHandle_t", "type":"unsigned long long" }, + { "typedef":"PublishedFileUpdateHandle_t", "type":"unsigned long long" }, + { "typedef":"PublishedFileId_t", "type":"unsigned long long" }, + { "typedef":"UGCFileWriteStreamHandle_t", "type":"unsigned long long" }, + { "typedef":"SteamLeaderboard_t", "type":"unsigned long long" }, + { "typedef":"SteamLeaderboardEntries_t", "type":"unsigned long long" }, + { "typedef":"SNetSocket_t", "type":"unsigned int" }, + { "typedef":"SNetListenSocket_t", "type":"unsigned int" }, + { "typedef":"ScreenshotHandle", "type":"unsigned int" }, + { "typedef":"HTTPRequestHandle", "type":"unsigned int" }, + { "typedef":"HTTPCookieContainerHandle", "type":"unsigned int" }, + { "typedef":"InputHandle_t", "type":"unsigned long long" }, + { "typedef":"InputActionSetHandle_t", "type":"unsigned long long" }, + { "typedef":"InputDigitalActionHandle_t", "type":"unsigned long long" }, + { "typedef":"InputAnalogActionHandle_t", "type":"unsigned long long" }, + { "typedef":"SteamInputActionEventCallbackPointer", "type":"void (*)(SteamInputActionEvent_t *)" }, + { "typedef":"ControllerHandle_t", "type":"unsigned long long" }, + { "typedef":"ControllerActionSetHandle_t", "type":"unsigned long long" }, + { "typedef":"ControllerDigitalActionHandle_t", "type":"unsigned long long" }, + { "typedef":"ControllerAnalogActionHandle_t", "type":"unsigned long long" }, + { "typedef":"UGCQueryHandle_t", "type":"unsigned long long" }, + { "typedef":"UGCUpdateHandle_t", "type":"unsigned long long" }, + { "typedef":"HHTMLBrowser", "type":"unsigned int" }, + { "typedef":"SteamItemInstanceID_t", "type":"unsigned long long" }, + { "typedef":"SteamItemDef_t", "type":"int" }, + { "typedef":"SteamInventoryResult_t", "type":"int" }, + { "typedef":"SteamInventoryUpdateHandle_t", "type":"unsigned long long" }, + { "typedef":"RemotePlaySessionID_t", "type":"unsigned int" }, + { "typedef":"FnSteamNetConnectionStatusChanged", "type":"void (*)(SteamNetConnectionStatusChangedCallback_t *)" }, + { "typedef":"FnSteamNetAuthenticationStatusChanged", "type":"void (*)(SteamNetAuthenticationStatus_t *)" }, + { "typedef":"FnSteamRelayNetworkStatusChanged", "type":"void (*)(SteamRelayNetworkStatus_t *)" }, + { "typedef":"FnSteamNetworkingMessagesSessionRequest", "type":"void (*)(SteamNetworkingMessagesSessionRequest_t *)" }, + { "typedef":"FnSteamNetworkingMessagesSessionFailed", "type":"void (*)(SteamNetworkingMessagesSessionFailed_t *)" }, + { "typedef":"FnSteamNetworkingFakeIPResult", "type":"void (*)(SteamNetworkingFakeIPResult_t *)" }, + { "typedef":"HSteamNetConnection", "type":"unsigned int" }, + { "typedef":"HSteamListenSocket", "type":"unsigned int" }, + { "typedef":"HSteamNetPollGroup", "type":"unsigned int" }, + { "typedef":"SteamNetworkingErrMsg", "type":"char [1024]" }, + { "typedef":"SteamNetworkingPOPID", "type":"unsigned int" }, + { "typedef":"SteamNetworkingMicroseconds", "type":"long long" }, + { "typedef":"FSteamNetworkingSocketsDebugOutput", "type":"void (*)(ESteamNetworkingSocketsDebugOutputType, const char *)" } + ] +} diff --git a/Amalgam/src/SDK/Definitions/Steam/Steam_API_Common.h b/Amalgam/src/SDK/Definitions/Steam/Steam_API_Common.h new file mode 100644 index 0000000..0d5ea7d --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/Steam_API_Common.h @@ -0,0 +1,238 @@ +//====== 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 + +#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; + +// #define away __cdecl on posix. +// This is really, really bad. We're sorry. But it's been this way for +// a long time now and it's scary to change it, as there may be others that +// depend on it. +#ifndef _WIN32 + #define __cdecl +#endif + +// function prototype +extern "C" typedef void ( S_CALLTYPE *SteamAPIWarningMessageHook_t )( int, const char * ); +extern "C" typedef uint32 ( S_CALLTYPE *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(). +// +// Note that there is an alternative, lower level callback dispatch mechanism. +// See SteamAPI_ManualDispatch_Init +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// 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: + friend class CCallbackMgr; + 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/Amalgam/src/SDK/Definitions/Steam/Steam_API_Flat.h b/Amalgam/src/SDK/Definitions/Steam/Steam_API_Flat.h new file mode 100644 index 0000000..6b5bbf1 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/Steam_API_Flat.h @@ -0,0 +1,1278 @@ +//====== Copyright Valve Corporation, All rights reserved. ==================== +// +// Purpose: Header for "flat" SteamAPI. Use this for binding to other languages. +// This file is auto-generated, do not edit it. +// +//============================================================================= + +#ifndef STEAMAPIFLAT_H +#define STEAMAPIFLAT_H + +#include "steam/Steam_API.h" +#include "steam/ISteamGameServer.h" +#include "steam/ISteamGameServerStats.h" + +typedef uint64 uint64_steamid; // Used when passing or returning CSteamID +typedef uint64 uint64_gameid; // Used when passing or return CGameID + + + +// ISteamClient +S_API HSteamPipe SteamAPI_ISteamClient_CreateSteamPipe( ISteamClient* self ); +S_API bool SteamAPI_ISteamClient_BReleaseSteamPipe( ISteamClient* self, HSteamPipe hSteamPipe ); +S_API HSteamUser SteamAPI_ISteamClient_ConnectToGlobalUser( ISteamClient* self, HSteamPipe hSteamPipe ); +S_API HSteamUser SteamAPI_ISteamClient_CreateLocalUser( ISteamClient* self, HSteamPipe * phSteamPipe, EAccountType eAccountType ); +S_API void SteamAPI_ISteamClient_ReleaseUser( ISteamClient* self, HSteamPipe hSteamPipe, HSteamUser hUser ); +S_API ISteamUser * SteamAPI_ISteamClient_GetISteamUser( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamGameServer * SteamAPI_ISteamClient_GetISteamGameServer( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API void SteamAPI_ISteamClient_SetLocalIPBinding( ISteamClient* self, const SteamIPAddress_t & unIP, uint16 usPort ); +S_API ISteamFriends * SteamAPI_ISteamClient_GetISteamFriends( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamUtils * SteamAPI_ISteamClient_GetISteamUtils( ISteamClient* self, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamMatchmaking * SteamAPI_ISteamClient_GetISteamMatchmaking( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamMatchmakingServers * SteamAPI_ISteamClient_GetISteamMatchmakingServers( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API void * SteamAPI_ISteamClient_GetISteamGenericInterface( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamUserStats * SteamAPI_ISteamClient_GetISteamUserStats( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamGameServerStats * SteamAPI_ISteamClient_GetISteamGameServerStats( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamApps * SteamAPI_ISteamClient_GetISteamApps( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamNetworking * SteamAPI_ISteamClient_GetISteamNetworking( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamRemoteStorage * SteamAPI_ISteamClient_GetISteamRemoteStorage( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamScreenshots * SteamAPI_ISteamClient_GetISteamScreenshots( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamGameSearch * SteamAPI_ISteamClient_GetISteamGameSearch( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API uint32 SteamAPI_ISteamClient_GetIPCCallCount( ISteamClient* self ); +S_API void SteamAPI_ISteamClient_SetWarningMessageHook( ISteamClient* self, SteamAPIWarningMessageHook_t pFunction ); +S_API bool SteamAPI_ISteamClient_BShutdownIfAllPipesClosed( ISteamClient* self ); +S_API ISteamHTTP * SteamAPI_ISteamClient_GetISteamHTTP( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamController * SteamAPI_ISteamClient_GetISteamController( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamUGC * SteamAPI_ISteamClient_GetISteamUGC( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamAppList * SteamAPI_ISteamClient_GetISteamAppList( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamMusic * SteamAPI_ISteamClient_GetISteamMusic( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamMusicRemote * SteamAPI_ISteamClient_GetISteamMusicRemote( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamHTMLSurface * SteamAPI_ISteamClient_GetISteamHTMLSurface( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamInventory * SteamAPI_ISteamClient_GetISteamInventory( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamVideo * SteamAPI_ISteamClient_GetISteamVideo( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamParentalSettings * SteamAPI_ISteamClient_GetISteamParentalSettings( ISteamClient* self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamInput * SteamAPI_ISteamClient_GetISteamInput( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamParties * SteamAPI_ISteamClient_GetISteamParties( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); +S_API ISteamRemotePlay * SteamAPI_ISteamClient_GetISteamRemotePlay( ISteamClient* self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char * pchVersion ); + +// ISteamUser + +// A versioned accessor is exported by the library +S_API ISteamUser *SteamAPI_SteamUser_v023(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamUser(), but using this ensures that you are using a matching library. +inline ISteamUser *SteamAPI_SteamUser() { return SteamAPI_SteamUser_v023(); } +S_API HSteamUser SteamAPI_ISteamUser_GetHSteamUser( ISteamUser* self ); +S_API bool SteamAPI_ISteamUser_BLoggedOn( ISteamUser* self ); +S_API uint64_steamid SteamAPI_ISteamUser_GetSteamID( ISteamUser* self ); +S_API int SteamAPI_ISteamUser_InitiateGameConnection_DEPRECATED( ISteamUser* self, void * pAuthBlob, int cbMaxAuthBlob, uint64_steamid steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure ); +S_API void SteamAPI_ISteamUser_TerminateGameConnection_DEPRECATED( ISteamUser* self, uint32 unIPServer, uint16 usPortServer ); +S_API void SteamAPI_ISteamUser_TrackAppUsageEvent( ISteamUser* self, uint64_gameid gameID, int eAppUsageEvent, const char * pchExtraInfo ); +S_API bool SteamAPI_ISteamUser_GetUserDataFolder( ISteamUser* self, char * pchBuffer, int cubBuffer ); +S_API void SteamAPI_ISteamUser_StartVoiceRecording( ISteamUser* self ); +S_API void SteamAPI_ISteamUser_StopVoiceRecording( ISteamUser* self ); +S_API EVoiceResult SteamAPI_ISteamUser_GetAvailableVoice( ISteamUser* self, uint32 * pcbCompressed, uint32 * pcbUncompressed_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated ); +S_API EVoiceResult SteamAPI_ISteamUser_GetVoice( ISteamUser* self, 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( ISteamUser* self, const void * pCompressed, uint32 cbCompressed, void * pDestBuffer, uint32 cbDestBufferSize, uint32 * nBytesWritten, uint32 nDesiredSampleRate ); +S_API uint32 SteamAPI_ISteamUser_GetVoiceOptimalSampleRate( ISteamUser* self ); +S_API HAuthTicket SteamAPI_ISteamUser_GetAuthSessionTicket( ISteamUser* self, void * pTicket, int cbMaxTicket, uint32 * pcbTicket, const SteamNetworkingIdentity * pSteamNetworkingIdentity ); +S_API HAuthTicket SteamAPI_ISteamUser_GetAuthTicketForWebApi( ISteamUser* self, const char * pchIdentity ); +S_API EBeginAuthSessionResult SteamAPI_ISteamUser_BeginAuthSession( ISteamUser* self, const void * pAuthTicket, int cbAuthTicket, uint64_steamid steamID ); +S_API void SteamAPI_ISteamUser_EndAuthSession( ISteamUser* self, uint64_steamid steamID ); +S_API void SteamAPI_ISteamUser_CancelAuthTicket( ISteamUser* self, HAuthTicket hAuthTicket ); +S_API EUserHasLicenseForAppResult SteamAPI_ISteamUser_UserHasLicenseForApp( ISteamUser* self, uint64_steamid steamID, AppId_t appID ); +S_API bool SteamAPI_ISteamUser_BIsBehindNAT( ISteamUser* self ); +S_API void SteamAPI_ISteamUser_AdvertiseGame( ISteamUser* self, uint64_steamid steamIDGameServer, uint32 unIPServer, uint16 usPortServer ); +S_API SteamAPICall_t SteamAPI_ISteamUser_RequestEncryptedAppTicket( ISteamUser* self, void * pDataToInclude, int cbDataToInclude ); +S_API bool SteamAPI_ISteamUser_GetEncryptedAppTicket( ISteamUser* self, void * pTicket, int cbMaxTicket, uint32 * pcbTicket ); +S_API int SteamAPI_ISteamUser_GetGameBadgeLevel( ISteamUser* self, int nSeries, bool bFoil ); +S_API int SteamAPI_ISteamUser_GetPlayerSteamLevel( ISteamUser* self ); +S_API SteamAPICall_t SteamAPI_ISteamUser_RequestStoreAuthURL( ISteamUser* self, const char * pchRedirectURL ); +S_API bool SteamAPI_ISteamUser_BIsPhoneVerified( ISteamUser* self ); +S_API bool SteamAPI_ISteamUser_BIsTwoFactorEnabled( ISteamUser* self ); +S_API bool SteamAPI_ISteamUser_BIsPhoneIdentifying( ISteamUser* self ); +S_API bool SteamAPI_ISteamUser_BIsPhoneRequiringVerification( ISteamUser* self ); +S_API SteamAPICall_t SteamAPI_ISteamUser_GetMarketEligibility( ISteamUser* self ); +S_API SteamAPICall_t SteamAPI_ISteamUser_GetDurationControl( ISteamUser* self ); +S_API bool SteamAPI_ISteamUser_BSetDurationControlOnlineState( ISteamUser* self, EDurationControlOnlineState eNewState ); + +// ISteamFriends + +// A versioned accessor is exported by the library +S_API ISteamFriends *SteamAPI_SteamFriends_v017(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamFriends(), but using this ensures that you are using a matching library. +inline ISteamFriends *SteamAPI_SteamFriends() { return SteamAPI_SteamFriends_v017(); } +S_API const char * SteamAPI_ISteamFriends_GetPersonaName( ISteamFriends* self ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_SetPersonaName( ISteamFriends* self, const char * pchPersonaName ); +S_API EPersonaState SteamAPI_ISteamFriends_GetPersonaState( ISteamFriends* self ); +S_API int SteamAPI_ISteamFriends_GetFriendCount( ISteamFriends* self, int iFriendFlags ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetFriendByIndex( ISteamFriends* self, int iFriend, int iFriendFlags ); +S_API EFriendRelationship SteamAPI_ISteamFriends_GetFriendRelationship( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API EPersonaState SteamAPI_ISteamFriends_GetFriendPersonaState( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API const char * SteamAPI_ISteamFriends_GetFriendPersonaName( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API bool SteamAPI_ISteamFriends_GetFriendGamePlayed( ISteamFriends* self, uint64_steamid steamIDFriend, FriendGameInfo_t * pFriendGameInfo ); +S_API const char * SteamAPI_ISteamFriends_GetFriendPersonaNameHistory( ISteamFriends* self, uint64_steamid steamIDFriend, int iPersonaName ); +S_API int SteamAPI_ISteamFriends_GetFriendSteamLevel( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API const char * SteamAPI_ISteamFriends_GetPlayerNickname( ISteamFriends* self, uint64_steamid steamIDPlayer ); +S_API int SteamAPI_ISteamFriends_GetFriendsGroupCount( ISteamFriends* self ); +S_API FriendsGroupID_t SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex( ISteamFriends* self, int iFG ); +S_API const char * SteamAPI_ISteamFriends_GetFriendsGroupName( ISteamFriends* self, FriendsGroupID_t friendsGroupID ); +S_API int SteamAPI_ISteamFriends_GetFriendsGroupMembersCount( ISteamFriends* self, FriendsGroupID_t friendsGroupID ); +S_API void SteamAPI_ISteamFriends_GetFriendsGroupMembersList( ISteamFriends* self, FriendsGroupID_t friendsGroupID, CSteamID * pOutSteamIDMembers, int nMembersCount ); +S_API bool SteamAPI_ISteamFriends_HasFriend( ISteamFriends* self, uint64_steamid steamIDFriend, int iFriendFlags ); +S_API int SteamAPI_ISteamFriends_GetClanCount( ISteamFriends* self ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetClanByIndex( ISteamFriends* self, int iClan ); +S_API const char * SteamAPI_ISteamFriends_GetClanName( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API const char * SteamAPI_ISteamFriends_GetClanTag( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API bool SteamAPI_ISteamFriends_GetClanActivityCounts( ISteamFriends* self, uint64_steamid steamIDClan, int * pnOnline, int * pnInGame, int * pnChatting ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_DownloadClanActivityCounts( ISteamFriends* self, CSteamID * psteamIDClans, int cClansToRequest ); +S_API int SteamAPI_ISteamFriends_GetFriendCountFromSource( ISteamFriends* self, uint64_steamid steamIDSource ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetFriendFromSourceByIndex( ISteamFriends* self, uint64_steamid steamIDSource, int iFriend ); +S_API bool SteamAPI_ISteamFriends_IsUserInSource( ISteamFriends* self, uint64_steamid steamIDUser, uint64_steamid steamIDSource ); +S_API void SteamAPI_ISteamFriends_SetInGameVoiceSpeaking( ISteamFriends* self, uint64_steamid steamIDUser, bool bSpeaking ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlay( ISteamFriends* self, const char * pchDialog ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayToUser( ISteamFriends* self, const char * pchDialog, uint64_steamid steamID ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage( ISteamFriends* self, const char * pchURL, EActivateGameOverlayToWebPageMode eMode ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayToStore( ISteamFriends* self, AppId_t nAppID, EOverlayToStoreFlag eFlag ); +S_API void SteamAPI_ISteamFriends_SetPlayedWith( ISteamFriends* self, uint64_steamid steamIDUserPlayedWith ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialog( ISteamFriends* self, uint64_steamid steamIDLobby ); +S_API int SteamAPI_ISteamFriends_GetSmallFriendAvatar( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API int SteamAPI_ISteamFriends_GetMediumFriendAvatar( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API int SteamAPI_ISteamFriends_GetLargeFriendAvatar( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API bool SteamAPI_ISteamFriends_RequestUserInformation( ISteamFriends* self, uint64_steamid steamIDUser, bool bRequireNameOnly ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_RequestClanOfficerList( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetClanOwner( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API int SteamAPI_ISteamFriends_GetClanOfficerCount( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetClanOfficerByIndex( ISteamFriends* self, uint64_steamid steamIDClan, int iOfficer ); +S_API uint32 SteamAPI_ISteamFriends_GetUserRestrictions( ISteamFriends* self ); +S_API bool SteamAPI_ISteamFriends_SetRichPresence( ISteamFriends* self, const char * pchKey, const char * pchValue ); +S_API void SteamAPI_ISteamFriends_ClearRichPresence( ISteamFriends* self ); +S_API const char * SteamAPI_ISteamFriends_GetFriendRichPresence( ISteamFriends* self, uint64_steamid steamIDFriend, const char * pchKey ); +S_API int SteamAPI_ISteamFriends_GetFriendRichPresenceKeyCount( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API const char * SteamAPI_ISteamFriends_GetFriendRichPresenceKeyByIndex( ISteamFriends* self, uint64_steamid steamIDFriend, int iKey ); +S_API void SteamAPI_ISteamFriends_RequestFriendRichPresence( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API bool SteamAPI_ISteamFriends_InviteUserToGame( ISteamFriends* self, uint64_steamid steamIDFriend, const char * pchConnectString ); +S_API int SteamAPI_ISteamFriends_GetCoplayFriendCount( ISteamFriends* self ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetCoplayFriend( ISteamFriends* self, int iCoplayFriend ); +S_API int SteamAPI_ISteamFriends_GetFriendCoplayTime( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API AppId_t SteamAPI_ISteamFriends_GetFriendCoplayGame( ISteamFriends* self, uint64_steamid steamIDFriend ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_JoinClanChatRoom( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API bool SteamAPI_ISteamFriends_LeaveClanChatRoom( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API int SteamAPI_ISteamFriends_GetClanChatMemberCount( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API uint64_steamid SteamAPI_ISteamFriends_GetChatMemberByIndex( ISteamFriends* self, uint64_steamid steamIDClan, int iUser ); +S_API bool SteamAPI_ISteamFriends_SendClanChatMessage( ISteamFriends* self, uint64_steamid steamIDClanChat, const char * pchText ); +S_API int SteamAPI_ISteamFriends_GetClanChatMessage( ISteamFriends* self, uint64_steamid steamIDClanChat, int iMessage, void * prgchText, int cchTextMax, EChatEntryType * peChatEntryType, CSteamID * psteamidChatter ); +S_API bool SteamAPI_ISteamFriends_IsClanChatAdmin( ISteamFriends* self, uint64_steamid steamIDClanChat, uint64_steamid steamIDUser ); +S_API bool SteamAPI_ISteamFriends_IsClanChatWindowOpenInSteam( ISteamFriends* self, uint64_steamid steamIDClanChat ); +S_API bool SteamAPI_ISteamFriends_OpenClanChatWindowInSteam( ISteamFriends* self, uint64_steamid steamIDClanChat ); +S_API bool SteamAPI_ISteamFriends_CloseClanChatWindowInSteam( ISteamFriends* self, uint64_steamid steamIDClanChat ); +S_API bool SteamAPI_ISteamFriends_SetListenForFriendsMessages( ISteamFriends* self, bool bInterceptEnabled ); +S_API bool SteamAPI_ISteamFriends_ReplyToFriendMessage( ISteamFriends* self, uint64_steamid steamIDFriend, const char * pchMsgToSend ); +S_API int SteamAPI_ISteamFriends_GetFriendMessage( ISteamFriends* self, uint64_steamid steamIDFriend, int iMessageID, void * pvData, int cubData, EChatEntryType * peChatEntryType ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_GetFollowerCount( ISteamFriends* self, uint64_steamid steamID ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_IsFollowing( ISteamFriends* self, uint64_steamid steamID ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_EnumerateFollowingList( ISteamFriends* self, uint32 unStartIndex ); +S_API bool SteamAPI_ISteamFriends_IsClanPublic( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API bool SteamAPI_ISteamFriends_IsClanOfficialGameGroup( ISteamFriends* self, uint64_steamid steamIDClan ); +S_API int SteamAPI_ISteamFriends_GetNumChatsWithUnreadPriorityMessages( ISteamFriends* self ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayRemotePlayTogetherInviteDialog( ISteamFriends* self, uint64_steamid steamIDLobby ); +S_API bool SteamAPI_ISteamFriends_RegisterProtocolInOverlayBrowser( ISteamFriends* self, const char * pchProtocol ); +S_API void SteamAPI_ISteamFriends_ActivateGameOverlayInviteDialogConnectString( ISteamFriends* self, const char * pchConnectString ); +S_API SteamAPICall_t SteamAPI_ISteamFriends_RequestEquippedProfileItems( ISteamFriends* self, uint64_steamid steamID ); +S_API bool SteamAPI_ISteamFriends_BHasEquippedProfileItem( ISteamFriends* self, uint64_steamid steamID, ECommunityProfileItemType itemType ); +S_API const char * SteamAPI_ISteamFriends_GetProfileItemPropertyString( ISteamFriends* self, uint64_steamid steamID, ECommunityProfileItemType itemType, ECommunityProfileItemProperty prop ); +S_API uint32 SteamAPI_ISteamFriends_GetProfileItemPropertyUint( ISteamFriends* self, uint64_steamid steamID, ECommunityProfileItemType itemType, ECommunityProfileItemProperty prop ); + +// ISteamUtils + +// A versioned accessor is exported by the library +S_API ISteamUtils *SteamAPI_SteamUtils_v010(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamUtils(), but using this ensures that you are using a matching library. +inline ISteamUtils *SteamAPI_SteamUtils() { return SteamAPI_SteamUtils_v010(); } + +// A versioned accessor is exported by the library +S_API ISteamUtils *SteamAPI_SteamGameServerUtils_v010(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerUtils(), but using this ensures that you are using a matching library. +inline ISteamUtils *SteamAPI_SteamGameServerUtils() { return SteamAPI_SteamGameServerUtils_v010(); } +S_API uint32 SteamAPI_ISteamUtils_GetSecondsSinceAppActive( ISteamUtils* self ); +S_API uint32 SteamAPI_ISteamUtils_GetSecondsSinceComputerActive( ISteamUtils* self ); +S_API EUniverse SteamAPI_ISteamUtils_GetConnectedUniverse( ISteamUtils* self ); +S_API uint32 SteamAPI_ISteamUtils_GetServerRealTime( ISteamUtils* self ); +S_API const char * SteamAPI_ISteamUtils_GetIPCountry( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_GetImageSize( ISteamUtils* self, int iImage, uint32 * pnWidth, uint32 * pnHeight ); +S_API bool SteamAPI_ISteamUtils_GetImageRGBA( ISteamUtils* self, int iImage, uint8 * pubDest, int nDestBufferSize ); +S_API uint8 SteamAPI_ISteamUtils_GetCurrentBatteryPower( ISteamUtils* self ); +S_API uint32 SteamAPI_ISteamUtils_GetAppID( ISteamUtils* self ); +S_API void SteamAPI_ISteamUtils_SetOverlayNotificationPosition( ISteamUtils* self, ENotificationPosition eNotificationPosition ); +S_API bool SteamAPI_ISteamUtils_IsAPICallCompleted( ISteamUtils* self, SteamAPICall_t hSteamAPICall, bool * pbFailed ); +S_API ESteamAPICallFailure SteamAPI_ISteamUtils_GetAPICallFailureReason( ISteamUtils* self, SteamAPICall_t hSteamAPICall ); +S_API bool SteamAPI_ISteamUtils_GetAPICallResult( ISteamUtils* self, SteamAPICall_t hSteamAPICall, void * pCallback, int cubCallback, int iCallbackExpected, bool * pbFailed ); +S_API uint32 SteamAPI_ISteamUtils_GetIPCCallCount( ISteamUtils* self ); +S_API void SteamAPI_ISteamUtils_SetWarningMessageHook( ISteamUtils* self, SteamAPIWarningMessageHook_t pFunction ); +S_API bool SteamAPI_ISteamUtils_IsOverlayEnabled( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_BOverlayNeedsPresent( ISteamUtils* self ); +S_API SteamAPICall_t SteamAPI_ISteamUtils_CheckFileSignature( ISteamUtils* self, const char * szFileName ); +S_API bool SteamAPI_ISteamUtils_ShowGamepadTextInput( ISteamUtils* self, EGamepadTextInputMode eInputMode, EGamepadTextInputLineMode eLineInputMode, const char * pchDescription, uint32 unCharMax, const char * pchExistingText ); +S_API uint32 SteamAPI_ISteamUtils_GetEnteredGamepadTextLength( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_GetEnteredGamepadTextInput( ISteamUtils* self, char * pchText, uint32 cchText ); +S_API const char * SteamAPI_ISteamUtils_GetSteamUILanguage( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_IsSteamRunningInVR( ISteamUtils* self ); +S_API void SteamAPI_ISteamUtils_SetOverlayNotificationInset( ISteamUtils* self, int nHorizontalInset, int nVerticalInset ); +S_API bool SteamAPI_ISteamUtils_IsSteamInBigPictureMode( ISteamUtils* self ); +S_API void SteamAPI_ISteamUtils_StartVRDashboard( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_IsVRHeadsetStreamingEnabled( ISteamUtils* self ); +S_API void SteamAPI_ISteamUtils_SetVRHeadsetStreamingEnabled( ISteamUtils* self, bool bEnabled ); +S_API bool SteamAPI_ISteamUtils_IsSteamChinaLauncher( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_InitFilterText( ISteamUtils* self, uint32 unFilterOptions ); +S_API int SteamAPI_ISteamUtils_FilterText( ISteamUtils* self, ETextFilteringContext eContext, uint64_steamid sourceSteamID, const char * pchInputMessage, char * pchOutFilteredText, uint32 nByteSizeOutFilteredText ); +S_API ESteamIPv6ConnectivityState SteamAPI_ISteamUtils_GetIPv6ConnectivityState( ISteamUtils* self, ESteamIPv6ConnectivityProtocol eProtocol ); +S_API bool SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck( ISteamUtils* self ); +S_API bool SteamAPI_ISteamUtils_ShowFloatingGamepadTextInput( ISteamUtils* self, EFloatingGamepadTextInputMode eKeyboardMode, int nTextFieldXPosition, int nTextFieldYPosition, int nTextFieldWidth, int nTextFieldHeight ); +S_API void SteamAPI_ISteamUtils_SetGameLauncherMode( ISteamUtils* self, bool bLauncherMode ); +S_API bool SteamAPI_ISteamUtils_DismissFloatingGamepadTextInput( ISteamUtils* self ); + +// ISteamMatchmaking + +// A versioned accessor is exported by the library +S_API ISteamMatchmaking *SteamAPI_SteamMatchmaking_v009(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamMatchmaking(), but using this ensures that you are using a matching library. +inline ISteamMatchmaking *SteamAPI_SteamMatchmaking() { return SteamAPI_SteamMatchmaking_v009(); } +S_API int SteamAPI_ISteamMatchmaking_GetFavoriteGameCount( ISteamMatchmaking* self ); +S_API bool SteamAPI_ISteamMatchmaking_GetFavoriteGame( ISteamMatchmaking* self, int iGame, AppId_t * pnAppID, uint32 * pnIP, uint16 * pnConnPort, uint16 * pnQueryPort, uint32 * punFlags, uint32 * pRTime32LastPlayedOnServer ); +S_API int SteamAPI_ISteamMatchmaking_AddFavoriteGame( ISteamMatchmaking* self, AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags, uint32 rTime32LastPlayedOnServer ); +S_API bool SteamAPI_ISteamMatchmaking_RemoveFavoriteGame( ISteamMatchmaking* self, AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags ); +S_API SteamAPICall_t SteamAPI_ISteamMatchmaking_RequestLobbyList( ISteamMatchmaking* self ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListStringFilter( ISteamMatchmaking* self, const char * pchKeyToMatch, const char * pchValueToMatch, ELobbyComparison eComparisonType ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListNumericalFilter( ISteamMatchmaking* self, const char * pchKeyToMatch, int nValueToMatch, ELobbyComparison eComparisonType ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListNearValueFilter( ISteamMatchmaking* self, const char * pchKeyToMatch, int nValueToBeCloseTo ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListFilterSlotsAvailable( ISteamMatchmaking* self, int nSlotsAvailable ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListDistanceFilter( ISteamMatchmaking* self, ELobbyDistanceFilter eLobbyDistanceFilter ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListResultCountFilter( ISteamMatchmaking* self, int cMaxResults ); +S_API void SteamAPI_ISteamMatchmaking_AddRequestLobbyListCompatibleMembersFilter( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API uint64_steamid SteamAPI_ISteamMatchmaking_GetLobbyByIndex( ISteamMatchmaking* self, int iLobby ); +S_API SteamAPICall_t SteamAPI_ISteamMatchmaking_CreateLobby( ISteamMatchmaking* self, ELobbyType eLobbyType, int cMaxMembers ); +S_API SteamAPICall_t SteamAPI_ISteamMatchmaking_JoinLobby( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API void SteamAPI_ISteamMatchmaking_LeaveLobby( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API bool SteamAPI_ISteamMatchmaking_InviteUserToLobby( ISteamMatchmaking* self, uint64_steamid steamIDLobby, uint64_steamid steamIDInvitee ); +S_API int SteamAPI_ISteamMatchmaking_GetNumLobbyMembers( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API uint64_steamid SteamAPI_ISteamMatchmaking_GetLobbyMemberByIndex( ISteamMatchmaking* self, uint64_steamid steamIDLobby, int iMember ); +S_API const char * SteamAPI_ISteamMatchmaking_GetLobbyData( ISteamMatchmaking* self, uint64_steamid steamIDLobby, const char * pchKey ); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyData( ISteamMatchmaking* self, uint64_steamid steamIDLobby, const char * pchKey, const char * pchValue ); +S_API int SteamAPI_ISteamMatchmaking_GetLobbyDataCount( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API bool SteamAPI_ISteamMatchmaking_GetLobbyDataByIndex( ISteamMatchmaking* self, uint64_steamid steamIDLobby, int iLobbyData, char * pchKey, int cchKeyBufferSize, char * pchValue, int cchValueBufferSize ); +S_API bool SteamAPI_ISteamMatchmaking_DeleteLobbyData( ISteamMatchmaking* self, uint64_steamid steamIDLobby, const char * pchKey ); +S_API const char * SteamAPI_ISteamMatchmaking_GetLobbyMemberData( ISteamMatchmaking* self, uint64_steamid steamIDLobby, uint64_steamid steamIDUser, const char * pchKey ); +S_API void SteamAPI_ISteamMatchmaking_SetLobbyMemberData( ISteamMatchmaking* self, uint64_steamid steamIDLobby, const char * pchKey, const char * pchValue ); +S_API bool SteamAPI_ISteamMatchmaking_SendLobbyChatMsg( ISteamMatchmaking* self, uint64_steamid steamIDLobby, const void * pvMsgBody, int cubMsgBody ); +S_API int SteamAPI_ISteamMatchmaking_GetLobbyChatEntry( ISteamMatchmaking* self, uint64_steamid steamIDLobby, int iChatID, CSteamID * pSteamIDUser, void * pvData, int cubData, EChatEntryType * peChatEntryType ); +S_API bool SteamAPI_ISteamMatchmaking_RequestLobbyData( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API void SteamAPI_ISteamMatchmaking_SetLobbyGameServer( ISteamMatchmaking* self, uint64_steamid steamIDLobby, uint32 unGameServerIP, uint16 unGameServerPort, uint64_steamid steamIDGameServer ); +S_API bool SteamAPI_ISteamMatchmaking_GetLobbyGameServer( ISteamMatchmaking* self, uint64_steamid steamIDLobby, uint32 * punGameServerIP, uint16 * punGameServerPort, CSteamID * psteamIDGameServer ); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyMemberLimit( ISteamMatchmaking* self, uint64_steamid steamIDLobby, int cMaxMembers ); +S_API int SteamAPI_ISteamMatchmaking_GetLobbyMemberLimit( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyType( ISteamMatchmaking* self, uint64_steamid steamIDLobby, ELobbyType eLobbyType ); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyJoinable( ISteamMatchmaking* self, uint64_steamid steamIDLobby, bool bLobbyJoinable ); +S_API uint64_steamid SteamAPI_ISteamMatchmaking_GetLobbyOwner( ISteamMatchmaking* self, uint64_steamid steamIDLobby ); +S_API bool SteamAPI_ISteamMatchmaking_SetLobbyOwner( ISteamMatchmaking* self, uint64_steamid steamIDLobby, uint64_steamid steamIDNewOwner ); +S_API bool SteamAPI_ISteamMatchmaking_SetLinkedLobby( ISteamMatchmaking* self, uint64_steamid steamIDLobby, uint64_steamid steamIDLobbyDependent ); + +// ISteamMatchmakingServerListResponse +S_API void SteamAPI_ISteamMatchmakingServerListResponse_ServerResponded( ISteamMatchmakingServerListResponse* self, HServerListRequest hRequest, int iServer ); +S_API void SteamAPI_ISteamMatchmakingServerListResponse_ServerFailedToRespond( ISteamMatchmakingServerListResponse* self, HServerListRequest hRequest, int iServer ); +S_API void SteamAPI_ISteamMatchmakingServerListResponse_RefreshComplete( ISteamMatchmakingServerListResponse* self, HServerListRequest hRequest, EMatchMakingServerResponse response ); + +// ISteamMatchmakingPingResponse +S_API void SteamAPI_ISteamMatchmakingPingResponse_ServerResponded( ISteamMatchmakingPingResponse* self, gameserveritem_t & server ); +S_API void SteamAPI_ISteamMatchmakingPingResponse_ServerFailedToRespond( ISteamMatchmakingPingResponse* self ); + +// ISteamMatchmakingPlayersResponse +S_API void SteamAPI_ISteamMatchmakingPlayersResponse_AddPlayerToList( ISteamMatchmakingPlayersResponse* self, const char * pchName, int nScore, float flTimePlayed ); +S_API void SteamAPI_ISteamMatchmakingPlayersResponse_PlayersFailedToRespond( ISteamMatchmakingPlayersResponse* self ); +S_API void SteamAPI_ISteamMatchmakingPlayersResponse_PlayersRefreshComplete( ISteamMatchmakingPlayersResponse* self ); + +// ISteamMatchmakingRulesResponse +S_API void SteamAPI_ISteamMatchmakingRulesResponse_RulesResponded( ISteamMatchmakingRulesResponse* self, const char * pchRule, const char * pchValue ); +S_API void SteamAPI_ISteamMatchmakingRulesResponse_RulesFailedToRespond( ISteamMatchmakingRulesResponse* self ); +S_API void SteamAPI_ISteamMatchmakingRulesResponse_RulesRefreshComplete( ISteamMatchmakingRulesResponse* self ); + +// ISteamMatchmakingServers + +// A versioned accessor is exported by the library +S_API ISteamMatchmakingServers *SteamAPI_SteamMatchmakingServers_v002(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamMatchmakingServers(), but using this ensures that you are using a matching library. +inline ISteamMatchmakingServers *SteamAPI_SteamMatchmakingServers() { return SteamAPI_SteamMatchmakingServers_v002(); } +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestInternetServerList( ISteamMatchmakingServers* self, AppId_t iApp, MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse * pRequestServersResponse ); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestLANServerList( ISteamMatchmakingServers* self, AppId_t iApp, ISteamMatchmakingServerListResponse * pRequestServersResponse ); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestFriendsServerList( ISteamMatchmakingServers* self, AppId_t iApp, MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse * pRequestServersResponse ); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestFavoritesServerList( ISteamMatchmakingServers* self, AppId_t iApp, MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse * pRequestServersResponse ); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestHistoryServerList( ISteamMatchmakingServers* self, AppId_t iApp, MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse * pRequestServersResponse ); +S_API HServerListRequest SteamAPI_ISteamMatchmakingServers_RequestSpectatorServerList( ISteamMatchmakingServers* self, AppId_t iApp, MatchMakingKeyValuePair_t ** ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse * pRequestServersResponse ); +S_API void SteamAPI_ISteamMatchmakingServers_ReleaseRequest( ISteamMatchmakingServers* self, HServerListRequest hServerListRequest ); +S_API gameserveritem_t * SteamAPI_ISteamMatchmakingServers_GetServerDetails( ISteamMatchmakingServers* self, HServerListRequest hRequest, int iServer ); +S_API void SteamAPI_ISteamMatchmakingServers_CancelQuery( ISteamMatchmakingServers* self, HServerListRequest hRequest ); +S_API void SteamAPI_ISteamMatchmakingServers_RefreshQuery( ISteamMatchmakingServers* self, HServerListRequest hRequest ); +S_API bool SteamAPI_ISteamMatchmakingServers_IsRefreshing( ISteamMatchmakingServers* self, HServerListRequest hRequest ); +S_API int SteamAPI_ISteamMatchmakingServers_GetServerCount( ISteamMatchmakingServers* self, HServerListRequest hRequest ); +S_API void SteamAPI_ISteamMatchmakingServers_RefreshServer( ISteamMatchmakingServers* self, HServerListRequest hRequest, int iServer ); +S_API HServerQuery SteamAPI_ISteamMatchmakingServers_PingServer( ISteamMatchmakingServers* self, uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse * pRequestServersResponse ); +S_API HServerQuery SteamAPI_ISteamMatchmakingServers_PlayerDetails( ISteamMatchmakingServers* self, uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse * pRequestServersResponse ); +S_API HServerQuery SteamAPI_ISteamMatchmakingServers_ServerRules( ISteamMatchmakingServers* self, uint32 unIP, uint16 usPort, ISteamMatchmakingRulesResponse * pRequestServersResponse ); +S_API void SteamAPI_ISteamMatchmakingServers_CancelServerQuery( ISteamMatchmakingServers* self, HServerQuery hServerQuery ); + +// ISteamGameSearch + +// A versioned accessor is exported by the library +S_API ISteamGameSearch *SteamAPI_SteamGameSearch_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameSearch(), but using this ensures that you are using a matching library. +inline ISteamGameSearch *SteamAPI_SteamGameSearch() { return SteamAPI_SteamGameSearch_v001(); } +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_AddGameSearchParams( ISteamGameSearch* self, const char * pchKeyToFind, const char * pchValuesToFind ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SearchForGameWithLobby( ISteamGameSearch* self, uint64_steamid steamIDLobby, int nPlayerMin, int nPlayerMax ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SearchForGameSolo( ISteamGameSearch* self, int nPlayerMin, int nPlayerMax ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_AcceptGame( ISteamGameSearch* self ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_DeclineGame( ISteamGameSearch* self ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_RetrieveConnectionDetails( ISteamGameSearch* self, uint64_steamid steamIDHost, char * pchConnectionDetails, int cubConnectionDetails ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_EndGameSearch( ISteamGameSearch* self ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SetGameHostParams( ISteamGameSearch* self, const char * pchKey, const char * pchValue ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SetConnectionDetails( ISteamGameSearch* self, const char * pchConnectionDetails, int cubConnectionDetails ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_RequestPlayersForGame( ISteamGameSearch* self, int nPlayerMin, int nPlayerMax, int nMaxTeamSize ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_HostConfirmGameStart( ISteamGameSearch* self, uint64 ullUniqueGameID ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_CancelRequestPlayersForGame( ISteamGameSearch* self ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_SubmitPlayerResult( ISteamGameSearch* self, uint64 ullUniqueGameID, uint64_steamid steamIDPlayer, EPlayerResult_t EPlayerResult ); +S_API EGameSearchErrorCode_t SteamAPI_ISteamGameSearch_EndGame( ISteamGameSearch* self, uint64 ullUniqueGameID ); + +// ISteamParties + +// A versioned accessor is exported by the library +S_API ISteamParties *SteamAPI_SteamParties_v002(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamParties(), but using this ensures that you are using a matching library. +inline ISteamParties *SteamAPI_SteamParties() { return SteamAPI_SteamParties_v002(); } +S_API uint32 SteamAPI_ISteamParties_GetNumActiveBeacons( ISteamParties* self ); +S_API PartyBeaconID_t SteamAPI_ISteamParties_GetBeaconByIndex( ISteamParties* self, uint32 unIndex ); +S_API bool SteamAPI_ISteamParties_GetBeaconDetails( ISteamParties* self, PartyBeaconID_t ulBeaconID, CSteamID * pSteamIDBeaconOwner, SteamPartyBeaconLocation_t * pLocation, char * pchMetadata, int cchMetadata ); +S_API SteamAPICall_t SteamAPI_ISteamParties_JoinParty( ISteamParties* self, PartyBeaconID_t ulBeaconID ); +S_API bool SteamAPI_ISteamParties_GetNumAvailableBeaconLocations( ISteamParties* self, uint32 * puNumLocations ); +S_API bool SteamAPI_ISteamParties_GetAvailableBeaconLocations( ISteamParties* self, SteamPartyBeaconLocation_t * pLocationList, uint32 uMaxNumLocations ); +S_API SteamAPICall_t SteamAPI_ISteamParties_CreateBeacon( ISteamParties* self, uint32 unOpenSlots, SteamPartyBeaconLocation_t * pBeaconLocation, const char * pchConnectString, const char * pchMetadata ); +S_API void SteamAPI_ISteamParties_OnReservationCompleted( ISteamParties* self, PartyBeaconID_t ulBeacon, uint64_steamid steamIDUser ); +S_API void SteamAPI_ISteamParties_CancelReservation( ISteamParties* self, PartyBeaconID_t ulBeacon, uint64_steamid steamIDUser ); +S_API SteamAPICall_t SteamAPI_ISteamParties_ChangeNumOpenSlots( ISteamParties* self, PartyBeaconID_t ulBeacon, uint32 unOpenSlots ); +S_API bool SteamAPI_ISteamParties_DestroyBeacon( ISteamParties* self, PartyBeaconID_t ulBeacon ); +S_API bool SteamAPI_ISteamParties_GetBeaconLocationData( ISteamParties* self, SteamPartyBeaconLocation_t BeaconLocation, ESteamPartyBeaconLocationData eData, char * pchDataStringOut, int cchDataStringOut ); + +// ISteamRemoteStorage + +// A versioned accessor is exported by the library +S_API ISteamRemoteStorage *SteamAPI_SteamRemoteStorage_v016(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamRemoteStorage(), but using this ensures that you are using a matching library. +inline ISteamRemoteStorage *SteamAPI_SteamRemoteStorage() { return SteamAPI_SteamRemoteStorage_v016(); } +S_API bool SteamAPI_ISteamRemoteStorage_FileWrite( ISteamRemoteStorage* self, const char * pchFile, const void * pvData, int32 cubData ); +S_API int32 SteamAPI_ISteamRemoteStorage_FileRead( ISteamRemoteStorage* self, const char * pchFile, void * pvData, int32 cubDataToRead ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_FileWriteAsync( ISteamRemoteStorage* self, const char * pchFile, const void * pvData, uint32 cubData ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_FileReadAsync( ISteamRemoteStorage* self, const char * pchFile, uint32 nOffset, uint32 cubToRead ); +S_API bool SteamAPI_ISteamRemoteStorage_FileReadAsyncComplete( ISteamRemoteStorage* self, SteamAPICall_t hReadCall, void * pvBuffer, uint32 cubToRead ); +S_API bool SteamAPI_ISteamRemoteStorage_FileForget( ISteamRemoteStorage* self, const char * pchFile ); +S_API bool SteamAPI_ISteamRemoteStorage_FileDelete( ISteamRemoteStorage* self, const char * pchFile ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_FileShare( ISteamRemoteStorage* self, const char * pchFile ); +S_API bool SteamAPI_ISteamRemoteStorage_SetSyncPlatforms( ISteamRemoteStorage* self, const char * pchFile, ERemoteStoragePlatform eRemoteStoragePlatform ); +S_API UGCFileWriteStreamHandle_t SteamAPI_ISteamRemoteStorage_FileWriteStreamOpen( ISteamRemoteStorage* self, const char * pchFile ); +S_API bool SteamAPI_ISteamRemoteStorage_FileWriteStreamWriteChunk( ISteamRemoteStorage* self, UGCFileWriteStreamHandle_t writeHandle, const void * pvData, int32 cubData ); +S_API bool SteamAPI_ISteamRemoteStorage_FileWriteStreamClose( ISteamRemoteStorage* self, UGCFileWriteStreamHandle_t writeHandle ); +S_API bool SteamAPI_ISteamRemoteStorage_FileWriteStreamCancel( ISteamRemoteStorage* self, UGCFileWriteStreamHandle_t writeHandle ); +S_API bool SteamAPI_ISteamRemoteStorage_FileExists( ISteamRemoteStorage* self, const char * pchFile ); +S_API bool SteamAPI_ISteamRemoteStorage_FilePersisted( ISteamRemoteStorage* self, const char * pchFile ); +S_API int32 SteamAPI_ISteamRemoteStorage_GetFileSize( ISteamRemoteStorage* self, const char * pchFile ); +S_API int64 SteamAPI_ISteamRemoteStorage_GetFileTimestamp( ISteamRemoteStorage* self, const char * pchFile ); +S_API ERemoteStoragePlatform SteamAPI_ISteamRemoteStorage_GetSyncPlatforms( ISteamRemoteStorage* self, const char * pchFile ); +S_API int32 SteamAPI_ISteamRemoteStorage_GetFileCount( ISteamRemoteStorage* self ); +S_API const char * SteamAPI_ISteamRemoteStorage_GetFileNameAndSize( ISteamRemoteStorage* self, int iFile, int32 * pnFileSizeInBytes ); +S_API bool SteamAPI_ISteamRemoteStorage_GetQuota( ISteamRemoteStorage* self, uint64 * pnTotalBytes, uint64 * puAvailableBytes ); +S_API bool SteamAPI_ISteamRemoteStorage_IsCloudEnabledForAccount( ISteamRemoteStorage* self ); +S_API bool SteamAPI_ISteamRemoteStorage_IsCloudEnabledForApp( ISteamRemoteStorage* self ); +S_API void SteamAPI_ISteamRemoteStorage_SetCloudEnabledForApp( ISteamRemoteStorage* self, bool bEnabled ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UGCDownload( ISteamRemoteStorage* self, UGCHandle_t hContent, uint32 unPriority ); +S_API bool SteamAPI_ISteamRemoteStorage_GetUGCDownloadProgress( ISteamRemoteStorage* self, UGCHandle_t hContent, int32 * pnBytesDownloaded, int32 * pnBytesExpected ); +S_API bool SteamAPI_ISteamRemoteStorage_GetUGCDetails( ISteamRemoteStorage* self, UGCHandle_t hContent, AppId_t * pnAppID, char ** ppchName, int32 * pnFileSizeInBytes, CSteamID * pSteamIDOwner ); +S_API int32 SteamAPI_ISteamRemoteStorage_UGCRead( ISteamRemoteStorage* self, UGCHandle_t hContent, void * pvData, int32 cubDataToRead, uint32 cOffset, EUGCReadAction eAction ); +S_API int32 SteamAPI_ISteamRemoteStorage_GetCachedUGCCount( ISteamRemoteStorage* self ); +S_API UGCHandle_t SteamAPI_ISteamRemoteStorage_GetCachedUGCHandle( ISteamRemoteStorage* self, int32 iCachedContent ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_PublishWorkshopFile( ISteamRemoteStorage* self, const char * pchFile, const char * pchPreviewFile, AppId_t nConsumerAppId, const char * pchTitle, const char * pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t * pTags, EWorkshopFileType eWorkshopFileType ); +S_API PublishedFileUpdateHandle_t SteamAPI_ISteamRemoteStorage_CreatePublishedFileUpdateRequest( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileFile( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, const char * pchFile ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFilePreviewFile( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, const char * pchPreviewFile ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTitle( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, const char * pchTitle ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileDescription( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, const char * pchDescription ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileVisibility( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, ERemoteStoragePublishedFileVisibility eVisibility ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileTags( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, SteamParamStringArray_t * pTags ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_CommitPublishedFileUpdate( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_GetPublishedFileDetails( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_DeletePublishedFile( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumerateUserPublishedFiles( ISteamRemoteStorage* self, uint32 unStartIndex ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_SubscribePublishedFile( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumerateUserSubscribedFiles( ISteamRemoteStorage* self, uint32 unStartIndex ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UnsubscribePublishedFile( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId ); +S_API bool SteamAPI_ISteamRemoteStorage_UpdatePublishedFileSetChangeDescription( ISteamRemoteStorage* self, PublishedFileUpdateHandle_t updateHandle, const char * pchChangeDescription ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_GetPublishedItemVoteDetails( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UpdateUserPublishedItemVote( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId, bool bVoteUp ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_GetUserPublishedItemVoteDetails( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumerateUserSharedWorkshopFiles( ISteamRemoteStorage* self, uint64_steamid steamId, uint32 unStartIndex, SteamParamStringArray_t * pRequiredTags, SteamParamStringArray_t * pExcludedTags ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_PublishVideo( ISteamRemoteStorage* self, 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 ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_SetUserPublishedFileAction( ISteamRemoteStorage* self, PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumeratePublishedFilesByUserAction( ISteamRemoteStorage* self, EWorkshopFileAction eAction, uint32 unStartIndex ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_EnumeratePublishedWorkshopFiles( ISteamRemoteStorage* self, EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, SteamParamStringArray_t * pTags, SteamParamStringArray_t * pUserTags ); +S_API SteamAPICall_t SteamAPI_ISteamRemoteStorage_UGCDownloadToLocation( ISteamRemoteStorage* self, UGCHandle_t hContent, const char * pchLocation, uint32 unPriority ); +S_API int32 SteamAPI_ISteamRemoteStorage_GetLocalFileChangeCount( ISteamRemoteStorage* self ); +S_API const char * SteamAPI_ISteamRemoteStorage_GetLocalFileChange( ISteamRemoteStorage* self, int iFile, ERemoteStorageLocalFileChange * pEChangeType, ERemoteStorageFilePathType * pEFilePathType ); +S_API bool SteamAPI_ISteamRemoteStorage_BeginFileWriteBatch( ISteamRemoteStorage* self ); +S_API bool SteamAPI_ISteamRemoteStorage_EndFileWriteBatch( ISteamRemoteStorage* self ); + +// ISteamUserStats + +// A versioned accessor is exported by the library +S_API ISteamUserStats *SteamAPI_SteamUserStats_v012(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamUserStats(), but using this ensures that you are using a matching library. +inline ISteamUserStats *SteamAPI_SteamUserStats() { return SteamAPI_SteamUserStats_v012(); } +S_API bool SteamAPI_ISteamUserStats_RequestCurrentStats( ISteamUserStats* self ); +S_API bool SteamAPI_ISteamUserStats_GetStatInt32( ISteamUserStats* self, const char * pchName, int32 * pData ); +S_API bool SteamAPI_ISteamUserStats_GetStatFloat( ISteamUserStats* self, const char * pchName, float * pData ); +S_API bool SteamAPI_ISteamUserStats_SetStatInt32( ISteamUserStats* self, const char * pchName, int32 nData ); +S_API bool SteamAPI_ISteamUserStats_SetStatFloat( ISteamUserStats* self, const char * pchName, float fData ); +S_API bool SteamAPI_ISteamUserStats_UpdateAvgRateStat( ISteamUserStats* self, const char * pchName, float flCountThisSession, double dSessionLength ); +S_API bool SteamAPI_ISteamUserStats_GetAchievement( ISteamUserStats* self, const char * pchName, bool * pbAchieved ); +S_API bool SteamAPI_ISteamUserStats_SetAchievement( ISteamUserStats* self, const char * pchName ); +S_API bool SteamAPI_ISteamUserStats_ClearAchievement( ISteamUserStats* self, const char * pchName ); +S_API bool SteamAPI_ISteamUserStats_GetAchievementAndUnlockTime( ISteamUserStats* self, const char * pchName, bool * pbAchieved, uint32 * punUnlockTime ); +S_API bool SteamAPI_ISteamUserStats_StoreStats( ISteamUserStats* self ); +S_API int SteamAPI_ISteamUserStats_GetAchievementIcon( ISteamUserStats* self, const char * pchName ); +S_API const char * SteamAPI_ISteamUserStats_GetAchievementDisplayAttribute( ISteamUserStats* self, const char * pchName, const char * pchKey ); +S_API bool SteamAPI_ISteamUserStats_IndicateAchievementProgress( ISteamUserStats* self, const char * pchName, uint32 nCurProgress, uint32 nMaxProgress ); +S_API uint32 SteamAPI_ISteamUserStats_GetNumAchievements( ISteamUserStats* self ); +S_API const char * SteamAPI_ISteamUserStats_GetAchievementName( ISteamUserStats* self, uint32 iAchievement ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_RequestUserStats( ISteamUserStats* self, uint64_steamid steamIDUser ); +S_API bool SteamAPI_ISteamUserStats_GetUserStatInt32( ISteamUserStats* self, uint64_steamid steamIDUser, const char * pchName, int32 * pData ); +S_API bool SteamAPI_ISteamUserStats_GetUserStatFloat( ISteamUserStats* self, uint64_steamid steamIDUser, const char * pchName, float * pData ); +S_API bool SteamAPI_ISteamUserStats_GetUserAchievement( ISteamUserStats* self, uint64_steamid steamIDUser, const char * pchName, bool * pbAchieved ); +S_API bool SteamAPI_ISteamUserStats_GetUserAchievementAndUnlockTime( ISteamUserStats* self, uint64_steamid steamIDUser, const char * pchName, bool * pbAchieved, uint32 * punUnlockTime ); +S_API bool SteamAPI_ISteamUserStats_ResetAllStats( ISteamUserStats* self, bool bAchievementsToo ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_FindOrCreateLeaderboard( ISteamUserStats* self, const char * pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_FindLeaderboard( ISteamUserStats* self, const char * pchLeaderboardName ); +S_API const char * SteamAPI_ISteamUserStats_GetLeaderboardName( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard ); +S_API int SteamAPI_ISteamUserStats_GetLeaderboardEntryCount( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard ); +S_API ELeaderboardSortMethod SteamAPI_ISteamUserStats_GetLeaderboardSortMethod( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard ); +S_API ELeaderboardDisplayType SteamAPI_ISteamUserStats_GetLeaderboardDisplayType( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_DownloadLeaderboardEntries( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, ELeaderboardDataRequest eLeaderboardDataRequest, int nRangeStart, int nRangeEnd ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, CSteamID * prgUsers, int cUsers ); +S_API bool SteamAPI_ISteamUserStats_GetDownloadedLeaderboardEntry( ISteamUserStats* self, SteamLeaderboardEntries_t hSteamLeaderboardEntries, int index, LeaderboardEntry_t * pLeaderboardEntry, int32 * pDetails, int cDetailsMax ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_UploadLeaderboardScore( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32 * pScoreDetails, int cScoreDetailsCount ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_AttachLeaderboardUGC( ISteamUserStats* self, SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers( ISteamUserStats* self ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_RequestGlobalAchievementPercentages( ISteamUserStats* self ); +S_API int SteamAPI_ISteamUserStats_GetMostAchievedAchievementInfo( ISteamUserStats* self, char * pchName, uint32 unNameBufLen, float * pflPercent, bool * pbAchieved ); +S_API int SteamAPI_ISteamUserStats_GetNextMostAchievedAchievementInfo( ISteamUserStats* self, int iIteratorPrevious, char * pchName, uint32 unNameBufLen, float * pflPercent, bool * pbAchieved ); +S_API bool SteamAPI_ISteamUserStats_GetAchievementAchievedPercent( ISteamUserStats* self, const char * pchName, float * pflPercent ); +S_API SteamAPICall_t SteamAPI_ISteamUserStats_RequestGlobalStats( ISteamUserStats* self, int nHistoryDays ); +S_API bool SteamAPI_ISteamUserStats_GetGlobalStatInt64( ISteamUserStats* self, const char * pchStatName, int64 * pData ); +S_API bool SteamAPI_ISteamUserStats_GetGlobalStatDouble( ISteamUserStats* self, const char * pchStatName, double * pData ); +S_API int32 SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64( ISteamUserStats* self, const char * pchStatName, int64 * pData, uint32 cubData ); +S_API int32 SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble( ISteamUserStats* self, const char * pchStatName, double * pData, uint32 cubData ); +S_API bool SteamAPI_ISteamUserStats_GetAchievementProgressLimitsInt32( ISteamUserStats* self, const char * pchName, int32 * pnMinProgress, int32 * pnMaxProgress ); +S_API bool SteamAPI_ISteamUserStats_GetAchievementProgressLimitsFloat( ISteamUserStats* self, const char * pchName, float * pfMinProgress, float * pfMaxProgress ); + +// ISteamApps + +// A versioned accessor is exported by the library +S_API ISteamApps *SteamAPI_SteamApps_v008(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamApps(), but using this ensures that you are using a matching library. +inline ISteamApps *SteamAPI_SteamApps() { return SteamAPI_SteamApps_v008(); } +S_API bool SteamAPI_ISteamApps_BIsSubscribed( ISteamApps* self ); +S_API bool SteamAPI_ISteamApps_BIsLowViolence( ISteamApps* self ); +S_API bool SteamAPI_ISteamApps_BIsCybercafe( ISteamApps* self ); +S_API bool SteamAPI_ISteamApps_BIsVACBanned( ISteamApps* self ); +S_API const char * SteamAPI_ISteamApps_GetCurrentGameLanguage( ISteamApps* self ); +S_API const char * SteamAPI_ISteamApps_GetAvailableGameLanguages( ISteamApps* self ); +S_API bool SteamAPI_ISteamApps_BIsSubscribedApp( ISteamApps* self, AppId_t appID ); +S_API bool SteamAPI_ISteamApps_BIsDlcInstalled( ISteamApps* self, AppId_t appID ); +S_API uint32 SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime( ISteamApps* self, AppId_t nAppID ); +S_API bool SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend( ISteamApps* self ); +S_API int SteamAPI_ISteamApps_GetDLCCount( ISteamApps* self ); +S_API bool SteamAPI_ISteamApps_BGetDLCDataByIndex( ISteamApps* self, int iDLC, AppId_t * pAppID, bool * pbAvailable, char * pchName, int cchNameBufferSize ); +S_API void SteamAPI_ISteamApps_InstallDLC( ISteamApps* self, AppId_t nAppID ); +S_API void SteamAPI_ISteamApps_UninstallDLC( ISteamApps* self, AppId_t nAppID ); +S_API void SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey( ISteamApps* self, AppId_t nAppID ); +S_API bool SteamAPI_ISteamApps_GetCurrentBetaName( ISteamApps* self, char * pchName, int cchNameBufferSize ); +S_API bool SteamAPI_ISteamApps_MarkContentCorrupt( ISteamApps* self, bool bMissingFilesOnly ); +S_API uint32 SteamAPI_ISteamApps_GetInstalledDepots( ISteamApps* self, AppId_t appID, DepotId_t * pvecDepots, uint32 cMaxDepots ); +S_API uint32 SteamAPI_ISteamApps_GetAppInstallDir( ISteamApps* self, AppId_t appID, char * pchFolder, uint32 cchFolderBufferSize ); +S_API bool SteamAPI_ISteamApps_BIsAppInstalled( ISteamApps* self, AppId_t appID ); +S_API uint64_steamid SteamAPI_ISteamApps_GetAppOwner( ISteamApps* self ); +S_API const char * SteamAPI_ISteamApps_GetLaunchQueryParam( ISteamApps* self, const char * pchKey ); +S_API bool SteamAPI_ISteamApps_GetDlcDownloadProgress( ISteamApps* self, AppId_t nAppID, uint64 * punBytesDownloaded, uint64 * punBytesTotal ); +S_API int SteamAPI_ISteamApps_GetAppBuildId( ISteamApps* self ); +S_API void SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys( ISteamApps* self ); +S_API SteamAPICall_t SteamAPI_ISteamApps_GetFileDetails( ISteamApps* self, const char * pszFileName ); +S_API int SteamAPI_ISteamApps_GetLaunchCommandLine( ISteamApps* self, char * pszCommandLine, int cubCommandLine ); +S_API bool SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing( ISteamApps* self ); +S_API bool SteamAPI_ISteamApps_BIsTimedTrial( ISteamApps* self, uint32 * punSecondsAllowed, uint32 * punSecondsPlayed ); +S_API bool SteamAPI_ISteamApps_SetDlcContext( ISteamApps* self, AppId_t nAppID ); + +// ISteamNetworking + +// A versioned accessor is exported by the library +S_API ISteamNetworking *SteamAPI_SteamNetworking_v006(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamNetworking(), but using this ensures that you are using a matching library. +inline ISteamNetworking *SteamAPI_SteamNetworking() { return SteamAPI_SteamNetworking_v006(); } + +// A versioned accessor is exported by the library +S_API ISteamNetworking *SteamAPI_SteamGameServerNetworking_v006(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerNetworking(), but using this ensures that you are using a matching library. +inline ISteamNetworking *SteamAPI_SteamGameServerNetworking() { return SteamAPI_SteamGameServerNetworking_v006(); } +S_API bool SteamAPI_ISteamNetworking_SendP2PPacket( ISteamNetworking* self, uint64_steamid steamIDRemote, const void * pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel ); +S_API bool SteamAPI_ISteamNetworking_IsP2PPacketAvailable( ISteamNetworking* self, uint32 * pcubMsgSize, int nChannel ); +S_API bool SteamAPI_ISteamNetworking_ReadP2PPacket( ISteamNetworking* self, void * pubDest, uint32 cubDest, uint32 * pcubMsgSize, CSteamID * psteamIDRemote, int nChannel ); +S_API bool SteamAPI_ISteamNetworking_AcceptP2PSessionWithUser( ISteamNetworking* self, uint64_steamid steamIDRemote ); +S_API bool SteamAPI_ISteamNetworking_CloseP2PSessionWithUser( ISteamNetworking* self, uint64_steamid steamIDRemote ); +S_API bool SteamAPI_ISteamNetworking_CloseP2PChannelWithUser( ISteamNetworking* self, uint64_steamid steamIDRemote, int nChannel ); +S_API bool SteamAPI_ISteamNetworking_GetP2PSessionState( ISteamNetworking* self, uint64_steamid steamIDRemote, P2PSessionState_t * pConnectionState ); +S_API bool SteamAPI_ISteamNetworking_AllowP2PPacketRelay( ISteamNetworking* self, bool bAllow ); +S_API SNetListenSocket_t SteamAPI_ISteamNetworking_CreateListenSocket( ISteamNetworking* self, int nVirtualP2PPort, SteamIPAddress_t nIP, uint16 nPort, bool bAllowUseOfPacketRelay ); +S_API SNetSocket_t SteamAPI_ISteamNetworking_CreateP2PConnectionSocket( ISteamNetworking* self, uint64_steamid steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay ); +S_API SNetSocket_t SteamAPI_ISteamNetworking_CreateConnectionSocket( ISteamNetworking* self, SteamIPAddress_t nIP, uint16 nPort, int nTimeoutSec ); +S_API bool SteamAPI_ISteamNetworking_DestroySocket( ISteamNetworking* self, SNetSocket_t hSocket, bool bNotifyRemoteEnd ); +S_API bool SteamAPI_ISteamNetworking_DestroyListenSocket( ISteamNetworking* self, SNetListenSocket_t hSocket, bool bNotifyRemoteEnd ); +S_API bool SteamAPI_ISteamNetworking_SendDataOnSocket( ISteamNetworking* self, SNetSocket_t hSocket, void * pubData, uint32 cubData, bool bReliable ); +S_API bool SteamAPI_ISteamNetworking_IsDataAvailableOnSocket( ISteamNetworking* self, SNetSocket_t hSocket, uint32 * pcubMsgSize ); +S_API bool SteamAPI_ISteamNetworking_RetrieveDataFromSocket( ISteamNetworking* self, SNetSocket_t hSocket, void * pubDest, uint32 cubDest, uint32 * pcubMsgSize ); +S_API bool SteamAPI_ISteamNetworking_IsDataAvailable( ISteamNetworking* self, SNetListenSocket_t hListenSocket, uint32 * pcubMsgSize, SNetSocket_t * phSocket ); +S_API bool SteamAPI_ISteamNetworking_RetrieveData( ISteamNetworking* self, SNetListenSocket_t hListenSocket, void * pubDest, uint32 cubDest, uint32 * pcubMsgSize, SNetSocket_t * phSocket ); +S_API bool SteamAPI_ISteamNetworking_GetSocketInfo( ISteamNetworking* self, SNetSocket_t hSocket, CSteamID * pSteamIDRemote, int * peSocketStatus, SteamIPAddress_t * punIPRemote, uint16 * punPortRemote ); +S_API bool SteamAPI_ISteamNetworking_GetListenSocketInfo( ISteamNetworking* self, SNetListenSocket_t hListenSocket, SteamIPAddress_t * pnIP, uint16 * pnPort ); +S_API ESNetSocketConnectionType SteamAPI_ISteamNetworking_GetSocketConnectionType( ISteamNetworking* self, SNetSocket_t hSocket ); +S_API int SteamAPI_ISteamNetworking_GetMaxPacketSize( ISteamNetworking* self, SNetSocket_t hSocket ); + +// ISteamScreenshots + +// A versioned accessor is exported by the library +S_API ISteamScreenshots *SteamAPI_SteamScreenshots_v003(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamScreenshots(), but using this ensures that you are using a matching library. +inline ISteamScreenshots *SteamAPI_SteamScreenshots() { return SteamAPI_SteamScreenshots_v003(); } +S_API ScreenshotHandle SteamAPI_ISteamScreenshots_WriteScreenshot( ISteamScreenshots* self, void * pubRGB, uint32 cubRGB, int nWidth, int nHeight ); +S_API ScreenshotHandle SteamAPI_ISteamScreenshots_AddScreenshotToLibrary( ISteamScreenshots* self, const char * pchFilename, const char * pchThumbnailFilename, int nWidth, int nHeight ); +S_API void SteamAPI_ISteamScreenshots_TriggerScreenshot( ISteamScreenshots* self ); +S_API void SteamAPI_ISteamScreenshots_HookScreenshots( ISteamScreenshots* self, bool bHook ); +S_API bool SteamAPI_ISteamScreenshots_SetLocation( ISteamScreenshots* self, ScreenshotHandle hScreenshot, const char * pchLocation ); +S_API bool SteamAPI_ISteamScreenshots_TagUser( ISteamScreenshots* self, ScreenshotHandle hScreenshot, uint64_steamid steamID ); +S_API bool SteamAPI_ISteamScreenshots_TagPublishedFile( ISteamScreenshots* self, ScreenshotHandle hScreenshot, PublishedFileId_t unPublishedFileID ); +S_API bool SteamAPI_ISteamScreenshots_IsScreenshotsHooked( ISteamScreenshots* self ); +S_API ScreenshotHandle SteamAPI_ISteamScreenshots_AddVRScreenshotToLibrary( ISteamScreenshots* self, EVRScreenshotType eType, const char * pchFilename, const char * pchVRFilename ); + +// ISteamMusic + +// A versioned accessor is exported by the library +S_API ISteamMusic *SteamAPI_SteamMusic_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamMusic(), but using this ensures that you are using a matching library. +inline ISteamMusic *SteamAPI_SteamMusic() { return SteamAPI_SteamMusic_v001(); } +S_API bool SteamAPI_ISteamMusic_BIsEnabled( ISteamMusic* self ); +S_API bool SteamAPI_ISteamMusic_BIsPlaying( ISteamMusic* self ); +S_API AudioPlayback_Status SteamAPI_ISteamMusic_GetPlaybackStatus( ISteamMusic* self ); +S_API void SteamAPI_ISteamMusic_Play( ISteamMusic* self ); +S_API void SteamAPI_ISteamMusic_Pause( ISteamMusic* self ); +S_API void SteamAPI_ISteamMusic_PlayPrevious( ISteamMusic* self ); +S_API void SteamAPI_ISteamMusic_PlayNext( ISteamMusic* self ); +S_API void SteamAPI_ISteamMusic_SetVolume( ISteamMusic* self, float flVolume ); +S_API float SteamAPI_ISteamMusic_GetVolume( ISteamMusic* self ); + +// ISteamMusicRemote + +// A versioned accessor is exported by the library +S_API ISteamMusicRemote *SteamAPI_SteamMusicRemote_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamMusicRemote(), but using this ensures that you are using a matching library. +inline ISteamMusicRemote *SteamAPI_SteamMusicRemote() { return SteamAPI_SteamMusicRemote_v001(); } +S_API bool SteamAPI_ISteamMusicRemote_RegisterSteamMusicRemote( ISteamMusicRemote* self, const char * pchName ); +S_API bool SteamAPI_ISteamMusicRemote_DeregisterSteamMusicRemote( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_BIsCurrentMusicRemote( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_BActivationSuccess( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_SetDisplayName( ISteamMusicRemote* self, const char * pchDisplayName ); +S_API bool SteamAPI_ISteamMusicRemote_SetPNGIcon_64x64( ISteamMusicRemote* self, void * pvBuffer, uint32 cbBufferLength ); +S_API bool SteamAPI_ISteamMusicRemote_EnablePlayPrevious( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_EnablePlayNext( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_EnableShuffled( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_EnableLooped( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_EnableQueue( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_EnablePlaylists( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_UpdatePlaybackStatus( ISteamMusicRemote* self, AudioPlayback_Status nStatus ); +S_API bool SteamAPI_ISteamMusicRemote_UpdateShuffled( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_UpdateLooped( ISteamMusicRemote* self, bool bValue ); +S_API bool SteamAPI_ISteamMusicRemote_UpdateVolume( ISteamMusicRemote* self, float flValue ); +S_API bool SteamAPI_ISteamMusicRemote_CurrentEntryWillChange( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_CurrentEntryIsAvailable( ISteamMusicRemote* self, bool bAvailable ); +S_API bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryText( ISteamMusicRemote* self, const char * pchText ); +S_API bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryElapsedSeconds( ISteamMusicRemote* self, int nValue ); +S_API bool SteamAPI_ISteamMusicRemote_UpdateCurrentEntryCoverArt( ISteamMusicRemote* self, void * pvBuffer, uint32 cbBufferLength ); +S_API bool SteamAPI_ISteamMusicRemote_CurrentEntryDidChange( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_QueueWillChange( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_ResetQueueEntries( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_SetQueueEntry( ISteamMusicRemote* self, int nID, int nPosition, const char * pchEntryText ); +S_API bool SteamAPI_ISteamMusicRemote_SetCurrentQueueEntry( ISteamMusicRemote* self, int nID ); +S_API bool SteamAPI_ISteamMusicRemote_QueueDidChange( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_PlaylistWillChange( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_ResetPlaylistEntries( ISteamMusicRemote* self ); +S_API bool SteamAPI_ISteamMusicRemote_SetPlaylistEntry( ISteamMusicRemote* self, int nID, int nPosition, const char * pchEntryText ); +S_API bool SteamAPI_ISteamMusicRemote_SetCurrentPlaylistEntry( ISteamMusicRemote* self, int nID ); +S_API bool SteamAPI_ISteamMusicRemote_PlaylistDidChange( ISteamMusicRemote* self ); + +// ISteamHTTP + +// A versioned accessor is exported by the library +S_API ISteamHTTP *SteamAPI_SteamHTTP_v003(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamHTTP(), but using this ensures that you are using a matching library. +inline ISteamHTTP *SteamAPI_SteamHTTP() { return SteamAPI_SteamHTTP_v003(); } + +// A versioned accessor is exported by the library +S_API ISteamHTTP *SteamAPI_SteamGameServerHTTP_v003(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerHTTP(), but using this ensures that you are using a matching library. +inline ISteamHTTP *SteamAPI_SteamGameServerHTTP() { return SteamAPI_SteamGameServerHTTP_v003(); } +S_API HTTPRequestHandle SteamAPI_ISteamHTTP_CreateHTTPRequest( ISteamHTTP* self, EHTTPMethod eHTTPRequestMethod, const char * pchAbsoluteURL ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestContextValue( ISteamHTTP* self, HTTPRequestHandle hRequest, uint64 ulContextValue ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestNetworkActivityTimeout( ISteamHTTP* self, HTTPRequestHandle hRequest, uint32 unTimeoutSeconds ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestHeaderValue( ISteamHTTP* self, HTTPRequestHandle hRequest, const char * pchHeaderName, const char * pchHeaderValue ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestGetOrPostParameter( ISteamHTTP* self, HTTPRequestHandle hRequest, const char * pchParamName, const char * pchParamValue ); +S_API bool SteamAPI_ISteamHTTP_SendHTTPRequest( ISteamHTTP* self, HTTPRequestHandle hRequest, SteamAPICall_t * pCallHandle ); +S_API bool SteamAPI_ISteamHTTP_SendHTTPRequestAndStreamResponse( ISteamHTTP* self, HTTPRequestHandle hRequest, SteamAPICall_t * pCallHandle ); +S_API bool SteamAPI_ISteamHTTP_DeferHTTPRequest( ISteamHTTP* self, HTTPRequestHandle hRequest ); +S_API bool SteamAPI_ISteamHTTP_PrioritizeHTTPRequest( ISteamHTTP* self, HTTPRequestHandle hRequest ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseHeaderSize( ISteamHTTP* self, HTTPRequestHandle hRequest, const char * pchHeaderName, uint32 * unResponseHeaderSize ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseHeaderValue( ISteamHTTP* self, HTTPRequestHandle hRequest, const char * pchHeaderName, uint8 * pHeaderValueBuffer, uint32 unBufferSize ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseBodySize( ISteamHTTP* self, HTTPRequestHandle hRequest, uint32 * unBodySize ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPResponseBodyData( ISteamHTTP* self, HTTPRequestHandle hRequest, uint8 * pBodyDataBuffer, uint32 unBufferSize ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPStreamingResponseBodyData( ISteamHTTP* self, HTTPRequestHandle hRequest, uint32 cOffset, uint8 * pBodyDataBuffer, uint32 unBufferSize ); +S_API bool SteamAPI_ISteamHTTP_ReleaseHTTPRequest( ISteamHTTP* self, HTTPRequestHandle hRequest ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPDownloadProgressPct( ISteamHTTP* self, HTTPRequestHandle hRequest, float * pflPercentOut ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestRawPostBody( ISteamHTTP* self, HTTPRequestHandle hRequest, const char * pchContentType, uint8 * pubBody, uint32 unBodyLen ); +S_API HTTPCookieContainerHandle SteamAPI_ISteamHTTP_CreateCookieContainer( ISteamHTTP* self, bool bAllowResponsesToModify ); +S_API bool SteamAPI_ISteamHTTP_ReleaseCookieContainer( ISteamHTTP* self, HTTPCookieContainerHandle hCookieContainer ); +S_API bool SteamAPI_ISteamHTTP_SetCookie( ISteamHTTP* self, HTTPCookieContainerHandle hCookieContainer, const char * pchHost, const char * pchUrl, const char * pchCookie ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestCookieContainer( ISteamHTTP* self, HTTPRequestHandle hRequest, HTTPCookieContainerHandle hCookieContainer ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestUserAgentInfo( ISteamHTTP* self, HTTPRequestHandle hRequest, const char * pchUserAgentInfo ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestRequiresVerifiedCertificate( ISteamHTTP* self, HTTPRequestHandle hRequest, bool bRequireVerifiedCertificate ); +S_API bool SteamAPI_ISteamHTTP_SetHTTPRequestAbsoluteTimeoutMS( ISteamHTTP* self, HTTPRequestHandle hRequest, uint32 unMilliseconds ); +S_API bool SteamAPI_ISteamHTTP_GetHTTPRequestWasTimedOut( ISteamHTTP* self, HTTPRequestHandle hRequest, bool * pbWasTimedOut ); + +// ISteamInput + +// A versioned accessor is exported by the library +S_API ISteamInput *SteamAPI_SteamInput_v006(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamInput(), but using this ensures that you are using a matching library. +inline ISteamInput *SteamAPI_SteamInput() { return SteamAPI_SteamInput_v006(); } +S_API bool SteamAPI_ISteamInput_Init( ISteamInput* self, bool bExplicitlyCallRunFrame ); +S_API bool SteamAPI_ISteamInput_Shutdown( ISteamInput* self ); +S_API bool SteamAPI_ISteamInput_SetInputActionManifestFilePath( ISteamInput* self, const char * pchInputActionManifestAbsolutePath ); +S_API void SteamAPI_ISteamInput_RunFrame( ISteamInput* self, bool bReservedValue ); +S_API bool SteamAPI_ISteamInput_BWaitForData( ISteamInput* self, bool bWaitForever, uint32 unTimeout ); +S_API bool SteamAPI_ISteamInput_BNewDataAvailable( ISteamInput* self ); +S_API int SteamAPI_ISteamInput_GetConnectedControllers( ISteamInput* self, InputHandle_t * handlesOut ); +S_API void SteamAPI_ISteamInput_EnableDeviceCallbacks( ISteamInput* self ); +S_API void SteamAPI_ISteamInput_EnableActionEventCallbacks( ISteamInput* self, SteamInputActionEventCallbackPointer pCallback ); +S_API InputActionSetHandle_t SteamAPI_ISteamInput_GetActionSetHandle( ISteamInput* self, const char * pszActionSetName ); +S_API void SteamAPI_ISteamInput_ActivateActionSet( ISteamInput* self, InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle ); +S_API InputActionSetHandle_t SteamAPI_ISteamInput_GetCurrentActionSet( ISteamInput* self, InputHandle_t inputHandle ); +S_API void SteamAPI_ISteamInput_ActivateActionSetLayer( ISteamInput* self, InputHandle_t inputHandle, InputActionSetHandle_t actionSetLayerHandle ); +S_API void SteamAPI_ISteamInput_DeactivateActionSetLayer( ISteamInput* self, InputHandle_t inputHandle, InputActionSetHandle_t actionSetLayerHandle ); +S_API void SteamAPI_ISteamInput_DeactivateAllActionSetLayers( ISteamInput* self, InputHandle_t inputHandle ); +S_API int SteamAPI_ISteamInput_GetActiveActionSetLayers( ISteamInput* self, InputHandle_t inputHandle, InputActionSetHandle_t * handlesOut ); +S_API InputDigitalActionHandle_t SteamAPI_ISteamInput_GetDigitalActionHandle( ISteamInput* self, const char * pszActionName ); +S_API InputDigitalActionData_t SteamAPI_ISteamInput_GetDigitalActionData( ISteamInput* self, InputHandle_t inputHandle, InputDigitalActionHandle_t digitalActionHandle ); +S_API int SteamAPI_ISteamInput_GetDigitalActionOrigins( ISteamInput* self, InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputDigitalActionHandle_t digitalActionHandle, EInputActionOrigin * originsOut ); +S_API const char * SteamAPI_ISteamInput_GetStringForDigitalActionName( ISteamInput* self, InputDigitalActionHandle_t eActionHandle ); +S_API InputAnalogActionHandle_t SteamAPI_ISteamInput_GetAnalogActionHandle( ISteamInput* self, const char * pszActionName ); +S_API InputAnalogActionData_t SteamAPI_ISteamInput_GetAnalogActionData( ISteamInput* self, InputHandle_t inputHandle, InputAnalogActionHandle_t analogActionHandle ); +S_API int SteamAPI_ISteamInput_GetAnalogActionOrigins( ISteamInput* self, InputHandle_t inputHandle, InputActionSetHandle_t actionSetHandle, InputAnalogActionHandle_t analogActionHandle, EInputActionOrigin * originsOut ); +S_API const char * SteamAPI_ISteamInput_GetGlyphPNGForActionOrigin( ISteamInput* self, EInputActionOrigin eOrigin, ESteamInputGlyphSize eSize, uint32 unFlags ); +S_API const char * SteamAPI_ISteamInput_GetGlyphSVGForActionOrigin( ISteamInput* self, EInputActionOrigin eOrigin, uint32 unFlags ); +S_API const char * SteamAPI_ISteamInput_GetGlyphForActionOrigin_Legacy( ISteamInput* self, EInputActionOrigin eOrigin ); +S_API const char * SteamAPI_ISteamInput_GetStringForActionOrigin( ISteamInput* self, EInputActionOrigin eOrigin ); +S_API const char * SteamAPI_ISteamInput_GetStringForAnalogActionName( ISteamInput* self, InputAnalogActionHandle_t eActionHandle ); +S_API void SteamAPI_ISteamInput_StopAnalogActionMomentum( ISteamInput* self, InputHandle_t inputHandle, InputAnalogActionHandle_t eAction ); +S_API InputMotionData_t SteamAPI_ISteamInput_GetMotionData( ISteamInput* self, InputHandle_t inputHandle ); +S_API void SteamAPI_ISteamInput_TriggerVibration( ISteamInput* self, InputHandle_t inputHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed ); +S_API void SteamAPI_ISteamInput_TriggerVibrationExtended( ISteamInput* self, InputHandle_t inputHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed, unsigned short usLeftTriggerSpeed, unsigned short usRightTriggerSpeed ); +S_API void SteamAPI_ISteamInput_TriggerSimpleHapticEvent( ISteamInput* self, InputHandle_t inputHandle, EControllerHapticLocation eHapticLocation, uint8 nIntensity, char nGainDB, uint8 nOtherIntensity, char nOtherGainDB ); +S_API void SteamAPI_ISteamInput_SetLEDColor( ISteamInput* self, InputHandle_t inputHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags ); +S_API void SteamAPI_ISteamInput_Legacy_TriggerHapticPulse( ISteamInput* self, InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ); +S_API void SteamAPI_ISteamInput_Legacy_TriggerRepeatedHapticPulse( ISteamInput* self, InputHandle_t inputHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ); +S_API bool SteamAPI_ISteamInput_ShowBindingPanel( ISteamInput* self, InputHandle_t inputHandle ); +S_API ESteamInputType SteamAPI_ISteamInput_GetInputTypeForHandle( ISteamInput* self, InputHandle_t inputHandle ); +S_API InputHandle_t SteamAPI_ISteamInput_GetControllerForGamepadIndex( ISteamInput* self, int nIndex ); +S_API int SteamAPI_ISteamInput_GetGamepadIndexForController( ISteamInput* self, InputHandle_t ulinputHandle ); +S_API const char * SteamAPI_ISteamInput_GetStringForXboxOrigin( ISteamInput* self, EXboxOrigin eOrigin ); +S_API const char * SteamAPI_ISteamInput_GetGlyphForXboxOrigin( ISteamInput* self, EXboxOrigin eOrigin ); +S_API EInputActionOrigin SteamAPI_ISteamInput_GetActionOriginFromXboxOrigin( ISteamInput* self, InputHandle_t inputHandle, EXboxOrigin eOrigin ); +S_API EInputActionOrigin SteamAPI_ISteamInput_TranslateActionOrigin( ISteamInput* self, ESteamInputType eDestinationInputType, EInputActionOrigin eSourceOrigin ); +S_API bool SteamAPI_ISteamInput_GetDeviceBindingRevision( ISteamInput* self, InputHandle_t inputHandle, int * pMajor, int * pMinor ); +S_API uint32 SteamAPI_ISteamInput_GetRemotePlaySessionID( ISteamInput* self, InputHandle_t inputHandle ); +S_API uint16 SteamAPI_ISteamInput_GetSessionInputConfigurationSettings( ISteamInput* self ); +S_API void SteamAPI_ISteamInput_SetDualSenseTriggerEffect( ISteamInput* self, InputHandle_t inputHandle, const ScePadTriggerEffectParam * pParam ); + +// ISteamController + +// A versioned accessor is exported by the library +S_API ISteamController *SteamAPI_SteamController_v008(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamController(), but using this ensures that you are using a matching library. +inline ISteamController *SteamAPI_SteamController() { return SteamAPI_SteamController_v008(); } +S_API bool SteamAPI_ISteamController_Init( ISteamController* self ); +S_API bool SteamAPI_ISteamController_Shutdown( ISteamController* self ); +S_API void SteamAPI_ISteamController_RunFrame( ISteamController* self ); +S_API int SteamAPI_ISteamController_GetConnectedControllers( ISteamController* self, ControllerHandle_t * handlesOut ); +S_API ControllerActionSetHandle_t SteamAPI_ISteamController_GetActionSetHandle( ISteamController* self, const char * pszActionSetName ); +S_API void SteamAPI_ISteamController_ActivateActionSet( ISteamController* self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle ); +S_API ControllerActionSetHandle_t SteamAPI_ISteamController_GetCurrentActionSet( ISteamController* self, ControllerHandle_t controllerHandle ); +S_API void SteamAPI_ISteamController_ActivateActionSetLayer( ISteamController* self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ); +S_API void SteamAPI_ISteamController_DeactivateActionSetLayer( ISteamController* self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle ); +S_API void SteamAPI_ISteamController_DeactivateAllActionSetLayers( ISteamController* self, ControllerHandle_t controllerHandle ); +S_API int SteamAPI_ISteamController_GetActiveActionSetLayers( ISteamController* self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t * handlesOut ); +S_API ControllerDigitalActionHandle_t SteamAPI_ISteamController_GetDigitalActionHandle( ISteamController* self, const char * pszActionName ); +S_API InputDigitalActionData_t SteamAPI_ISteamController_GetDigitalActionData( ISteamController* self, ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle ); +S_API int SteamAPI_ISteamController_GetDigitalActionOrigins( ISteamController* self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, EControllerActionOrigin * originsOut ); +S_API ControllerAnalogActionHandle_t SteamAPI_ISteamController_GetAnalogActionHandle( ISteamController* self, const char * pszActionName ); +S_API InputAnalogActionData_t SteamAPI_ISteamController_GetAnalogActionData( ISteamController* self, ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle ); +S_API int SteamAPI_ISteamController_GetAnalogActionOrigins( ISteamController* self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, EControllerActionOrigin * originsOut ); +S_API const char * SteamAPI_ISteamController_GetGlyphForActionOrigin( ISteamController* self, EControllerActionOrigin eOrigin ); +S_API const char * SteamAPI_ISteamController_GetStringForActionOrigin( ISteamController* self, EControllerActionOrigin eOrigin ); +S_API void SteamAPI_ISteamController_StopAnalogActionMomentum( ISteamController* self, ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction ); +S_API InputMotionData_t SteamAPI_ISteamController_GetMotionData( ISteamController* self, ControllerHandle_t controllerHandle ); +S_API void SteamAPI_ISteamController_TriggerHapticPulse( ISteamController* self, ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec ); +S_API void SteamAPI_ISteamController_TriggerRepeatedHapticPulse( ISteamController* self, ControllerHandle_t controllerHandle, ESteamControllerPad eTargetPad, unsigned short usDurationMicroSec, unsigned short usOffMicroSec, unsigned short unRepeat, unsigned int nFlags ); +S_API void SteamAPI_ISteamController_TriggerVibration( ISteamController* self, ControllerHandle_t controllerHandle, unsigned short usLeftSpeed, unsigned short usRightSpeed ); +S_API void SteamAPI_ISteamController_SetLEDColor( ISteamController* self, ControllerHandle_t controllerHandle, uint8 nColorR, uint8 nColorG, uint8 nColorB, unsigned int nFlags ); +S_API bool SteamAPI_ISteamController_ShowBindingPanel( ISteamController* self, ControllerHandle_t controllerHandle ); +S_API ESteamInputType SteamAPI_ISteamController_GetInputTypeForHandle( ISteamController* self, ControllerHandle_t controllerHandle ); +S_API ControllerHandle_t SteamAPI_ISteamController_GetControllerForGamepadIndex( ISteamController* self, int nIndex ); +S_API int SteamAPI_ISteamController_GetGamepadIndexForController( ISteamController* self, ControllerHandle_t ulControllerHandle ); +S_API const char * SteamAPI_ISteamController_GetStringForXboxOrigin( ISteamController* self, EXboxOrigin eOrigin ); +S_API const char * SteamAPI_ISteamController_GetGlyphForXboxOrigin( ISteamController* self, EXboxOrigin eOrigin ); +S_API EControllerActionOrigin SteamAPI_ISteamController_GetActionOriginFromXboxOrigin( ISteamController* self, ControllerHandle_t controllerHandle, EXboxOrigin eOrigin ); +S_API EControllerActionOrigin SteamAPI_ISteamController_TranslateActionOrigin( ISteamController* self, ESteamInputType eDestinationInputType, EControllerActionOrigin eSourceOrigin ); +S_API bool SteamAPI_ISteamController_GetControllerBindingRevision( ISteamController* self, ControllerHandle_t controllerHandle, int * pMajor, int * pMinor ); + +// ISteamUGC + +// A versioned accessor is exported by the library +S_API ISteamUGC *SteamAPI_SteamUGC_v017(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamUGC(), but using this ensures that you are using a matching library. +inline ISteamUGC *SteamAPI_SteamUGC() { return SteamAPI_SteamUGC_v017(); } + +// A versioned accessor is exported by the library +S_API ISteamUGC *SteamAPI_SteamGameServerUGC_v017(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerUGC(), but using this ensures that you are using a matching library. +inline ISteamUGC *SteamAPI_SteamGameServerUGC() { return SteamAPI_SteamGameServerUGC_v017(); } +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryUserUGCRequest( ISteamUGC* self, AccountID_t unAccountID, EUserUGCList eListType, EUGCMatchingUGCType eMatchingUGCType, EUserUGCListSortOrder eSortOrder, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryAllUGCRequestPage( ISteamUGC* self, EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, uint32 unPage ); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryAllUGCRequestCursor( ISteamUGC* self, EUGCQuery eQueryType, EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, AppId_t nCreatorAppID, AppId_t nConsumerAppID, const char * pchCursor ); +S_API UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest( ISteamUGC* self, PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SendQueryUGCRequest( ISteamUGC* self, UGCQueryHandle_t handle ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCResult( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t * pDetails ); +S_API uint32 SteamAPI_ISteamUGC_GetQueryUGCNumTags( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCTag( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, uint32 indexTag, char * pchValue, uint32 cchValueSize ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCTagDisplayName( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, uint32 indexTag, char * pchValue, uint32 cchValueSize ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCPreviewURL( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, char * pchURL, uint32 cchURLSize ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCMetadata( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, char * pchMetadata, uint32 cchMetadatasize ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCChildren( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, PublishedFileId_t * pvecPublishedFileID, uint32 cMaxEntries ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCStatistic( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, EItemStatistic eStatType, uint64 * pStatValue ); +S_API uint32 SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, char * pchURLOrVideoID, uint32 cchURLSize, char * pchOriginalFileName, uint32 cchOriginalFileNameSize, EItemPreviewType * pPreviewType ); +S_API uint32 SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index ); +S_API bool SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, uint32 keyValueTagIndex, char * pchKey, uint32 cchKeySize, char * pchValue, uint32 cchValueSize ); +S_API bool SteamAPI_ISteamUGC_GetQueryFirstUGCKeyValueTag( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, const char * pchKey, char * pchValue, uint32 cchValueSize ); +S_API uint32 SteamAPI_ISteamUGC_GetQueryUGCContentDescriptors( ISteamUGC* self, UGCQueryHandle_t handle, uint32 index, EUGCContentDescriptorID * pvecDescriptors, uint32 cMaxEntries ); +S_API bool SteamAPI_ISteamUGC_ReleaseQueryUGCRequest( ISteamUGC* self, UGCQueryHandle_t handle ); +S_API bool SteamAPI_ISteamUGC_AddRequiredTag( ISteamUGC* self, UGCQueryHandle_t handle, const char * pTagName ); +S_API bool SteamAPI_ISteamUGC_AddRequiredTagGroup( ISteamUGC* self, UGCQueryHandle_t handle, const SteamParamStringArray_t * pTagGroups ); +S_API bool SteamAPI_ISteamUGC_AddExcludedTag( ISteamUGC* self, UGCQueryHandle_t handle, const char * pTagName ); +S_API bool SteamAPI_ISteamUGC_SetReturnOnlyIDs( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnOnlyIDs ); +S_API bool SteamAPI_ISteamUGC_SetReturnKeyValueTags( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnKeyValueTags ); +S_API bool SteamAPI_ISteamUGC_SetReturnLongDescription( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnLongDescription ); +S_API bool SteamAPI_ISteamUGC_SetReturnMetadata( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnMetadata ); +S_API bool SteamAPI_ISteamUGC_SetReturnChildren( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnChildren ); +S_API bool SteamAPI_ISteamUGC_SetReturnAdditionalPreviews( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnAdditionalPreviews ); +S_API bool SteamAPI_ISteamUGC_SetReturnTotalOnly( ISteamUGC* self, UGCQueryHandle_t handle, bool bReturnTotalOnly ); +S_API bool SteamAPI_ISteamUGC_SetReturnPlaytimeStats( ISteamUGC* self, UGCQueryHandle_t handle, uint32 unDays ); +S_API bool SteamAPI_ISteamUGC_SetLanguage( ISteamUGC* self, UGCQueryHandle_t handle, const char * pchLanguage ); +S_API bool SteamAPI_ISteamUGC_SetAllowCachedResponse( ISteamUGC* self, UGCQueryHandle_t handle, uint32 unMaxAgeSeconds ); +S_API bool SteamAPI_ISteamUGC_SetCloudFileNameFilter( ISteamUGC* self, UGCQueryHandle_t handle, const char * pMatchCloudFileName ); +S_API bool SteamAPI_ISteamUGC_SetMatchAnyTag( ISteamUGC* self, UGCQueryHandle_t handle, bool bMatchAnyTag ); +S_API bool SteamAPI_ISteamUGC_SetSearchText( ISteamUGC* self, UGCQueryHandle_t handle, const char * pSearchText ); +S_API bool SteamAPI_ISteamUGC_SetRankedByTrendDays( ISteamUGC* self, UGCQueryHandle_t handle, uint32 unDays ); +S_API bool SteamAPI_ISteamUGC_SetTimeCreatedDateRange( ISteamUGC* self, UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd ); +S_API bool SteamAPI_ISteamUGC_SetTimeUpdatedDateRange( ISteamUGC* self, UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd ); +S_API bool SteamAPI_ISteamUGC_AddRequiredKeyValueTag( ISteamUGC* self, UGCQueryHandle_t handle, const char * pKey, const char * pValue ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RequestUGCDetails( ISteamUGC* self, PublishedFileId_t nPublishedFileID, uint32 unMaxAgeSeconds ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_CreateItem( ISteamUGC* self, AppId_t nConsumerAppId, EWorkshopFileType eFileType ); +S_API UGCUpdateHandle_t SteamAPI_ISteamUGC_StartItemUpdate( ISteamUGC* self, AppId_t nConsumerAppId, PublishedFileId_t nPublishedFileID ); +S_API bool SteamAPI_ISteamUGC_SetItemTitle( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchTitle ); +S_API bool SteamAPI_ISteamUGC_SetItemDescription( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchDescription ); +S_API bool SteamAPI_ISteamUGC_SetItemUpdateLanguage( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchLanguage ); +S_API bool SteamAPI_ISteamUGC_SetItemMetadata( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchMetaData ); +S_API bool SteamAPI_ISteamUGC_SetItemVisibility( ISteamUGC* self, UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVisibility eVisibility ); +S_API bool SteamAPI_ISteamUGC_SetItemTags( ISteamUGC* self, UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t * pTags ); +S_API bool SteamAPI_ISteamUGC_SetItemContent( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pszContentFolder ); +S_API bool SteamAPI_ISteamUGC_SetItemPreview( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pszPreviewFile ); +S_API bool SteamAPI_ISteamUGC_SetAllowLegacyUpload( ISteamUGC* self, UGCUpdateHandle_t handle, bool bAllowLegacyUpload ); +S_API bool SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags( ISteamUGC* self, UGCUpdateHandle_t handle ); +S_API bool SteamAPI_ISteamUGC_RemoveItemKeyValueTags( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchKey ); +S_API bool SteamAPI_ISteamUGC_AddItemKeyValueTag( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchKey, const char * pchValue ); +S_API bool SteamAPI_ISteamUGC_AddItemPreviewFile( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pszPreviewFile, EItemPreviewType type ); +S_API bool SteamAPI_ISteamUGC_AddItemPreviewVideo( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pszVideoID ); +S_API bool SteamAPI_ISteamUGC_UpdateItemPreviewFile( ISteamUGC* self, UGCUpdateHandle_t handle, uint32 index, const char * pszPreviewFile ); +S_API bool SteamAPI_ISteamUGC_UpdateItemPreviewVideo( ISteamUGC* self, UGCUpdateHandle_t handle, uint32 index, const char * pszVideoID ); +S_API bool SteamAPI_ISteamUGC_RemoveItemPreview( ISteamUGC* self, UGCUpdateHandle_t handle, uint32 index ); +S_API bool SteamAPI_ISteamUGC_AddContentDescriptor( ISteamUGC* self, UGCUpdateHandle_t handle, EUGCContentDescriptorID descid ); +S_API bool SteamAPI_ISteamUGC_RemoveContentDescriptor( ISteamUGC* self, UGCUpdateHandle_t handle, EUGCContentDescriptorID descid ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SubmitItemUpdate( ISteamUGC* self, UGCUpdateHandle_t handle, const char * pchChangeNote ); +S_API EItemUpdateStatus SteamAPI_ISteamUGC_GetItemUpdateProgress( ISteamUGC* self, UGCUpdateHandle_t handle, uint64 * punBytesProcessed, uint64 * punBytesTotal ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SetUserItemVote( ISteamUGC* self, PublishedFileId_t nPublishedFileID, bool bVoteUp ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_GetUserItemVote( ISteamUGC* self, PublishedFileId_t nPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_AddItemToFavorites( ISteamUGC* self, AppId_t nAppId, PublishedFileId_t nPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RemoveItemFromFavorites( ISteamUGC* self, AppId_t nAppId, PublishedFileId_t nPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_SubscribeItem( ISteamUGC* self, PublishedFileId_t nPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_UnsubscribeItem( ISteamUGC* self, PublishedFileId_t nPublishedFileID ); +S_API uint32 SteamAPI_ISteamUGC_GetNumSubscribedItems( ISteamUGC* self ); +S_API uint32 SteamAPI_ISteamUGC_GetSubscribedItems( ISteamUGC* self, PublishedFileId_t * pvecPublishedFileID, uint32 cMaxEntries ); +S_API uint32 SteamAPI_ISteamUGC_GetItemState( ISteamUGC* self, PublishedFileId_t nPublishedFileID ); +S_API bool SteamAPI_ISteamUGC_GetItemInstallInfo( ISteamUGC* self, PublishedFileId_t nPublishedFileID, uint64 * punSizeOnDisk, char * pchFolder, uint32 cchFolderSize, uint32 * punTimeStamp ); +S_API bool SteamAPI_ISteamUGC_GetItemDownloadInfo( ISteamUGC* self, PublishedFileId_t nPublishedFileID, uint64 * punBytesDownloaded, uint64 * punBytesTotal ); +S_API bool SteamAPI_ISteamUGC_DownloadItem( ISteamUGC* self, PublishedFileId_t nPublishedFileID, bool bHighPriority ); +S_API bool SteamAPI_ISteamUGC_BInitWorkshopForGameServer( ISteamUGC* self, DepotId_t unWorkshopDepotID, const char * pszFolder ); +S_API void SteamAPI_ISteamUGC_SuspendDownloads( ISteamUGC* self, bool bSuspend ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_StartPlaytimeTracking( ISteamUGC* self, PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_StopPlaytimeTracking( ISteamUGC* self, PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems( ISteamUGC* self ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_AddDependency( ISteamUGC* self, PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RemoveDependency( ISteamUGC* self, PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_AddAppDependency( ISteamUGC* self, PublishedFileId_t nPublishedFileID, AppId_t nAppID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_RemoveAppDependency( ISteamUGC* self, PublishedFileId_t nPublishedFileID, AppId_t nAppID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_GetAppDependencies( ISteamUGC* self, PublishedFileId_t nPublishedFileID ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_DeleteItem( ISteamUGC* self, PublishedFileId_t nPublishedFileID ); +S_API bool SteamAPI_ISteamUGC_ShowWorkshopEULA( ISteamUGC* self ); +S_API SteamAPICall_t SteamAPI_ISteamUGC_GetWorkshopEULAStatus( ISteamUGC* self ); + +// ISteamAppList + +// A versioned accessor is exported by the library +S_API ISteamAppList *SteamAPI_SteamAppList_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamAppList(), but using this ensures that you are using a matching library. +inline ISteamAppList *SteamAPI_SteamAppList() { return SteamAPI_SteamAppList_v001(); } +S_API uint32 SteamAPI_ISteamAppList_GetNumInstalledApps( ISteamAppList* self ); +S_API uint32 SteamAPI_ISteamAppList_GetInstalledApps( ISteamAppList* self, AppId_t * pvecAppID, uint32 unMaxAppIDs ); +S_API int SteamAPI_ISteamAppList_GetAppName( ISteamAppList* self, AppId_t nAppID, char * pchName, int cchNameMax ); +S_API int SteamAPI_ISteamAppList_GetAppInstallDir( ISteamAppList* self, AppId_t nAppID, char * pchDirectory, int cchNameMax ); +S_API int SteamAPI_ISteamAppList_GetAppBuildId( ISteamAppList* self, AppId_t nAppID ); + +// ISteamHTMLSurface + +// A versioned accessor is exported by the library +S_API ISteamHTMLSurface *SteamAPI_SteamHTMLSurface_v005(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamHTMLSurface(), but using this ensures that you are using a matching library. +inline ISteamHTMLSurface *SteamAPI_SteamHTMLSurface() { return SteamAPI_SteamHTMLSurface_v005(); } +S_API bool SteamAPI_ISteamHTMLSurface_Init( ISteamHTMLSurface* self ); +S_API bool SteamAPI_ISteamHTMLSurface_Shutdown( ISteamHTMLSurface* self ); +S_API SteamAPICall_t SteamAPI_ISteamHTMLSurface_CreateBrowser( ISteamHTMLSurface* self, const char * pchUserAgent, const char * pchUserCSS ); +S_API void SteamAPI_ISteamHTMLSurface_RemoveBrowser( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_LoadURL( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, const char * pchURL, const char * pchPostData ); +S_API void SteamAPI_ISteamHTMLSurface_SetSize( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight ); +S_API void SteamAPI_ISteamHTMLSurface_StopLoad( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_Reload( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_GoBack( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_GoForward( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_AddHeader( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, const char * pchKey, const char * pchValue ); +S_API void SteamAPI_ISteamHTMLSurface_ExecuteJavascript( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, const char * pchScript ); +S_API void SteamAPI_ISteamHTMLSurface_MouseUp( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, ISteamHTMLSurface::EHTMLMouseButton eMouseButton ); +S_API void SteamAPI_ISteamHTMLSurface_MouseDown( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, ISteamHTMLSurface::EHTMLMouseButton eMouseButton ); +S_API void SteamAPI_ISteamHTMLSurface_MouseDoubleClick( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, ISteamHTMLSurface::EHTMLMouseButton eMouseButton ); +S_API void SteamAPI_ISteamHTMLSurface_MouseMove( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, int x, int y ); +S_API void SteamAPI_ISteamHTMLSurface_MouseWheel( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, int32 nDelta ); +S_API void SteamAPI_ISteamHTMLSurface_KeyDown( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, ISteamHTMLSurface::EHTMLKeyModifiers eHTMLKeyModifiers, bool bIsSystemKey ); +S_API void SteamAPI_ISteamHTMLSurface_KeyUp( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, ISteamHTMLSurface::EHTMLKeyModifiers eHTMLKeyModifiers ); +S_API void SteamAPI_ISteamHTMLSurface_KeyChar( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, ISteamHTMLSurface::EHTMLKeyModifiers eHTMLKeyModifiers ); +S_API void SteamAPI_ISteamHTMLSurface_SetHorizontalScroll( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll ); +S_API void SteamAPI_ISteamHTMLSurface_SetVerticalScroll( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll ); +S_API void SteamAPI_ISteamHTMLSurface_SetKeyFocus( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, bool bHasKeyFocus ); +S_API void SteamAPI_ISteamHTMLSurface_ViewSource( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_CopyToClipboard( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_PasteFromClipboard( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_Find( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, const char * pchSearchStr, bool bCurrentlyInFind, bool bReverse ); +S_API void SteamAPI_ISteamHTMLSurface_StopFind( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_GetLinkAtPosition( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, int x, int y ); +S_API void SteamAPI_ISteamHTMLSurface_SetCookie( ISteamHTMLSurface* self, const char * pchHostname, const char * pchKey, const char * pchValue, const char * pchPath, RTime32 nExpires, bool bSecure, bool bHTTPOnly ); +S_API void SteamAPI_ISteamHTMLSurface_SetPageScaleFactor( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY ); +S_API void SteamAPI_ISteamHTMLSurface_SetBackgroundMode( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, bool bBackgroundMode ); +S_API void SteamAPI_ISteamHTMLSurface_SetDPIScalingFactor( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, float flDPIScaling ); +S_API void SteamAPI_ISteamHTMLSurface_OpenDeveloperTools( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle ); +S_API void SteamAPI_ISteamHTMLSurface_AllowStartRequest( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, bool bAllowed ); +S_API void SteamAPI_ISteamHTMLSurface_JSDialogResponse( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, bool bResult ); +S_API void SteamAPI_ISteamHTMLSurface_FileLoadDialogResponse( ISteamHTMLSurface* self, HHTMLBrowser unBrowserHandle, const char ** pchSelectedFiles ); + +// ISteamInventory + +// A versioned accessor is exported by the library +S_API ISteamInventory *SteamAPI_SteamInventory_v003(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamInventory(), but using this ensures that you are using a matching library. +inline ISteamInventory *SteamAPI_SteamInventory() { return SteamAPI_SteamInventory_v003(); } + +// A versioned accessor is exported by the library +S_API ISteamInventory *SteamAPI_SteamGameServerInventory_v003(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerInventory(), but using this ensures that you are using a matching library. +inline ISteamInventory *SteamAPI_SteamGameServerInventory() { return SteamAPI_SteamGameServerInventory_v003(); } +S_API EResult SteamAPI_ISteamInventory_GetResultStatus( ISteamInventory* self, SteamInventoryResult_t resultHandle ); +S_API bool SteamAPI_ISteamInventory_GetResultItems( ISteamInventory* self, SteamInventoryResult_t resultHandle, SteamItemDetails_t * pOutItemsArray, uint32 * punOutItemsArraySize ); +S_API bool SteamAPI_ISteamInventory_GetResultItemProperty( ISteamInventory* self, SteamInventoryResult_t resultHandle, uint32 unItemIndex, const char * pchPropertyName, char * pchValueBuffer, uint32 * punValueBufferSizeOut ); +S_API uint32 SteamAPI_ISteamInventory_GetResultTimestamp( ISteamInventory* self, SteamInventoryResult_t resultHandle ); +S_API bool SteamAPI_ISteamInventory_CheckResultSteamID( ISteamInventory* self, SteamInventoryResult_t resultHandle, uint64_steamid steamIDExpected ); +S_API void SteamAPI_ISteamInventory_DestroyResult( ISteamInventory* self, SteamInventoryResult_t resultHandle ); +S_API bool SteamAPI_ISteamInventory_GetAllItems( ISteamInventory* self, SteamInventoryResult_t * pResultHandle ); +S_API bool SteamAPI_ISteamInventory_GetItemsByID( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, const SteamItemInstanceID_t * pInstanceIDs, uint32 unCountInstanceIDs ); +S_API bool SteamAPI_ISteamInventory_SerializeResult( ISteamInventory* self, SteamInventoryResult_t resultHandle, void * pOutBuffer, uint32 * punOutBufferSize ); +S_API bool SteamAPI_ISteamInventory_DeserializeResult( ISteamInventory* self, SteamInventoryResult_t * pOutResultHandle, const void * pBuffer, uint32 unBufferSize, bool bRESERVED_MUST_BE_FALSE ); +S_API bool SteamAPI_ISteamInventory_GenerateItems( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, const SteamItemDef_t * pArrayItemDefs, const uint32 * punArrayQuantity, uint32 unArrayLength ); +S_API bool SteamAPI_ISteamInventory_GrantPromoItems( ISteamInventory* self, SteamInventoryResult_t * pResultHandle ); +S_API bool SteamAPI_ISteamInventory_AddPromoItem( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, SteamItemDef_t itemDef ); +S_API bool SteamAPI_ISteamInventory_AddPromoItems( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, const SteamItemDef_t * pArrayItemDefs, uint32 unArrayLength ); +S_API bool SteamAPI_ISteamInventory_ConsumeItem( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, SteamItemInstanceID_t itemConsume, uint32 unQuantity ); +S_API bool SteamAPI_ISteamInventory_ExchangeItems( ISteamInventory* self, 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( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, SteamItemInstanceID_t itemIdSource, uint32 unQuantity, SteamItemInstanceID_t itemIdDest ); +S_API void SteamAPI_ISteamInventory_SendItemDropHeartbeat( ISteamInventory* self ); +S_API bool SteamAPI_ISteamInventory_TriggerItemDrop( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, SteamItemDef_t dropListDefinition ); +S_API bool SteamAPI_ISteamInventory_TradeItems( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, uint64_steamid 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( ISteamInventory* self ); +S_API bool SteamAPI_ISteamInventory_GetItemDefinitionIDs( ISteamInventory* self, SteamItemDef_t * pItemDefIDs, uint32 * punItemDefIDsArraySize ); +S_API bool SteamAPI_ISteamInventory_GetItemDefinitionProperty( ISteamInventory* self, SteamItemDef_t iDefinition, const char * pchPropertyName, char * pchValueBuffer, uint32 * punValueBufferSizeOut ); +S_API SteamAPICall_t SteamAPI_ISteamInventory_RequestEligiblePromoItemDefinitionsIDs( ISteamInventory* self, uint64_steamid steamID ); +S_API bool SteamAPI_ISteamInventory_GetEligiblePromoItemDefinitionIDs( ISteamInventory* self, uint64_steamid steamID, SteamItemDef_t * pItemDefIDs, uint32 * punItemDefIDsArraySize ); +S_API SteamAPICall_t SteamAPI_ISteamInventory_StartPurchase( ISteamInventory* self, const SteamItemDef_t * pArrayItemDefs, const uint32 * punArrayQuantity, uint32 unArrayLength ); +S_API SteamAPICall_t SteamAPI_ISteamInventory_RequestPrices( ISteamInventory* self ); +S_API uint32 SteamAPI_ISteamInventory_GetNumItemsWithPrices( ISteamInventory* self ); +S_API bool SteamAPI_ISteamInventory_GetItemsWithPrices( ISteamInventory* self, SteamItemDef_t * pArrayItemDefs, uint64 * pCurrentPrices, uint64 * pBasePrices, uint32 unArrayLength ); +S_API bool SteamAPI_ISteamInventory_GetItemPrice( ISteamInventory* self, SteamItemDef_t iDefinition, uint64 * pCurrentPrice, uint64 * pBasePrice ); +S_API SteamInventoryUpdateHandle_t SteamAPI_ISteamInventory_StartUpdateProperties( ISteamInventory* self ); +S_API bool SteamAPI_ISteamInventory_RemoveProperty( ISteamInventory* self, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName ); +S_API bool SteamAPI_ISteamInventory_SetPropertyString( ISteamInventory* self, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, const char * pchPropertyValue ); +S_API bool SteamAPI_ISteamInventory_SetPropertyBool( ISteamInventory* self, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, bool bValue ); +S_API bool SteamAPI_ISteamInventory_SetPropertyInt64( ISteamInventory* self, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, int64 nValue ); +S_API bool SteamAPI_ISteamInventory_SetPropertyFloat( ISteamInventory* self, SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char * pchPropertyName, float flValue ); +S_API bool SteamAPI_ISteamInventory_SubmitUpdateProperties( ISteamInventory* self, SteamInventoryUpdateHandle_t handle, SteamInventoryResult_t * pResultHandle ); +S_API bool SteamAPI_ISteamInventory_InspectItem( ISteamInventory* self, SteamInventoryResult_t * pResultHandle, const char * pchItemToken ); + +// ISteamVideo + +// A versioned accessor is exported by the library +S_API ISteamVideo *SteamAPI_SteamVideo_v002(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamVideo(), but using this ensures that you are using a matching library. +inline ISteamVideo *SteamAPI_SteamVideo() { return SteamAPI_SteamVideo_v002(); } +S_API void SteamAPI_ISteamVideo_GetVideoURL( ISteamVideo* self, AppId_t unVideoAppID ); +S_API bool SteamAPI_ISteamVideo_IsBroadcasting( ISteamVideo* self, int * pnNumViewers ); +S_API void SteamAPI_ISteamVideo_GetOPFSettings( ISteamVideo* self, AppId_t unVideoAppID ); +S_API bool SteamAPI_ISteamVideo_GetOPFStringForApp( ISteamVideo* self, AppId_t unVideoAppID, char * pchBuffer, int32 * pnBufferSize ); + +// ISteamParentalSettings + +// A versioned accessor is exported by the library +S_API ISteamParentalSettings *SteamAPI_SteamParentalSettings_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamParentalSettings(), but using this ensures that you are using a matching library. +inline ISteamParentalSettings *SteamAPI_SteamParentalSettings() { return SteamAPI_SteamParentalSettings_v001(); } +S_API bool SteamAPI_ISteamParentalSettings_BIsParentalLockEnabled( ISteamParentalSettings* self ); +S_API bool SteamAPI_ISteamParentalSettings_BIsParentalLockLocked( ISteamParentalSettings* self ); +S_API bool SteamAPI_ISteamParentalSettings_BIsAppBlocked( ISteamParentalSettings* self, AppId_t nAppID ); +S_API bool SteamAPI_ISteamParentalSettings_BIsAppInBlockList( ISteamParentalSettings* self, AppId_t nAppID ); +S_API bool SteamAPI_ISteamParentalSettings_BIsFeatureBlocked( ISteamParentalSettings* self, EParentalFeature eFeature ); +S_API bool SteamAPI_ISteamParentalSettings_BIsFeatureInBlockList( ISteamParentalSettings* self, EParentalFeature eFeature ); + +// ISteamRemotePlay + +// A versioned accessor is exported by the library +S_API ISteamRemotePlay *SteamAPI_SteamRemotePlay_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamRemotePlay(), but using this ensures that you are using a matching library. +inline ISteamRemotePlay *SteamAPI_SteamRemotePlay() { return SteamAPI_SteamRemotePlay_v001(); } +S_API uint32 SteamAPI_ISteamRemotePlay_GetSessionCount( ISteamRemotePlay* self ); +S_API RemotePlaySessionID_t SteamAPI_ISteamRemotePlay_GetSessionID( ISteamRemotePlay* self, int iSessionIndex ); +S_API uint64_steamid SteamAPI_ISteamRemotePlay_GetSessionSteamID( ISteamRemotePlay* self, RemotePlaySessionID_t unSessionID ); +S_API const char * SteamAPI_ISteamRemotePlay_GetSessionClientName( ISteamRemotePlay* self, RemotePlaySessionID_t unSessionID ); +S_API ESteamDeviceFormFactor SteamAPI_ISteamRemotePlay_GetSessionClientFormFactor( ISteamRemotePlay* self, RemotePlaySessionID_t unSessionID ); +S_API bool SteamAPI_ISteamRemotePlay_BGetSessionClientResolution( ISteamRemotePlay* self, RemotePlaySessionID_t unSessionID, int * pnResolutionX, int * pnResolutionY ); +S_API bool SteamAPI_ISteamRemotePlay_BSendRemotePlayTogetherInvite( ISteamRemotePlay* self, uint64_steamid steamIDFriend ); + +// ISteamNetworkingMessages + +// A versioned accessor is exported by the library +S_API ISteamNetworkingMessages *SteamAPI_SteamNetworkingMessages_SteamAPI_v002(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamNetworkingMessages_SteamAPI(), but using this ensures that you are using a matching library. +inline ISteamNetworkingMessages *SteamAPI_SteamNetworkingMessages_SteamAPI() { return SteamAPI_SteamNetworkingMessages_SteamAPI_v002(); } + +// A versioned accessor is exported by the library +S_API ISteamNetworkingMessages *SteamAPI_SteamGameServerNetworkingMessages_SteamAPI_v002(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerNetworkingMessages_SteamAPI(), but using this ensures that you are using a matching library. +inline ISteamNetworkingMessages *SteamAPI_SteamGameServerNetworkingMessages_SteamAPI() { return SteamAPI_SteamGameServerNetworkingMessages_SteamAPI_v002(); } +S_API EResult SteamAPI_ISteamNetworkingMessages_SendMessageToUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, const void * pubData, uint32 cubData, int nSendFlags, int nRemoteChannel ); +S_API int SteamAPI_ISteamNetworkingMessages_ReceiveMessagesOnChannel( ISteamNetworkingMessages* self, int nLocalChannel, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ); +S_API bool SteamAPI_ISteamNetworkingMessages_AcceptSessionWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote ); +S_API bool SteamAPI_ISteamNetworkingMessages_CloseSessionWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote ); +S_API bool SteamAPI_ISteamNetworkingMessages_CloseChannelWithUser( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, int nLocalChannel ); +S_API ESteamNetworkingConnectionState SteamAPI_ISteamNetworkingMessages_GetSessionConnectionInfo( ISteamNetworkingMessages* self, const SteamNetworkingIdentity & identityRemote, SteamNetConnectionInfo_t * pConnectionInfo, SteamNetConnectionRealTimeStatus_t * pQuickStatus ); + +// ISteamNetworkingSockets + +// A versioned accessor is exported by the library +S_API ISteamNetworkingSockets *SteamAPI_SteamNetworkingSockets_SteamAPI_v012(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamNetworkingSockets_SteamAPI(), but using this ensures that you are using a matching library. +inline ISteamNetworkingSockets *SteamAPI_SteamNetworkingSockets_SteamAPI() { return SteamAPI_SteamNetworkingSockets_SteamAPI_v012(); } + +// A versioned accessor is exported by the library +S_API ISteamNetworkingSockets *SteamAPI_SteamGameServerNetworkingSockets_SteamAPI_v012(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerNetworkingSockets_SteamAPI(), but using this ensures that you are using a matching library. +inline ISteamNetworkingSockets *SteamAPI_SteamGameServerNetworkingSockets_SteamAPI() { return SteamAPI_SteamGameServerNetworkingSockets_SteamAPI_v012(); } +S_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP( ISteamNetworkingSockets* self, const SteamNetworkingIPAddr & localAddress, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress( ISteamNetworkingSockets* self, const SteamNetworkingIPAddr & address, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2P( ISteamNetworkingSockets* self, int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2P( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityRemote, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API EResult SteamAPI_ISteamNetworkingSockets_AcceptConnection( ISteamNetworkingSockets* self, HSteamNetConnection hConn ); +S_API bool SteamAPI_ISteamNetworkingSockets_CloseConnection( ISteamNetworkingSockets* self, HSteamNetConnection hPeer, int nReason, const char * pszDebug, bool bEnableLinger ); +S_API bool SteamAPI_ISteamNetworkingSockets_CloseListenSocket( ISteamNetworkingSockets* self, HSteamListenSocket hSocket ); +S_API bool SteamAPI_ISteamNetworkingSockets_SetConnectionUserData( ISteamNetworkingSockets* self, HSteamNetConnection hPeer, int64 nUserData ); +S_API int64 SteamAPI_ISteamNetworkingSockets_GetConnectionUserData( ISteamNetworkingSockets* self, HSteamNetConnection hPeer ); +S_API void SteamAPI_ISteamNetworkingSockets_SetConnectionName( ISteamNetworkingSockets* self, HSteamNetConnection hPeer, const char * pszName ); +S_API bool SteamAPI_ISteamNetworkingSockets_GetConnectionName( ISteamNetworkingSockets* self, HSteamNetConnection hPeer, char * pszName, int nMaxLen ); +S_API EResult SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( ISteamNetworkingSockets* self, HSteamNetConnection hConn, const void * pData, uint32 cbData, int nSendFlags, int64 * pOutMessageNumber ); +S_API void SteamAPI_ISteamNetworkingSockets_SendMessages( ISteamNetworkingSockets* self, int nMessages, SteamNetworkingMessage_t *const * pMessages, int64 * pOutMessageNumberOrResult ); +S_API EResult SteamAPI_ISteamNetworkingSockets_FlushMessagesOnConnection( ISteamNetworkingSockets* self, HSteamNetConnection hConn ); +S_API int SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection( ISteamNetworkingSockets* self, HSteamNetConnection hConn, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ); +S_API bool SteamAPI_ISteamNetworkingSockets_GetConnectionInfo( ISteamNetworkingSockets* self, HSteamNetConnection hConn, SteamNetConnectionInfo_t * pInfo ); +S_API EResult SteamAPI_ISteamNetworkingSockets_GetConnectionRealTimeStatus( ISteamNetworkingSockets* self, HSteamNetConnection hConn, SteamNetConnectionRealTimeStatus_t * pStatus, int nLanes, SteamNetConnectionRealTimeLaneStatus_t * pLanes ); +S_API int SteamAPI_ISteamNetworkingSockets_GetDetailedConnectionStatus( ISteamNetworkingSockets* self, HSteamNetConnection hConn, char * pszBuf, int cbBuf ); +S_API bool SteamAPI_ISteamNetworkingSockets_GetListenSocketAddress( ISteamNetworkingSockets* self, HSteamListenSocket hSocket, SteamNetworkingIPAddr * address ); +S_API bool SteamAPI_ISteamNetworkingSockets_CreateSocketPair( ISteamNetworkingSockets* self, HSteamNetConnection * pOutConnection1, HSteamNetConnection * pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity * pIdentity1, const SteamNetworkingIdentity * pIdentity2 ); +S_API EResult SteamAPI_ISteamNetworkingSockets_ConfigureConnectionLanes( ISteamNetworkingSockets* self, HSteamNetConnection hConn, int nNumLanes, const int * pLanePriorities, const uint16 * pLaneWeights ); +S_API bool SteamAPI_ISteamNetworkingSockets_GetIdentity( ISteamNetworkingSockets* self, SteamNetworkingIdentity * pIdentity ); +S_API ESteamNetworkingAvailability SteamAPI_ISteamNetworkingSockets_InitAuthentication( ISteamNetworkingSockets* self ); +S_API ESteamNetworkingAvailability SteamAPI_ISteamNetworkingSockets_GetAuthenticationStatus( ISteamNetworkingSockets* self, SteamNetAuthenticationStatus_t * pDetails ); +S_API HSteamNetPollGroup SteamAPI_ISteamNetworkingSockets_CreatePollGroup( ISteamNetworkingSockets* self ); +S_API bool SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( ISteamNetworkingSockets* self, HSteamNetPollGroup hPollGroup ); +S_API bool SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup( ISteamNetworkingSockets* self, HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup ); +S_API int SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup( ISteamNetworkingSockets* self, HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ); +S_API bool SteamAPI_ISteamNetworkingSockets_ReceivedRelayAuthTicket( ISteamNetworkingSockets* self, const void * pvTicket, int cbTicket, SteamDatagramRelayAuthTicket * pOutParsedTicket ); +S_API int SteamAPI_ISteamNetworkingSockets_FindRelayAuthTicketForServer( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityGameServer, int nRemoteVirtualPort, SteamDatagramRelayAuthTicket * pOutParsedTicket ); +S_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectToHostedDedicatedServer( ISteamNetworkingSockets* self, const SteamNetworkingIdentity & identityTarget, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API uint16 SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPort( ISteamNetworkingSockets* self ); +S_API SteamNetworkingPOPID SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerPOPID( ISteamNetworkingSockets* self ); +S_API EResult SteamAPI_ISteamNetworkingSockets_GetHostedDedicatedServerAddress( ISteamNetworkingSockets* self, SteamDatagramHostedAddress * pRouting ); +S_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateHostedDedicatedServerListenSocket( ISteamNetworkingSockets* self, int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API EResult SteamAPI_ISteamNetworkingSockets_GetGameCoordinatorServerLogin( ISteamNetworkingSockets* self, SteamDatagramGameCoordinatorServerLogin * pLoginInfo, int * pcbSignedBlob, void * pBlob ); +S_API HSteamNetConnection SteamAPI_ISteamNetworkingSockets_ConnectP2PCustomSignaling( ISteamNetworkingSockets* self, ISteamNetworkingConnectionSignaling * pSignaling, const SteamNetworkingIdentity * pPeerIdentity, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API bool SteamAPI_ISteamNetworkingSockets_ReceivedP2PCustomSignal( ISteamNetworkingSockets* self, const void * pMsg, int cbMsg, ISteamNetworkingSignalingRecvContext * pContext ); +S_API bool SteamAPI_ISteamNetworkingSockets_GetCertificateRequest( ISteamNetworkingSockets* self, int * pcbBlob, void * pBlob, SteamNetworkingErrMsg & errMsg ); +S_API bool SteamAPI_ISteamNetworkingSockets_SetCertificate( ISteamNetworkingSockets* self, const void * pCertificate, int cbCertificate, SteamNetworkingErrMsg & errMsg ); +S_API void SteamAPI_ISteamNetworkingSockets_ResetIdentity( ISteamNetworkingSockets* self, const SteamNetworkingIdentity * pIdentity ); +S_API void SteamAPI_ISteamNetworkingSockets_RunCallbacks( ISteamNetworkingSockets* self ); +S_API bool SteamAPI_ISteamNetworkingSockets_BeginAsyncRequestFakeIP( ISteamNetworkingSockets* self, int nNumPorts ); +S_API void SteamAPI_ISteamNetworkingSockets_GetFakeIP( ISteamNetworkingSockets* self, int idxFirstPort, SteamNetworkingFakeIPResult_t * pInfo ); +S_API HSteamListenSocket SteamAPI_ISteamNetworkingSockets_CreateListenSocketP2PFakeIP( ISteamNetworkingSockets* self, int idxFakePort, int nOptions, const SteamNetworkingConfigValue_t * pOptions ); +S_API EResult SteamAPI_ISteamNetworkingSockets_GetRemoteFakeIPForConnection( ISteamNetworkingSockets* self, HSteamNetConnection hConn, SteamNetworkingIPAddr * pOutAddr ); +S_API ISteamNetworkingFakeUDPPort * SteamAPI_ISteamNetworkingSockets_CreateFakeUDPPort( ISteamNetworkingSockets* self, int idxFakeServerPort ); + +// ISteamNetworkingUtils + +// A versioned accessor is exported by the library +S_API ISteamNetworkingUtils *SteamAPI_SteamNetworkingUtils_SteamAPI_v004(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamNetworkingUtils_SteamAPI(), but using this ensures that you are using a matching library. +inline ISteamNetworkingUtils *SteamAPI_SteamNetworkingUtils_SteamAPI() { return SteamAPI_SteamNetworkingUtils_SteamAPI_v004(); } +S_API SteamNetworkingMessage_t * SteamAPI_ISteamNetworkingUtils_AllocateMessage( ISteamNetworkingUtils* self, int cbAllocateBuffer ); +S_API void SteamAPI_ISteamNetworkingUtils_InitRelayNetworkAccess( ISteamNetworkingUtils* self ); +S_API ESteamNetworkingAvailability SteamAPI_ISteamNetworkingUtils_GetRelayNetworkStatus( ISteamNetworkingUtils* self, SteamRelayNetworkStatus_t * pDetails ); +S_API float SteamAPI_ISteamNetworkingUtils_GetLocalPingLocation( ISteamNetworkingUtils* self, SteamNetworkPingLocation_t & result ); +S_API int SteamAPI_ISteamNetworkingUtils_EstimatePingTimeBetweenTwoLocations( ISteamNetworkingUtils* self, const SteamNetworkPingLocation_t & location1, const SteamNetworkPingLocation_t & location2 ); +S_API int SteamAPI_ISteamNetworkingUtils_EstimatePingTimeFromLocalHost( ISteamNetworkingUtils* self, const SteamNetworkPingLocation_t & remoteLocation ); +S_API void SteamAPI_ISteamNetworkingUtils_ConvertPingLocationToString( ISteamNetworkingUtils* self, const SteamNetworkPingLocation_t & location, char * pszBuf, int cchBufSize ); +S_API bool SteamAPI_ISteamNetworkingUtils_ParsePingLocationString( ISteamNetworkingUtils* self, const char * pszString, SteamNetworkPingLocation_t & result ); +S_API bool SteamAPI_ISteamNetworkingUtils_CheckPingDataUpToDate( ISteamNetworkingUtils* self, float flMaxAgeSeconds ); +S_API int SteamAPI_ISteamNetworkingUtils_GetPingToDataCenter( ISteamNetworkingUtils* self, SteamNetworkingPOPID popID, SteamNetworkingPOPID * pViaRelayPoP ); +S_API int SteamAPI_ISteamNetworkingUtils_GetDirectPingToPOP( ISteamNetworkingUtils* self, SteamNetworkingPOPID popID ); +S_API int SteamAPI_ISteamNetworkingUtils_GetPOPCount( ISteamNetworkingUtils* self ); +S_API int SteamAPI_ISteamNetworkingUtils_GetPOPList( ISteamNetworkingUtils* self, SteamNetworkingPOPID * list, int nListSz ); +S_API SteamNetworkingMicroseconds SteamAPI_ISteamNetworkingUtils_GetLocalTimestamp( ISteamNetworkingUtils* self ); +S_API void SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction( ISteamNetworkingUtils* self, ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc ); +S_API bool SteamAPI_ISteamNetworkingUtils_IsFakeIPv4( ISteamNetworkingUtils* self, uint32 nIPv4 ); +S_API ESteamNetworkingFakeIPType SteamAPI_ISteamNetworkingUtils_GetIPv4FakeIPType( ISteamNetworkingUtils* self, uint32 nIPv4 ); +S_API EResult SteamAPI_ISteamNetworkingUtils_GetRealIdentityForFakeIP( ISteamNetworkingUtils* self, const SteamNetworkingIPAddr & fakeIP, SteamNetworkingIdentity * pOutRealIdentity ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueInt32( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, int32 val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueFloat( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, float val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueString( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, const char * val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValuePtr( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, void * val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueInt32( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueFloat( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueString( ISteamNetworkingUtils* self, HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char * val ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetConnectionStatusChanged( ISteamNetworkingUtils* self, FnSteamNetConnectionStatusChanged fnCallback ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamNetAuthenticationStatusChanged( ISteamNetworkingUtils* self, FnSteamNetAuthenticationStatusChanged fnCallback ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_SteamRelayNetworkStatusChanged( ISteamNetworkingUtils* self, FnSteamRelayNetworkStatusChanged fnCallback ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_FakeIPResult( ISteamNetworkingUtils* self, FnSteamNetworkingFakeIPResult fnCallback ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionRequest( ISteamNetworkingUtils* self, FnSteamNetworkingMessagesSessionRequest fnCallback ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetGlobalCallback_MessagesSessionFailed( ISteamNetworkingUtils* self, FnSteamNetworkingMessagesSessionFailed fnCallback ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetConfigValue( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, ESteamNetworkingConfigDataType eDataType, const void * pArg ); +S_API bool SteamAPI_ISteamNetworkingUtils_SetConfigValueStruct( ISteamNetworkingUtils* self, const SteamNetworkingConfigValue_t & opt, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj ); +S_API ESteamNetworkingGetConfigValueResult SteamAPI_ISteamNetworkingUtils_GetConfigValue( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj, ESteamNetworkingConfigDataType * pOutDataType, void * pResult, size_t * cbResult ); +S_API const char * SteamAPI_ISteamNetworkingUtils_GetConfigValueInfo( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigDataType * pOutDataType, ESteamNetworkingConfigScope * pOutScope ); +S_API ESteamNetworkingConfigValue SteamAPI_ISteamNetworkingUtils_IterateGenericEditableConfigValues( ISteamNetworkingUtils* self, ESteamNetworkingConfigValue eCurrent, bool bEnumerateDevVars ); +S_API void SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_ToString( ISteamNetworkingUtils* self, const SteamNetworkingIPAddr & addr, char * buf, uint32 cbBuf, bool bWithPort ); +S_API bool SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_ParseString( ISteamNetworkingUtils* self, SteamNetworkingIPAddr * pAddr, const char * pszStr ); +S_API ESteamNetworkingFakeIPType SteamAPI_ISteamNetworkingUtils_SteamNetworkingIPAddr_GetFakeIPType( ISteamNetworkingUtils* self, const SteamNetworkingIPAddr & addr ); +S_API void SteamAPI_ISteamNetworkingUtils_SteamNetworkingIdentity_ToString( ISteamNetworkingUtils* self, const SteamNetworkingIdentity & identity, char * buf, uint32 cbBuf ); +S_API bool SteamAPI_ISteamNetworkingUtils_SteamNetworkingIdentity_ParseString( ISteamNetworkingUtils* self, SteamNetworkingIdentity * pIdentity, const char * pszStr ); + +// ISteamGameServer + +// A versioned accessor is exported by the library +S_API ISteamGameServer *SteamAPI_SteamGameServer_v015(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServer(), but using this ensures that you are using a matching library. +inline ISteamGameServer *SteamAPI_SteamGameServer() { return SteamAPI_SteamGameServer_v015(); } +S_API void SteamAPI_ISteamGameServer_SetProduct( ISteamGameServer* self, const char * pszProduct ); +S_API void SteamAPI_ISteamGameServer_SetGameDescription( ISteamGameServer* self, const char * pszGameDescription ); +S_API void SteamAPI_ISteamGameServer_SetModDir( ISteamGameServer* self, const char * pszModDir ); +S_API void SteamAPI_ISteamGameServer_SetDedicatedServer( ISteamGameServer* self, bool bDedicated ); +S_API void SteamAPI_ISteamGameServer_LogOn( ISteamGameServer* self, const char * pszToken ); +S_API void SteamAPI_ISteamGameServer_LogOnAnonymous( ISteamGameServer* self ); +S_API void SteamAPI_ISteamGameServer_LogOff( ISteamGameServer* self ); +S_API bool SteamAPI_ISteamGameServer_BLoggedOn( ISteamGameServer* self ); +S_API bool SteamAPI_ISteamGameServer_BSecure( ISteamGameServer* self ); +S_API uint64_steamid SteamAPI_ISteamGameServer_GetSteamID( ISteamGameServer* self ); +S_API bool SteamAPI_ISteamGameServer_WasRestartRequested( ISteamGameServer* self ); +S_API void SteamAPI_ISteamGameServer_SetMaxPlayerCount( ISteamGameServer* self, int cPlayersMax ); +S_API void SteamAPI_ISteamGameServer_SetBotPlayerCount( ISteamGameServer* self, int cBotplayers ); +S_API void SteamAPI_ISteamGameServer_SetServerName( ISteamGameServer* self, const char * pszServerName ); +S_API void SteamAPI_ISteamGameServer_SetMapName( ISteamGameServer* self, const char * pszMapName ); +S_API void SteamAPI_ISteamGameServer_SetPasswordProtected( ISteamGameServer* self, bool bPasswordProtected ); +S_API void SteamAPI_ISteamGameServer_SetSpectatorPort( ISteamGameServer* self, uint16 unSpectatorPort ); +S_API void SteamAPI_ISteamGameServer_SetSpectatorServerName( ISteamGameServer* self, const char * pszSpectatorServerName ); +S_API void SteamAPI_ISteamGameServer_ClearAllKeyValues( ISteamGameServer* self ); +S_API void SteamAPI_ISteamGameServer_SetKeyValue( ISteamGameServer* self, const char * pKey, const char * pValue ); +S_API void SteamAPI_ISteamGameServer_SetGameTags( ISteamGameServer* self, const char * pchGameTags ); +S_API void SteamAPI_ISteamGameServer_SetGameData( ISteamGameServer* self, const char * pchGameData ); +S_API void SteamAPI_ISteamGameServer_SetRegion( ISteamGameServer* self, const char * pszRegion ); +S_API void SteamAPI_ISteamGameServer_SetAdvertiseServerActive( ISteamGameServer* self, bool bActive ); +S_API HAuthTicket SteamAPI_ISteamGameServer_GetAuthSessionTicket( ISteamGameServer* self, void * pTicket, int cbMaxTicket, uint32 * pcbTicket, const SteamNetworkingIdentity * pSnid ); +S_API EBeginAuthSessionResult SteamAPI_ISteamGameServer_BeginAuthSession( ISteamGameServer* self, const void * pAuthTicket, int cbAuthTicket, uint64_steamid steamID ); +S_API void SteamAPI_ISteamGameServer_EndAuthSession( ISteamGameServer* self, uint64_steamid steamID ); +S_API void SteamAPI_ISteamGameServer_CancelAuthTicket( ISteamGameServer* self, HAuthTicket hAuthTicket ); +S_API EUserHasLicenseForAppResult SteamAPI_ISteamGameServer_UserHasLicenseForApp( ISteamGameServer* self, uint64_steamid steamID, AppId_t appID ); +S_API bool SteamAPI_ISteamGameServer_RequestUserGroupStatus( ISteamGameServer* self, uint64_steamid steamIDUser, uint64_steamid steamIDGroup ); +S_API void SteamAPI_ISteamGameServer_GetGameplayStats( ISteamGameServer* self ); +S_API SteamAPICall_t SteamAPI_ISteamGameServer_GetServerReputation( ISteamGameServer* self ); +S_API SteamIPAddress_t SteamAPI_ISteamGameServer_GetPublicIP( ISteamGameServer* self ); +S_API bool SteamAPI_ISteamGameServer_HandleIncomingPacket( ISteamGameServer* self, const void * pData, int cbData, uint32 srcIP, uint16 srcPort ); +S_API int SteamAPI_ISteamGameServer_GetNextOutgoingPacket( ISteamGameServer* self, void * pOut, int cbMaxOut, uint32 * pNetAdr, uint16 * pPort ); +S_API SteamAPICall_t SteamAPI_ISteamGameServer_AssociateWithClan( ISteamGameServer* self, uint64_steamid steamIDClan ); +S_API SteamAPICall_t SteamAPI_ISteamGameServer_ComputeNewPlayerCompatibility( ISteamGameServer* self, uint64_steamid steamIDNewPlayer ); +S_API bool SteamAPI_ISteamGameServer_SendUserConnectAndAuthenticate_DEPRECATED( ISteamGameServer* self, uint32 unIPClient, const void * pvAuthBlob, uint32 cubAuthBlobSize, CSteamID * pSteamIDUser ); +S_API uint64_steamid SteamAPI_ISteamGameServer_CreateUnauthenticatedUserConnection( ISteamGameServer* self ); +S_API void SteamAPI_ISteamGameServer_SendUserDisconnect_DEPRECATED( ISteamGameServer* self, uint64_steamid steamIDUser ); +S_API bool SteamAPI_ISteamGameServer_BUpdateUserData( ISteamGameServer* self, uint64_steamid steamIDUser, const char * pchPlayerName, uint32 uScore ); + +// ISteamGameServerStats + +// A versioned accessor is exported by the library +S_API ISteamGameServerStats *SteamAPI_SteamGameServerStats_v001(); +// Inline, unversioned accessor to get the current version. Essentially the same as SteamGameServerStats(), but using this ensures that you are using a matching library. +inline ISteamGameServerStats *SteamAPI_SteamGameServerStats() { return SteamAPI_SteamGameServerStats_v001(); } +S_API SteamAPICall_t SteamAPI_ISteamGameServerStats_RequestUserStats( ISteamGameServerStats* self, uint64_steamid steamIDUser ); +S_API bool SteamAPI_ISteamGameServerStats_GetUserStatInt32( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName, int32 * pData ); +S_API bool SteamAPI_ISteamGameServerStats_GetUserStatFloat( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName, float * pData ); +S_API bool SteamAPI_ISteamGameServerStats_GetUserAchievement( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName, bool * pbAchieved ); +S_API bool SteamAPI_ISteamGameServerStats_SetUserStatInt32( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName, int32 nData ); +S_API bool SteamAPI_ISteamGameServerStats_SetUserStatFloat( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName, float fData ); +S_API bool SteamAPI_ISteamGameServerStats_UpdateUserAvgRateStat( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName, float flCountThisSession, double dSessionLength ); +S_API bool SteamAPI_ISteamGameServerStats_SetUserAchievement( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName ); +S_API bool SteamAPI_ISteamGameServerStats_ClearUserAchievement( ISteamGameServerStats* self, uint64_steamid steamIDUser, const char * pchName ); +S_API SteamAPICall_t SteamAPI_ISteamGameServerStats_StoreUserStats( ISteamGameServerStats* self, uint64_steamid steamIDUser ); + +// ISteamNetworkingFakeUDPPort +S_API void SteamAPI_ISteamNetworkingFakeUDPPort_DestroyFakeUDPPort( ISteamNetworkingFakeUDPPort* self ); +S_API EResult SteamAPI_ISteamNetworkingFakeUDPPort_SendMessageToFakeIP( ISteamNetworkingFakeUDPPort* self, const SteamNetworkingIPAddr & remoteAddress, const void * pData, uint32 cbData, int nSendFlags ); +S_API int SteamAPI_ISteamNetworkingFakeUDPPort_ReceiveMessages( ISteamNetworkingFakeUDPPort* self, SteamNetworkingMessage_t ** ppOutMessages, int nMaxMessages ); +S_API void SteamAPI_ISteamNetworkingFakeUDPPort_ScheduleCleanup( ISteamNetworkingFakeUDPPort* self, const SteamNetworkingIPAddr & remoteAddress ); + +// SteamIPAddress_t +S_API bool SteamAPI_SteamIPAddress_t_IsSet( SteamIPAddress_t* self ); + +// MatchMakingKeyValuePair_t +S_API void SteamAPI_MatchMakingKeyValuePair_t_Construct( MatchMakingKeyValuePair_t* self ); + +// servernetadr_t +S_API void SteamAPI_servernetadr_t_Construct( servernetadr_t* self ); +S_API void SteamAPI_servernetadr_t_Init( servernetadr_t* self, unsigned int ip, uint16 usQueryPort, uint16 usConnectionPort ); +S_API uint16 SteamAPI_servernetadr_t_GetQueryPort( servernetadr_t* self ); +S_API void SteamAPI_servernetadr_t_SetQueryPort( servernetadr_t* self, uint16 usPort ); +S_API uint16 SteamAPI_servernetadr_t_GetConnectionPort( servernetadr_t* self ); +S_API void SteamAPI_servernetadr_t_SetConnectionPort( servernetadr_t* self, uint16 usPort ); +S_API uint32 SteamAPI_servernetadr_t_GetIP( servernetadr_t* self ); +S_API void SteamAPI_servernetadr_t_SetIP( servernetadr_t* self, uint32 unIP ); +S_API const char * SteamAPI_servernetadr_t_GetConnectionAddressString( servernetadr_t* self ); +S_API const char * SteamAPI_servernetadr_t_GetQueryAddressString( servernetadr_t* self ); +S_API bool SteamAPI_servernetadr_t_IsLessThan( servernetadr_t* self, const servernetadr_t & netadr ); +S_API void SteamAPI_servernetadr_t_Assign( servernetadr_t* self, const servernetadr_t & that ); + +// gameserveritem_t +S_API void SteamAPI_gameserveritem_t_Construct( gameserveritem_t* self ); +S_API const char * SteamAPI_gameserveritem_t_GetName( gameserveritem_t* self ); +S_API void SteamAPI_gameserveritem_t_SetName( gameserveritem_t* self, const char * pName ); + +// SteamNetworkingIPAddr +S_API void SteamAPI_SteamNetworkingIPAddr_Clear( SteamNetworkingIPAddr* self ); +S_API bool SteamAPI_SteamNetworkingIPAddr_IsIPv6AllZeros( SteamNetworkingIPAddr* self ); +S_API void SteamAPI_SteamNetworkingIPAddr_SetIPv6( SteamNetworkingIPAddr* self, const uint8 * ipv6, uint16 nPort ); +S_API void SteamAPI_SteamNetworkingIPAddr_SetIPv4( SteamNetworkingIPAddr* self, uint32 nIP, uint16 nPort ); +S_API bool SteamAPI_SteamNetworkingIPAddr_IsIPv4( SteamNetworkingIPAddr* self ); +S_API uint32 SteamAPI_SteamNetworkingIPAddr_GetIPv4( SteamNetworkingIPAddr* self ); +S_API void SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( SteamNetworkingIPAddr* self, uint16 nPort ); +S_API bool SteamAPI_SteamNetworkingIPAddr_IsLocalHost( SteamNetworkingIPAddr* self ); +S_API void SteamAPI_SteamNetworkingIPAddr_ToString( SteamNetworkingIPAddr* self, char * buf, uint32 cbBuf, bool bWithPort ); +S_API bool SteamAPI_SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr* self, const char * pszStr ); +S_API bool SteamAPI_SteamNetworkingIPAddr_IsEqualTo( SteamNetworkingIPAddr* self, const SteamNetworkingIPAddr & x ); +S_API ESteamNetworkingFakeIPType SteamAPI_SteamNetworkingIPAddr_GetFakeIPType( SteamNetworkingIPAddr* self ); +S_API bool SteamAPI_SteamNetworkingIPAddr_IsFakeIP( SteamNetworkingIPAddr* self ); + +// SteamNetworkingIdentity +S_API void SteamAPI_SteamNetworkingIdentity_Clear( SteamNetworkingIdentity* self ); +S_API bool SteamAPI_SteamNetworkingIdentity_IsInvalid( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetSteamID( SteamNetworkingIdentity* self, uint64_steamid steamID ); +S_API uint64_steamid SteamAPI_SteamNetworkingIdentity_GetSteamID( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetSteamID64( SteamNetworkingIdentity* self, uint64 steamID ); +S_API uint64 SteamAPI_SteamNetworkingIdentity_GetSteamID64( SteamNetworkingIdentity* self ); +S_API bool SteamAPI_SteamNetworkingIdentity_SetXboxPairwiseID( SteamNetworkingIdentity* self, const char * pszString ); +S_API const char * SteamAPI_SteamNetworkingIdentity_GetXboxPairwiseID( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetPSNID( SteamNetworkingIdentity* self, uint64 id ); +S_API uint64 SteamAPI_SteamNetworkingIdentity_GetPSNID( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetStadiaID( SteamNetworkingIdentity* self, uint64 id ); +S_API uint64 SteamAPI_SteamNetworkingIdentity_GetStadiaID( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetIPAddr( SteamNetworkingIdentity* self, const SteamNetworkingIPAddr & addr ); +S_API const SteamNetworkingIPAddr * SteamAPI_SteamNetworkingIdentity_GetIPAddr( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetIPv4Addr( SteamNetworkingIdentity* self, uint32 nIPv4, uint16 nPort ); +S_API uint32 SteamAPI_SteamNetworkingIdentity_GetIPv4( SteamNetworkingIdentity* self ); +S_API ESteamNetworkingFakeIPType SteamAPI_SteamNetworkingIdentity_GetFakeIPType( SteamNetworkingIdentity* self ); +S_API bool SteamAPI_SteamNetworkingIdentity_IsFakeIP( SteamNetworkingIdentity* self ); +S_API void SteamAPI_SteamNetworkingIdentity_SetLocalHost( SteamNetworkingIdentity* self ); +S_API bool SteamAPI_SteamNetworkingIdentity_IsLocalHost( SteamNetworkingIdentity* self ); +S_API bool SteamAPI_SteamNetworkingIdentity_SetGenericString( SteamNetworkingIdentity* self, const char * pszString ); +S_API const char * SteamAPI_SteamNetworkingIdentity_GetGenericString( SteamNetworkingIdentity* self ); +S_API bool SteamAPI_SteamNetworkingIdentity_SetGenericBytes( SteamNetworkingIdentity* self, const void * data, uint32 cbLen ); +S_API const uint8 * SteamAPI_SteamNetworkingIdentity_GetGenericBytes( SteamNetworkingIdentity* self, int & cbLen ); +S_API bool SteamAPI_SteamNetworkingIdentity_IsEqualTo( SteamNetworkingIdentity* self, const SteamNetworkingIdentity & x ); +S_API void SteamAPI_SteamNetworkingIdentity_ToString( SteamNetworkingIdentity* self, char * buf, uint32 cbBuf ); +S_API bool SteamAPI_SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity* self, const char * pszStr ); + +// SteamNetworkingMessage_t +S_API void SteamAPI_SteamNetworkingMessage_t_Release( SteamNetworkingMessage_t* self ); + +// SteamNetworkingConfigValue_t +S_API void SteamAPI_SteamNetworkingConfigValue_t_SetInt32( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, int32_t data ); +S_API void SteamAPI_SteamNetworkingConfigValue_t_SetInt64( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, int64_t data ); +S_API void SteamAPI_SteamNetworkingConfigValue_t_SetFloat( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, float data ); +S_API void SteamAPI_SteamNetworkingConfigValue_t_SetPtr( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, void * data ); +S_API void SteamAPI_SteamNetworkingConfigValue_t_SetString( SteamNetworkingConfigValue_t* self, ESteamNetworkingConfigValue eVal, const char * data ); + +// SteamDatagramHostedAddress +S_API void SteamAPI_SteamDatagramHostedAddress_Clear( SteamDatagramHostedAddress* self ); +S_API SteamNetworkingPOPID SteamAPI_SteamDatagramHostedAddress_GetPopID( SteamDatagramHostedAddress* self ); +S_API void SteamAPI_SteamDatagramHostedAddress_SetDevAddress( SteamDatagramHostedAddress* self, uint32 nIP, uint16 nPort, SteamNetworkingPOPID popid ); +#endif // STEAMAPIFLAT_H diff --git a/Amalgam/src/SDK/Definitions/Steam/Steam_API_Internal.h b/Amalgam/src/SDK/Definitions/Steam/Steam_API_Internal.h new file mode 100644 index 0000000..ff11002 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/Steam_API_Internal.h @@ -0,0 +1,399 @@ +//====== 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 to locate/create interfaces +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 ); + +// 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. +// +// SteamInternal_ContextInit takes a base pointer for the equivalent of +// struct { void (*pFn)(void* pCtx); uintptr_t counter; void *ptr; } +// Do not change layout or add non-pointer aligned data! +#define STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, expr, kind, version ) \ + inline void S_CALLTYPE SteamInternal_Init_ ## name( type *p ) { *p = (type)( expr ); } \ + STEAM_CLANG_ATTR( "interface_accessor_kind:" kind ";interface_accessor_version:" version ";" ) \ + inline type name() { \ + static void* s_CallbackCounterAndContext[ 3 ] = { (void*)&SteamInternal_Init_ ## name, 0, 0 }; \ + return *(type*)SteamInternal_ContextInit( s_CallbackCounterAndContext ); \ + } + +#define STEAM_DEFINE_USER_INTERFACE_ACCESSOR( type, name, version ) \ + STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, SteamInternal_FindOrCreateUserInterface( SteamAPI_GetHSteamUser(), version ), "user", version ) +#define STEAM_DEFINE_GAMESERVER_INTERFACE_ACCESSOR( type, name, version ) \ + STEAM_DEFINE_INTERFACE_ACCESSOR( type, name, SteamInternal_FindOrCreateGameServerInterface( SteamGameServer_GetHSteamUser(), version ), "gameserver", version ) + +// +// Internal stuff used for the standard, higher-level callback mechanism +// + +// 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 ); + +#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 ) + +#ifndef API_GEN + +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); +} + +#endif // #ifndef API_GEN + +// 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 + +/// Internal structure used in manual callback dispatch +struct CallbackMsg_t +{ + HSteamUser m_hSteamUser; // Specific user to whom this callback applies. + int m_iCallback; // Callback identifier. (Corresponds to the k_iCallback enum in the callback structure.) + uint8 *m_pubParam; // Points to the callback structure + int m_cubParam; // Size of the data pointed to by m_pubParam +}; +#pragma pack( pop ) + +// 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 ISteamRemotePlay; + +// Forward declare types +struct SteamNetworkingIdentity; + +//----------------------------------------------------------------------------- +// 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_iSteamAppsCallbacks = 1000 }; +enum { k_iSteamUserStatsCallbacks = 1100 }; +enum { k_iSteamNetworkingCallbacks = 1200 }; +enum { k_iSteamNetworkingSocketsCallbacks = 1220 }; +enum { k_iSteamNetworkingMessagesCallbacks = 1250 }; +enum { k_iSteamNetworkingUtilsCallbacks = 1280 }; +enum { k_iSteamRemoteStorageCallbacks = 1300 }; +enum { k_iSteamGameServerItemsCallbacks = 1500 }; +enum { k_iSteamGameCoordinatorCallbacks = 1700 }; +enum { k_iSteamGameServerStatsCallbacks = 1800 }; +enum { k_iSteam2AsyncCallbacks = 1900 }; +enum { k_iSteamGameStatsCallbacks = 2000 }; +enum { k_iSteamHTTPCallbacks = 2100 }; +enum { k_iSteamScreenshotsCallbacks = 2300 }; +// NOTE: 2500-2599 are reserved +enum { k_iSteamStreamLauncherCallbacks = 2600 }; +enum { k_iSteamControllerCallbacks = 2800 }; +enum { k_iSteamUGCCallbacks = 3400 }; +enum { k_iSteamStreamClientCallbacks = 3500 }; +enum { k_iSteamAppListCallbacks = 3900 }; +enum { k_iSteamMusicCallbacks = 4000 }; +enum { k_iSteamMusicRemoteCallbacks = 4100 }; +enum { k_iSteamGameNotificationCallbacks = 4400 }; +enum { k_iSteamHTMLSurfaceCallbacks = 4500 }; +enum { k_iSteamVideoCallbacks = 4600 }; +enum { k_iSteamInventoryCallbacks = 4700 }; +enum { k_ISteamParentalSettingsCallbacks = 5000 }; +enum { k_iSteamGameSearchCallbacks = 5200 }; +enum { k_iSteamPartiesCallbacks = 5300 }; +enum { k_iSteamSTARCallbacks = 5500 }; +enum { k_iSteamRemotePlayCallbacks = 5700 }; +enum { k_iSteamChatCallbacks = 5900 }; +// NOTE: Internal "IClientXxx" callback IDs go in clientenums.h + +// Macros used to annotate various Steamworks interfaces to generate the +// flat API +#ifdef API_GEN +# define STEAM_CLANG_ATTR(ATTR) __attribute__((annotate( ATTR ))) +#else +# define STEAM_CLANG_ATTR(ATTR) +#endif + +#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 ";") +#define STEAM_FLAT_NAME(NAME) STEAM_CLANG_ATTR("flat_name:" #NAME ";") + +// 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; } + 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; + 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; } + +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; +}; + + diff --git a/Amalgam/src/SDK/Definitions/Steam/Steam_Gameserver.h b/Amalgam/src/SDK/Definitions/Steam/Steam_Gameserver.h new file mode 100644 index 0000000..91f9b12 --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Steam/Steam_Gameserver.h @@ -0,0 +1,117 @@ +//====== 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 +}; + +/// Pass to SteamGameServer_Init to indicate that the same UDP port will be used for game traffic +/// UDP queries for server browser pings and LAN discovery. In this case, Steam will not open up a +/// socket to handle server browser queries, and you must use ISteamGameServer::HandleIncomingPacket +/// and ISteamGameServer::GetNextOutgoingPacket to handle packets related to server discovery on your socket. +const uint16 STEAMGAMESERVER_QUERY_PORT_SHARED = 0xffff; + +// DEPRECATED: This old name was really confusing. +const uint16 MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE = STEAMGAMESERVER_QUERY_PORT_SHARED; + +// 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() +// +// - unIP will usually be zero. If you are on a machine with multiple IP addresses, you can pass a non-zero +// value here and the relevant sockets will be bound to that IP. This can be used to ensure that +// the IP you desire is the one used in the server browser. +// - usGamePort is the port that clients will connect to for gameplay. You will usually open up your +// own socket bound to this port. +// - usQueryPort is the port that will manage server browser related duties and info +// pings from clients. If you pass STEAMGAMESERVER_QUERY_PORT_SHARED 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 ISteamGameServer::HandleIncomingPacket and +// ISteamGameServer::GetNextOutgoingPacket.) +// - The version string should be 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 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(); + if ( !m_pSteamGameServer || !m_pSteamGameServerUtils || !m_pSteamGameServerNetworking || !m_pSteamGameServerStats + || !m_pSteamHTTP || !m_pSteamInventory || !m_pSteamUGC ) + return false; + + return true; +} +#endif + +S_API bool S_CALLTYPE SteamInternal_GameServer_Init( uint32 unIP, uint16 usLegacySteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); +inline bool SteamGameServer_Init( uint32 unIP, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ) +{ + if ( !SteamInternal_GameServer_Init( unIP, 0, usGamePort, usQueryPort, eServerMode, pchVersionString ) ) + return false; + + return true; +} +inline void SteamGameServer_ReleaseCurrentThreadMemory() +{ + SteamAPI_ReleaseCurrentThreadMemory(); +} + +#endif // STEAM_GAMESERVER_H diff --git a/Amalgam/src/SDK/Definitions/Types.h b/Amalgam/src/SDK/Definitions/Types.h new file mode 100644 index 0000000..083c60c --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Types.h @@ -0,0 +1,576 @@ +#pragma once +#include +#include +#include +#include + +#pragma warning (disable : 26495) + +class Vec2 +{ +public: + float x = 0.f, y = 0.f; + +public: + Vec2(void) + { + x = y = 0.f; + } + + Vec2(float X, float Y) + { + x = X; y = Y; + } + + Vec2(float* v) + { + x = v[0]; y = v[1]; + } + + Vec2(const float* v) + { + x = v[0]; y = v[1]; + } + + Vec2(const Vec2& v) + { + x = v.x; y = v.y; + } + + Vec2& operator=(const Vec2& v) + { + x = v.x; y = v.y; return *this; + } + + float& operator[](int i) + { + return ((float*)this)[i]; + } + + float operator[](int i) const + { + return ((float*)this)[i]; + } + + Vec2& operator+=(const Vec2& v) + { + x += v.x; y += v.y; return *this; + } + + Vec2& operator-=(const Vec2& v) + { + x -= v.x; y -= v.y; return *this; + } + + Vec2& operator*=(const Vec2& v) + { + x *= v.x; y *= v.y; return *this; + } + + Vec2& operator/=(const Vec2& v) + { + x /= v.x; y /= v.y; return *this; + } + + Vec2& operator+=(float v) + { + x += v; y += v; return *this; + } + + Vec2& operator-=(float v) + { + x -= v; y -= v; return *this; + } + + Vec2& operator*=(float v) + { + x *= v; y *= v; return *this; + } + + Vec2& operator/=(float v) + { + x /= v; y /= v; return *this; + } + + Vec2 operator+(const Vec2& v) const + { + return Vec2(x + v.x, y + v.y); + } + + Vec2 operator-(const Vec2& v) const + { + return Vec2(x - v.x, y - v.y); + } + + Vec2 operator*(const Vec2& v) const + { + return Vec2(x * v.x, y * v.y); + } + + Vec2 operator/(const Vec2& v) const + { + return Vec2(x / v.x, y / v.y); + } + + Vec2 operator+(float v) const + { + return Vec2(x + v, y + v); + } + + Vec2 operator-(float v) const + { + return Vec2(x - v, y - v); + } + + Vec2 operator*(float v) const + { + return Vec2(x * v, y * v); + } + + Vec2 operator/(float v) const + { + return Vec2(x / v, y / v); + } + + void Set(float X = 0.f, float Y = 0.f) + { + x = X; y = Y; + } + + float Length(void) const + { + return sqrtf(x * x + y * y); + } + + float LengthSqr(void) const + { + return (x * x + y * y); + } + + float DistTo(const Vec2& v) const + { + return (*this - v).Length(); + } + + float DistToSqr(const Vec2& v) const + { + return (*this - v).LengthSqr(); + } + + float Dot(const Vec2& v) const + { + return x * v.x + y * v.y; + } + + bool IsZero(void) const + { + return fabsf(x) < 0.001f && + fabsf(y) < 0.001f; + } +}; +using Vector2D = Vec2; + +class Vec3 +{ +public: + float x = 0.f, y = 0.f, z = 0.f; + +public: + Vec3(void) + { + x = y = z = 0.f; + } + + void Zero() + { + x = y = z = 0.f; + } + + Vec3(float X, float Y, float Z) + { + x = X; y = Y; z = Z; + } + + Vec3(float* v) + { + x = v[0]; y = v[1]; z = v[2]; + } + + Vec3(const float* v) + { + x = v[0]; y = v[1]; z = v[2]; + } + + Vec3(const Vec3& v) + { + x = v.x; y = v.y; z = v.z; + } + + Vec3(const Vec2& v) + { + x = v.x; y = v.y; z = 0.f; + } + + Vec3& operator=(const Vec3& v) + { + x = v.x; y = v.y; z = v.z; return *this; + } + + Vec3& operator=(const Vec2& v) + { + x = v.x; y = v.y; z = 0.f; return *this; + } + + float& operator[](int i) + { + return ((float*)this)[i]; + } + + float operator[](int i) const + { + return ((float*)this)[i]; + } + + Vec3& operator+=(const Vec3& v) + { + x += v.x; y += v.y; z += v.z; return *this; + } + + Vec3& operator-=(const Vec3& v) + { + x -= v.x; y -= v.y; z -= v.z; return *this; + } + + Vec3& operator*=(const Vec3& v) + { + x *= v.x; y *= v.y; z *= v.z; return *this; + } + + Vec3& operator/=(const Vec3& v) + { + x /= v.x; y /= v.y; z /= v.z; return *this; + } + + Vec3& operator+=(float v) + { + x += v; y += v; z += v; return *this; + } + + Vec3& operator-=(float v) + { + x -= v; y -= v; z -= v; return *this; + } + + Vec3& operator*=(float v) + { + x *= v; y *= v; z *= v; return *this; + } + + Vec3& operator/=(float v) + { + x /= v; y /= v; z /= v; return *this; + } + + Vec3 operator+(const Vec3& v) const + { + return Vec3(x + v.x, y + v.y, z + v.z); + } + + Vec3 operator-(const Vec3& v) const + { + return Vec3(x - v.x, y - v.y, z - v.z); + } + + Vec3 operator*(const Vec3& v) const + { + return Vec3(x * v.x, y * v.y, z * v.z); + } + + Vec3 operator/(const Vec3& v) const + { + return Vec3(x / v.x, y / v.y, z / v.z); + } + + Vec3 operator+(float v) const + { + return Vec3(x + v, y + v, z + v); + } + + Vec3 operator-(float v) const + { + return Vec3(x - v, y - v, z - v); + } + + Vec3 operator*(float v) const + { + return Vec3(x * v, y * v, z * v); + } + + Vec3 operator/(float v) const + { + return Vec3(x / v, y / v, z / v); + } + + bool operator==(const Vec3& v) const + { + return (x == v.x && y == v.y && z == v.z); + } + + bool operator!=(const Vec3& v) const + { + return (x != v.x || y != v.y || z != v.z); + } + + void Set(float X = 0.f, float Y = 0.f, float Z = 0.f) + { + x = X; y = Y; z = Z; + } + + float Length(void) const + { + return sqrtf(x * x + y * y + z * z); + } + + float LengthSqr(void) const + { + return (x * x + y * y + z * z); + } + + float Normalize() + { + float fl_Length = Length(); + float fl_Length_normal = 1.f / (FLT_EPSILON + fl_Length); + + x = x * fl_Length_normal; + y = y * fl_Length_normal; + z = z * fl_Length_normal; + + return fl_Length; + } + + float NormalizeInPlace() + { + return Normalize(); + } + + float Length2D(void) const + { + return sqrtf(x * x + y * y); + } + + float Length2DSqr(void) const + { + return (x * x + y * y); + } + + float DistTo(const Vec3& v) const + { + return (*this - v).Length(); + } + + float DistToSqr(const Vec3& v) const + { + return (*this - v).LengthSqr(); + } + + float Dot(const Vec3& v) const + { + return x * v.x + y * v.y + z * v.z; + } + + Vec3 Cross(const Vec3& v) const + { + return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); + } + + bool IsZero(void) const + { + return fabsf(x) < 0.001f && + fabsf(y) < 0.001f && + fabsf(z) < 0.001f; + } + + Vec3 Scale(float fl) + { + return Vec3(x * fl, y * fl, z * fl); + } + + void Init(float ix, float iy, float iz) + { + x = ix; y = iy; z = iz; + } + + Vec3 toAngle() const noexcept + { + return { (atan2(-z, hypot(x, y))) * (180.f / 3.14159265358979323846f), + (atan2(y, x)) * (180.f / 3.14159265358979323846f), + 0.f }; + } + Vec3 fromAngle() const noexcept + { + return { cos(x * (3.14159265358979323846f / 180.f)) * cos(y * (3.14159265358979323846f / 180.f)), + cos(x * (3.14159265358979323846f / 180.f)) * sin(y * (3.14159265358979323846f / 180.f)), + -sin(x * (3.14159265358979323846f / 180.f)) }; + } +}; +using Vector = Vec3; +using QAngle = Vec3; +using RadianEuler = Vec3; + +class Vector4D +{ +public: + float x, y, z, w; +}; +using Quaternion = Vector4D; + +using matrix3x4 = float[3][4]; +class VMatrix +{ +public: + Vector m[4][4]; + +public: + inline const matrix3x4& As3x4() const + { + return *((const matrix3x4*)this); + } +}; + +struct IntRange_t +{ + int Min = 0, Max = 0; + + bool operator==(IntRange_t other) const + { + return Min == other.Min && Max == other.Max; + } + + bool operator!=(IntRange_t other) const + { + return Min != other.Min || Max != other.Max; + } +}; + +struct FloatRange_t +{ + float Min = 0, Max = 0; + + bool operator==(FloatRange_t other) const + { + return Min == other.Min && Max == other.Max; + } + + bool operator!=(FloatRange_t other) const + { + return Min != other.Min || Max != other.Max; + } +}; + +using byte = unsigned char; +struct Color_t +{ + byte r = 0, g = 0, b = 0, a = 0; + + bool operator==(Color_t other) const + { + return r == other.r && g == other.g && b == other.b && a == other.a; + } + + bool operator!=(Color_t other) const + { + return r != other.r || g != other.g || b != other.b || a != other.a; + } + + std::string ToHex() const + { + return std::format("\x7{:02X}{:02X}{:02X}", r, g, b); + } + + std::string ToHexA() const + { + return std::format("\x8{:02X}{:02X}{:02X}{:02X}", r, g, b, a); + } + + Color_t Lerp(Color_t to, float t) const + { + //a + (b - a) * t + return { + byte(r + (to.r - r) * t), + byte(g + (to.g - g) * t), + byte(b + (to.b - b) * t), + byte(a + (to.a - a) * t), + }; + } +}; + +struct Gradient_t +{ + Color_t StartColor = { 0, 0, 0, 255 }; + Color_t EndColor = { 0, 0, 0, 255 }; + + bool operator==(Gradient_t other) const + { + return StartColor == other.StartColor && EndColor == other.EndColor; + } + + bool operator!=(Gradient_t other) const + { + return StartColor != other.StartColor || EndColor != other.EndColor; + } +}; + +struct Chams_t +{ + std::vector VisibleMaterial = { "Original" }; + std::vector OccludedMaterial = {}; + Color_t VisibleColor = { 255, 255, 255, 255 }; + Color_t OccludedColor = { 255, 255, 255, 255 }; +}; + +struct Glow_t +{ + bool Stencil = false; + bool Blur = false; + int StencilScale = 1; + int BlurScale = 1; + + bool operator==(const Glow_t& other) const + { + return Stencil == other.Stencil && Blur == other.Blur && StencilScale == other.StencilScale && BlurScale == other.BlurScale; + } +}; + +struct DragBox_t +{ + int x = 100; + int y = 100; + + bool operator==(DragBox_t other) const + { + return x == other.x && y == other.y; + } + + bool operator!=(DragBox_t other) const + { + return x != other.x || y != other.y; + } +}; + +struct WindowBox_t +{ + int x = 100; + int y = 100; + int w = 200; + int h = 150; + + bool operator==(WindowBox_t other) const + { + return x == other.x && y == other.y && w == other.w && h == other.h; + } + + bool operator!=(WindowBox_t other) const + { + return x != other.x || y != other.y || w != other.w || h != other.h; + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Globals.h b/Amalgam/src/SDK/Globals.h new file mode 100644 index 0000000..d6cd1f2 --- /dev/null +++ b/Amalgam/src/SDK/Globals.h @@ -0,0 +1,108 @@ +#pragma once +#include "Definitions/Definitions.h" +#include "Definitions/Main/CUserCmd.h" +#include "../Utils/Signatures/Signatures.h" +#include "../Utils/Memory/Memory.h" + +MAKE_SIGNATURE(Get_RandomSeed, "client.dll", "0F B6 1D ? ? ? ? 89 9D", 0x0); + +struct DormantData +{ + Vec3 Location; + float LastUpdate = 0.f; +}; + +struct VelFixRecord +{ + Vec3 m_vecOrigin; + float m_flHeight; + float m_flSimulationTime; +}; + +struct DrawBullet +{ + std::pair m_line; + float m_flTime; + Color_t m_color; + bool m_bZBuffer = false; +}; + +struct DrawLine +{ + std::deque> m_line; + float m_flTime; + Color_t m_color; + bool m_bZBuffer = false; +}; + +struct DrawBox +{ + Vec3 m_vecPos; + Vec3 m_vecMins; + Vec3 m_vecMaxs; + Vec3 m_vecOrientation; + float m_flTime; + Color_t m_colorEdge; + Color_t m_colorFace; + bool m_bZBuffer = false; +}; + +namespace G +{ + inline bool Unload = false; + + inline bool IsAttacking = false; + inline bool CanPrimaryAttack = false; + inline bool CanSecondaryAttack = false; + inline bool CanHeadshot = false; + inline float Lerp = 0.015f; + + inline EWeaponType WeaponType = {}; + inline int WeaponDefIndex = 0; + + inline CUserCmd* CurrentUserCmd = nullptr; + inline CUserCmd* LastUserCmd = nullptr; + inline int Buttons = 0; + + inline std::pair Target = { 0, 0 }; + inline Vec3 AimPosition = {}; + inline Vec3 ViewAngles = {}; + inline Vec3 PunchAngles = {}; + + inline bool SilentAngles = false; + inline bool PSilentAngles = false; + + inline int ShiftedTicks = 0; + inline int ShiftedGoal = 0; + inline int WaitForShift = 0; + inline bool DoubleTap = false; + inline bool AntiWarp = false; + inline bool Warp = false; + inline bool Recharge = false; + inline int MaxShift = 24; + + inline bool AntiAim = false; + inline bool Busy = false; + inline int ChokeAmount = 0; + inline int ChokeGoal = 0; + inline int AnticipatedChoke = 0; + inline bool Choking = false; + + inline bool UpdatingAnims = false; + inline bool AnimateKart = false; + inline bool DrawingProps = false; + + inline std::unordered_map DormancyMap = {}; + inline std::unordered_map ChokeMap = {}; + inline std::unordered_map VelocityMap = {}; + + inline std::vector BulletsStorage = {}; + inline std::vector LinesStorage = {}; + inline std::vector BoxesStorage = {}; + + inline int* RandomSeed() + { + static auto dest = U::Memory.RelToAbs(S::Get_RandomSeed()); + return reinterpret_cast(dest); + } +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Color/Color.cpp b/Amalgam/src/SDK/Helpers/Color/Color.cpp new file mode 100644 index 0000000..8ec67de --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Color/Color.cpp @@ -0,0 +1,55 @@ +#include "Color.h" + +#include "../../Vars.h" +#include "../../../Features/Players/PlayerUtils.h" + +Color_t CColor::GetTeamColor(int iLocalTeam, int iTargetTeam, bool bOther) +{ + if (bOther) + return iLocalTeam == iTargetTeam ? Vars::Colors::Team.Value : Vars::Colors::Enemy.Value; + else + { + switch (iTargetTeam) + { + case 2: return Vars::Colors::TeamRed.Value; + case 3: return Vars::Colors::TeamBlu.Value; + } + } + + return { 255, 255, 255, 255 }; +} + +Color_t CColor::GetEntityDrawColor(CTFPlayer* pLocal, CBaseEntity* pEntity, bool enableOtherColors) +{ + Color_t out = GetTeamColor(pLocal->m_iTeamNum(), pEntity->m_iTeamNum(), enableOtherColors); + + if (pEntity->IsPlayer()) + { + auto pPlayer = pEntity->As(); + + if (pLocal == pPlayer) + out = Vars::Colors::Local.Value; + else if (H::Entities.IsFriend(pPlayer->entindex())) + out = F::PlayerUtils.mTags["Friend"].Color; + + PlayerInfo_t pi{}; bool bTagColor = false; Color_t cTagColor; + if (I::EngineClient->GetPlayerInfo(pPlayer->entindex(), &pi)) + { + std::string _; PriorityLabel_t plTag; + if (bTagColor = F::PlayerUtils.GetSignificantTag(pi.friendsID, &_, &plTag)) + cTagColor = plTag.Color; + } + + if (bTagColor) + out = cTagColor; + else if (pPlayer->IsCloaked()) + out = Vars::Colors::Cloak.Value; + else if (pPlayer->IsInvulnerable()) + out = Vars::Colors::Invulnerable.Value; + } + + if (pEntity->entindex() == G::Target.first && abs(G::Target.second - I::GlobalVars->tickcount) < 32) + out = Vars::Colors::Target.Value; + + return out; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Color/Color.h b/Amalgam/src/SDK/Helpers/Color/Color.h new file mode 100644 index 0000000..729ac2a --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Color/Color.h @@ -0,0 +1,12 @@ +#pragma once +#include "../../Definitions/Types.h" +#include "../../Definitions/Main/CTFPlayer.h" + +class CColor +{ +public: + Color_t GetTeamColor(int iLocalTeam, int iTargetTeam, bool bOther); + Color_t GetEntityDrawColor(CTFPlayer* pLocal, CBaseEntity* pEntity, bool enableOtherColors); +}; + +ADD_FEATURE_CUSTOM(CColor, Color, H) \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Draw/Draw.cpp b/Amalgam/src/SDK/Helpers/Draw/Draw.cpp new file mode 100644 index 0000000..31e1ebf --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Draw/Draw.cpp @@ -0,0 +1,366 @@ +#include "Draw.h" + +#include "Icons.h" +#include "../../Definitions/Interfaces.h" +#include "../../../Utils/Math/Math.h" +//#include "../../Includes/icons.h" +#include +#include + +MAKE_SIGNATURE(CDraw_GetIcon, "client.dll", "40 53 48 81 EC ? ? ? ? 48 8B DA", 0x0); + +void CDraw::UpdateScreenSize() +{ + m_nScreenW = I::BaseClientDLL->GetScreenWidth(); + m_nScreenH = I::BaseClientDLL->GetScreenHeight(); +} + +void CDraw::UpdateW2SMatrix() +{ + CViewSetup ViewSetup = {}; + + if (I::BaseClientDLL->GetPlayerView(ViewSetup)) + { + static VMatrix WorldToView = {}; + static VMatrix ViewToProjection = {}; + static VMatrix WorldToPixels = {}; + + I::RenderView->GetMatricesForView(ViewSetup, &WorldToView, &ViewToProjection, &m_WorldToProjection, &WorldToPixels); + } +} + +void CDraw::String(const Font_t& font, int x, int y, const Color_t& clr, const EAlign& align, const char* str, ...) +{ + if (str == nullptr) + return; + + va_list va_alist; + char cbuffer[1024] = { '\0' }; + wchar_t wstr[1024] = { '\0' }; + + va_start(va_alist, str); + vsprintf_s(cbuffer, str, va_alist); + va_end(va_alist); + + wsprintfW(wstr, L"%hs", cbuffer); + + const auto dwFont = font.m_dwFont; + + int w = 0, h = 0; I::MatSystemSurface->GetTextSize(dwFont, wstr, w, h); + switch (align) + { + case ALIGN_TOPLEFT: break; + case ALIGN_TOP: x -= w / 2; break; + case ALIGN_TOPRIGHT: x -= w; break; + case ALIGN_LEFT: y -= h / 2; break; + case ALIGN_CENTER: x -= w / 2; y -= h / 2; break; + case ALIGN_RIGHT: x -= w; y -= h / 2; break; + case ALIGN_BOTTOMLEFT: y -= h; break; + case ALIGN_BOTTOM: x -= w / 2; y -= h; break; + case ALIGN_BOTTOMRIGHT: x -= w; y -= h; break; + } + + I::MatSystemSurface->DrawSetTextPos(x, y); + I::MatSystemSurface->DrawSetTextFont(dwFont); + I::MatSystemSurface->DrawSetTextColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawPrintText(wstr, int(wcslen(wstr))); +} +void CDraw::String(const Font_t& font, int x, int y, const Color_t& clr, const EAlign& align, const wchar_t* str, ...) +{ + if (str == nullptr) + return; + + va_list va_alist; + wchar_t wstr[1024] = { '\0' }; + + va_start(va_alist, str); + vswprintf_s(wstr, str, va_alist); + va_end(va_alist); + + const auto dwFont = font.m_dwFont; + + int w = 0, h = 0; I::MatSystemSurface->GetTextSize(dwFont, wstr, w, h); + switch (align) + { + case ALIGN_TOPLEFT: break; + case ALIGN_TOP: x -= w / 2; break; + case ALIGN_TOPRIGHT: x -= w; break; + case ALIGN_LEFT: y -= h / 2; break; + case ALIGN_CENTER: x -= w / 2; y -= h / 2; break; + case ALIGN_RIGHT: x -= w; y -= h / 2; break; + case ALIGN_BOTTOMLEFT: y -= h; break; + case ALIGN_BOTTOM: x -= w / 2; y -= h; break; + case ALIGN_BOTTOMRIGHT: x -= w; y -= h; break; + } + + I::MatSystemSurface->DrawSetTextPos(x, y); + I::MatSystemSurface->DrawSetTextFont(dwFont); + I::MatSystemSurface->DrawSetTextColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawPrintText(wstr, int(wcslen(wstr))); +} + +void CDraw::Line(int x, int y, int x1, int y1, const Color_t& clr) +{ + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawLine(x, y, x1, y1); +} +void CDraw::Polygon(int count, Vertex_t* vertices, const Color_t& clr) +{ + static int id = 0; + if (!I::MatSystemSurface->IsTextureIDValid(id)) + id = I::MatSystemSurface->CreateNewTextureID(); + + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawSetTexture(id); + I::MatSystemSurface->DrawTexturedPolygon(count, vertices); +} + +void CDraw::DrawFillTriangle(const std::array& points, const Color_t& clr) +{ + std::array vertices{ Vertex_t(points.at(0)), Vertex_t(points.at(1)), Vertex_t(points.at(2)) }; + Polygon(3, vertices.data(), clr); +} +void CDraw::DrawLineTriangle(const std::array& points, const Color_t& clr) +{ + Line(points.at(0).x, points.at(0).y, points.at(1).x, points.at(1).y, clr); + Line(points.at(1).x, points.at(1).y, points.at(2).x, points.at(2).y, clr); + Line(points.at(2).x, points.at(2).y, points.at(0).x, points.at(0).y, clr); +} + +void CDraw::FillRect(int x, int y, int w, int h, const Color_t& clr) +{ + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawFilledRect(x, y, x + w, y + h); +} +void CDraw::LineRect(int x, int y, int w, int h, const Color_t& clr) +{ + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawOutlinedRect(x, y, x + w, y + h); +} +void CDraw::GradientRect(int x, int y, int w, int h, const Color_t& top_clr, const Color_t& bottom_clr, bool horizontal) +{ + I::MatSystemSurface->DrawSetColor(top_clr.r, top_clr.g, top_clr.b, top_clr.a); + I::MatSystemSurface->DrawFilledRectFade(x, y, x + w, y + h, top_clr.a, bottom_clr.a, horizontal); + I::MatSystemSurface->DrawSetColor(bottom_clr.r, bottom_clr.g, bottom_clr.b, bottom_clr.a); + I::MatSystemSurface->DrawFilledRectFade(x, y, x + w, y + h, top_clr.a, bottom_clr.a, horizontal); +} +void CDraw::FillRectOutline(int x, int y, int w, int h, const Color_t& clr, const Color_t& out) +{ + FillRect(x, y, w, h, clr); + LineRect(x - 1, y - 1, w + 2, h + 2, out); +} +void CDraw::LineRectOutline(int x, int y, int w, int h, const Color_t& clr, const Color_t& out, bool inside) +{ + LineRect(x, y, w, h, clr); + LineRect(x - 1, y - 1, w + 2, h + 2, out); + if (inside) + LineRect(x + 1, y + 1, w - 2, h - 2, out); +} +void CDraw::FillRectPercent(int x, int y, int w, int h, float t, const Color_t& clr, const Color_t& out, const EAlign& align, bool adjust) +{ + if (!adjust) + FillRect(x - 1, y - 1, w + 2, h + 2, out); + int nw = w, nh = h; + switch (align) + { + case ALIGN_LEFT: nw *= t; break; + case ALIGN_RIGHT: nw *= t; x += w - nw; break; + case ALIGN_TOP: nh *= t; break; + case ALIGN_BOTTOM: nh *= t; y += h - nh; break; + } + if (adjust) + FillRect(x - 1, y - 1, nw + 2, nh + 2, out); + FillRect(x, y, nw, nh, clr); +} +void CDraw::RoundRect(int x, int y, int w, int h, int radius, const Color_t& clr) +{ + Vertex_t roundsquare[64]; + + for (int i = 0; i < 4; i++) + { + const int _x = x + ((i < 2) ? (w - radius) : radius); + const int _y = y + ((i % 3) ? (h - radius) : radius); + + const float a = 90.f * i; + + for (int j = 0; j < 16; j++) + { + const float _a = DEG2RAD(a + j * 6.f); + + roundsquare[(i * 16) + j] = Vertex_t(Vector2D(_x + radius * sin(_a), _y - radius * cos(_a))); + } + } + + Polygon(64, roundsquare, clr); +} + +void CDraw::FillCircle(int x, int y, float radius, int segments, const Color_t clr) +{ + static std::vector vertices = {}; + + const float step = static_cast(PI) * 2.0f / segments; + for (float a = 0; a < PI * 2.0f; a += step) + vertices.emplace_back(Vertex_t{ { radius * cosf(a) + x, radius * sinf(a) + y } }); + + Polygon(segments, vertices.data(), clr); + + vertices.clear(); +} +void CDraw::LineCircle(int x, int y, float radius, int segments, const Color_t& clr) +{ + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawOutlinedCircle(x, y, radius, segments); +} + +void CDraw::Texture(int x, int y, int w, int h, int id, const EAlign& align) +{ + switch (align) + { + case ALIGN_TOPLEFT: break; + case ALIGN_TOP: x -= w / 2; break; + case ALIGN_TOPRIGHT: x -= w; break; + case ALIGN_LEFT: y -= h / 2; break; + case ALIGN_CENTER: x -= w / 2; y -= h / 2; break; + case ALIGN_RIGHT: x -= w; y -= h / 2; break; + case ALIGN_BOTTOMLEFT: y -= h; break; + case ALIGN_BOTTOM: x -= w / 2; y -= h; break; + case ALIGN_BOTTOMRIGHT: x -= w; y -= h; break; + } + + int nTexture = 0; + if (ICONS::TEXTURES[id].first != -1) + nTexture = ICONS::TEXTURES[id].first; + else + { + nTexture = ICONS::TEXTURES[id].first = I::MatSystemSurface->CreateNewTextureID(); + I::MatSystemSurface->DrawSetTextureFile(nTexture, ICONS::TEXTURES[id].second.c_str(), false, true); + } + + I::MatSystemSurface->DrawSetColor(255, 255, 255, 255); + I::MatSystemSurface->DrawSetTexture(nTexture); + I::MatSystemSurface->DrawTexturedRect(x, y, x + w, y + h); +} +CHudTexture* CDraw::GetIcon(const char* szIcon, int eIconFormat) // Thanks myzarfin +{ + return S::CDraw_GetIcon.As()(nullptr, szIcon, eIconFormat); +} +int CDraw::CreateTextureFromArray(const unsigned char* rgba, int w, int h) +{ + const int nTextureIdOut = I::MatSystemSurface->CreateNewTextureID(true); + I::MatSystemSurface->DrawSetTextureRGBAEx(nTextureIdOut, rgba, w, h, IMAGE_FORMAT_RGBA8888); + return nTextureIdOut; +} +void CDraw::DrawHudTexture(float x, float y, float s, const CHudTexture* texture, Color_t clr) +{ + if (!texture) + return; + + if (texture->bRenderUsingFont) + { + I::MatSystemSurface->DrawSetTextFont(texture->hFont); + I::MatSystemSurface->DrawSetTextColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawSetTextPos(x, y); + I::MatSystemSurface->DrawUnicodeChar(texture->cCharacterInFont); + } + else if (texture->textureId != -1) + { + I::MatSystemSurface->DrawSetTexture(texture->textureId); + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawTexturedSubRect(x, y, x + texture->Width() * s, y + texture->Height() * s, texture->texCoords[0], texture->texCoords[1], texture->texCoords[2], texture->texCoords[3]); + } +} +void CDraw::DrawHudTextureByName(float x, float y, float s, const char* textureName, Color_t clr) +{ + const CHudTexture* pIcon = GetIcon(textureName, 0); + + if (!pIcon) + return; + + if (pIcon->bRenderUsingFont) + { + I::MatSystemSurface->DrawSetTextFont(pIcon->hFont); + I::MatSystemSurface->DrawSetTextColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawSetTextPos(x, y); + I::MatSystemSurface->DrawUnicodeChar(pIcon->cCharacterInFont); + } + else if (pIcon->textureId != -1) + { + I::MatSystemSurface->DrawSetTexture(pIcon->textureId); + I::MatSystemSurface->DrawSetColor(clr.r, clr.g, clr.b, clr.a); + I::MatSystemSurface->DrawTexturedSubRect(x, y, x + pIcon->Width() * s, y + pIcon->Height() * s, pIcon->texCoords[0], pIcon->texCoords[1], pIcon->texCoords[2], pIcon->texCoords[3]); + } +} + +void CDraw::Avatar(int x, int y, int w, int h, const uint32 nFriendID, const EAlign& align) +{ + if (const auto nID = static_cast(nFriendID + 0x0110000100000000)) + { + switch (align) + { + case ALIGN_TOPLEFT: break; + case ALIGN_TOP: x -= w / 2; break; + case ALIGN_TOPRIGHT: x -= w; break; + case ALIGN_LEFT: y -= h / 2; break; + case ALIGN_CENTER: x -= w / 2; y -= h / 2; break; + case ALIGN_RIGHT: x -= w; y -= h / 2; break; + case ALIGN_BOTTOMLEFT: y -= h; break; + case ALIGN_BOTTOM: x -= w / 2; y -= h; break; + case ALIGN_BOTTOMRIGHT: x -= w; y -= h; break; + } + + if (m_Avatars.contains(nID)) + { + // The avatar has been cached + I::MatSystemSurface->DrawSetColor(255, 255, 255, 255); + I::MatSystemSurface->DrawSetTexture(m_Avatars[nID]); + I::MatSystemSurface->DrawTexturedRect(x, y, x + w, y + h); + } + else + { + // Retrieve the avatar + const int nAvatar = I::SteamFriends->GetMediumFriendAvatar(CSteamID(nID)); + + uint32 newW = 0, newH = 0; + if (I::SteamUtils->GetImageSize(nAvatar, &newW, &newH)) + { + const size_t nSize = 4 * size_t(newW) * size_t(newH) * sizeof(uint8); + auto* pData = static_cast(std::malloc(nSize)); + if (!pData) + return; + + if (I::SteamUtils->GetImageRGBA(nAvatar, pData, static_cast(nSize))) + { + const int nTextureID = I::MatSystemSurface->CreateNewTextureID(true); + if (I::MatSystemSurface->IsTextureIDValid(nTextureID)) + { + I::MatSystemSurface->DrawSetTextureRGBA(nTextureID, pData, newW, newH, 0, false); + m_Avatars[nID] = nTextureID; + } + } + + std::free(pData); + } + } + } +} +void CDraw::ClearAvatarCache() +{ + for (int iID : m_Avatars | std::views::values) + { + I::MatSystemSurface->DeleteTextureByID(iID); + I::MatSystemSurface->DestroyTextureID(iID); + } + + m_Avatars.clear(); +} + +void CDraw::StartClipping(int x, int y, int w, int h) +{ + I::MatSystemSurface->DisableClipping(false); + I::MatSystemSurface->SetClippingRect(x, y, x + w, y + h); +} + +void CDraw::EndClipping() +{ + I::MatSystemSurface->DisableClipping(true); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Draw/Draw.h b/Amalgam/src/SDK/Helpers/Draw/Draw.h new file mode 100644 index 0000000..2f54b71 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Draw/Draw.h @@ -0,0 +1,61 @@ +#pragma once +#include "../Fonts/Fonts.h" +#include "../../Definitions/Definitions.h" + +enum EAlign +{ + ALIGN_TOPLEFT, + ALIGN_TOP, + ALIGN_TOPRIGHT, + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT, + ALIGN_BOTTOMLEFT, + ALIGN_BOTTOM, + ALIGN_BOTTOMRIGHT +}; + +class CDraw +{ + std::unordered_map m_Avatars = {}; + +public: + void UpdateScreenSize(); + void UpdateW2SMatrix(); + + void String(const Font_t& font, int x, int y, const Color_t& clr, const EAlign& align, const char* str, ...); + void String(const Font_t& font, int x, int y, const Color_t& clr, const EAlign& align, const wchar_t* str, ...); + + void Line(int x, int y, int x1, int y1, const Color_t& clr); + void Polygon(int count, Vertex_t* vertices, const Color_t& clr); + + void DrawFillTriangle(const std::array& points, const Color_t& clr); + void DrawLineTriangle(const std::array& points, const Color_t& clr); + + void FillRect(int x, int y, int w, int h, const Color_t& clr); + void LineRect(int x, int y, int w, int h, const Color_t& clr); + void GradientRect(int x, int y, int w, int h, const Color_t& top_clr, const Color_t& bottom_clr, bool horizontal); + void FillRectOutline(int x, int y, int w, int h, const Color_t& clr, const Color_t& out = { 0, 0, 0, 255 }); + void LineRectOutline(int x, int y, int w, int h, const Color_t& clr, const Color_t& out = { 0, 0, 0, 255 }, bool inside = true); + void FillRectPercent(int x, int y, int w, int h, float t, const Color_t& clr, const Color_t& out = { 0, 0, 0, 255 }, const EAlign& align = ALIGN_LEFT, bool adjust = false); + void RoundRect(int x, int y, int w, int h, int radius, const Color_t& clr); + + void FillCircle(int x, int y, float radius, int segments, Color_t clr); + void LineCircle(int x, int y, float radius, int segments, const Color_t& clr); + + void Texture(int x, int y, int w, int h, int id, const EAlign& align = ALIGN_CENTER); + CHudTexture* GetIcon(const char* szIcon, int eIconFormat = 0); + int CreateTextureFromArray(const unsigned char* rgba, int w, int h); + void DrawHudTexture(float x, float y, float s, const CHudTexture* texture, Color_t clr = { 255, 255, 255, 255 }); + void DrawHudTextureByName(float x, float y, float s, const char* textureName, Color_t clr = { 255, 255, 255, 255 }); + void Avatar(int x, int y, int w, int h, const uint32 nFriendID, const EAlign& align = ALIGN_CENTER); + void ClearAvatarCache(); + + void StartClipping(int x, int y, int w, int h); + void EndClipping(); + + int m_nScreenW = 0, m_nScreenH = 0; + VMatrix m_WorldToProjection = {}; +}; + +ADD_FEATURE_CUSTOM(CDraw, Draw, H); \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Draw/Icons.h b/Amalgam/src/SDK/Helpers/Draw/Icons.h new file mode 100644 index 0000000..f29a530 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Draw/Icons.h @@ -0,0 +1,47 @@ +#pragma once +#include + +namespace ICONS +{ + inline std::vector> TEXTURES = { + { -1, "hud/leaderboard_class_scout.vtf" }, + { -1, "hud/leaderboard_class_sniper.vtf" }, + { -1, "hud/leaderboard_class_soldier.vtf" }, + { -1, "hud/leaderboard_class_demo.vtf" }, + { -1, "hud/leaderboard_class_medic.vtf" }, + { -1, "hud/leaderboard_class_heavy.vtf" }, + { -1, "hud/leaderboard_class_pyro.vtf" }, + { -1, "hud/leaderboard_class_spy.vtf" }, + { -1, "hud/leaderboard_class_engineer.vtf" }, + { -1, "vgui/class_portraits/scout_alpha.vtf" }, + { -1, "vgui/class_portraits/sniper_alpha.vtf" }, + { -1, "vgui/class_portraits/soldier_alpha.vtf" }, + { -1, "vgui/class_portraits/demoman_alpha.vtf" }, + { -1, "vgui/class_portraits/medic_alpha.vtf" }, + { -1, "vgui/class_portraits/heavy_alpha.vtf" }, + { -1, "vgui/class_portraits/pyro_alpha.vtf" }, + { -1, "vgui/class_portraits/spy_alpha.vtf" }, + { -1, "vgui/class_portraits/engineer_alpha.vtf" }, + { -1, "vgui/class_portraits/scout_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/sniper_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/soldier_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/demoman_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/medic_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/heavy_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/pyro_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/spy_blue_alpha.vtf" }, + { -1, "vgui/class_portraits/engineer_blue_alpha.vtf" }, + { -1, "hud/hud_obj_status_sentry_1.vtf" }, + { -1, "hud/hud_obj_status_sentry_2.vtf" }, + { -1, "hud/hud_obj_status_sentry_3.vtf" }, + { -1, "hud/hud_obj_status_dispenser.vtf" }, + { -1, "hud/hud_obj_status_tele_entrance.vtf" }, + { -1, "hud/hud_obj_status_tele_exit.vtf" }, + { -1, "sprites/healbeam.vtf" }, + { -1, "hud/hud_obj_status_ammo_64.vtf" }, + { -1, "hud/mvm_cash.vtf" }, + { -1, "hud/ico_demolish.vtf" }, + { -1, "vgui/spellbook_book.vtf" }, + { -1, "backpack/player/items/crafting/hwn2015_gargoyle_stone.vtf" } + }; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Entities/Entities.cpp b/Amalgam/src/SDK/Helpers/Entities/Entities.cpp new file mode 100644 index 0000000..56800b9 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Entities/Entities.cpp @@ -0,0 +1,231 @@ +#include "Entities.h" + +#include "../../SDK.h" +#include "../../../Utils/Hash/FNV1A.h" + +void CEntities::Fill() +{ + auto pLocal = I::ClientEntityList->GetClientEntity(I::EngineClient->GetLocalPlayer()); + if (!pLocal) + return; + + m_pLocal = pLocal->As(); + if (auto pEntity = m_pLocal->m_hActiveWeapon().Get()) + m_pLocalWeapon = pEntity->As(); + + switch (m_pLocal->m_iObserverMode()) + { + case OBS_MODE_FIRSTPERSON: + case OBS_MODE_THIRDPERSON: + { + if (auto pObservedTarget = m_pLocal->m_hObserverTarget().Get()) + m_pObservedTarget = pObservedTarget->As(); + break; + } + default: break; + } + + for (int n = 1; n < I::ClientEntityList->GetHighestEntityIndex(); n++) + { + auto pClientEntity = I::ClientEntityList->GetClientEntity(n); + if (!pClientEntity) + continue; + + auto pEntity = pClientEntity->As(); + + if (pEntity->IsDormant()) + { + if (!pEntity->IsPlayer()) + continue; + + auto pPlayer = pEntity->As(); + + // Is any dormant data available? + if (!G::DormancyMap.count(n)) + continue; + + auto& dormantData = G::DormancyMap[n]; + float lastUpdate = dormantData.LastUpdate; + + if (I::EngineClient->Time() - lastUpdate > Vars::ESP::DormantTime.Value) + continue; + + pPlayer->SetAbsOrigin(dormantData.Location); + pPlayer->m_vecOrigin() = dormantData.Location; + + pPlayer->m_lifeState() = LIFE_ALIVE; + auto playerResource = GetPR(); + if (playerResource && playerResource->GetValid(n)) + pPlayer->m_iHealth() = playerResource->GetHealth(n); + } + + auto nClassID = pEntity->GetClassID(); + switch (nClassID) + { + case ETFClassID::CTFPlayerResource: + m_pPlayerResource = pEntity->As(); + break; + case ETFClassID::CTFPlayer: + { + m_mGroups[EGroupType::PLAYERS_ALL].push_back(pEntity); + m_mGroups[pEntity->m_iTeamNum() != m_pLocal->m_iTeamNum() ? EGroupType::PLAYERS_ENEMIES : EGroupType::PLAYERS_TEAMMATES].push_back(pEntity); + + PlayerInfo_t pi{}; + if (I::EngineClient->GetPlayerInfo(n, &pi) && !pi.fakeplayer) + { + m_mIDIndex[pi.friendsID] = n; + m_mFriends[n] = I::SteamFriends->HasFriend({ pi.friendsID, 1, k_EUniversePublic, k_EAccountTypeIndividual }, k_EFriendFlagImmediate); + } + break; + } + case ETFClassID::CObjectSentrygun: + case ETFClassID::CObjectDispenser: + case ETFClassID::CObjectTeleporter: + m_mGroups[EGroupType::BUILDINGS_ALL].push_back(pEntity); + m_mGroups[pEntity->m_iTeamNum() != m_pLocal->m_iTeamNum() ? EGroupType::BUILDINGS_ENEMIES : EGroupType::BUILDINGS_TEAMMATES].push_back(pEntity); + break; + case ETFClassID::CBaseAnimating: + { + if (IsAmmo(pEntity)) + m_mGroups[EGroupType::WORLD_AMMO].push_back(pEntity); + else if (IsHealth(pEntity)) + m_mGroups[EGroupType::WORLD_HEALTH].push_back(pEntity); + else if (IsSpellbook(pEntity)) + m_mGroups[EGroupType::WORLD_SPELLBOOK].push_back(pEntity); + break; + } + case ETFClassID::CTFAmmoPack: + m_mGroups[EGroupType::WORLD_AMMO].push_back(pEntity); + break; + case ETFClassID::CTFProjectile_Rocket: + case ETFClassID::CTFGrenadePipebombProjectile: + case ETFClassID::CTFProjectile_Jar: + case ETFClassID::CTFProjectile_JarGas: + case ETFClassID::CTFProjectile_JarMilk: + case ETFClassID::CTFProjectile_Arrow: + case ETFClassID::CTFProjectile_SentryRocket: + case ETFClassID::CTFProjectile_Flare: + case ETFClassID::CTFProjectile_GrapplingHook: + case ETFClassID::CTFProjectile_Cleaver: + case ETFClassID::CTFProjectile_EnergyBall: + case ETFClassID::CTFProjectile_EnergyRing: + case ETFClassID::CTFProjectile_HealingBolt: + case ETFClassID::CTFProjectile_ThrowableBreadMonster: + case ETFClassID::CTFStunBall: + case ETFClassID::CTFBall_Ornament: + { + m_mGroups[EGroupType::WORLD_PROJECTILES].push_back(pEntity); + + if (nClassID == ETFClassID::CTFGrenadePipebombProjectile) + { + auto pPipebomb = pEntity->As(); + + if (pPipebomb->HasStickyEffects() && pPipebomb->As()->m_hThrower().Get() == pLocal) + m_mGroups[EGroupType::MISC_LOCAL_STICKIES].push_back(pEntity); + } + + if (nClassID == ETFClassID::CTFProjectile_Flare) + { + auto pSecondary = m_pLocal->GetWeaponFromSlot(EWeaponSlot::SLOT_SECONDARY); + if (pSecondary && pSecondary->m_iItemDefinitionIndex() == ETFWeapons::Pyro_s_TheDetonator && pEntity->m_hOwnerEntity().Get() == m_pLocal) + m_mGroups[EGroupType::MISC_LOCAL_FLARES].push_back(pEntity); + + break; + } + + break; + } + case ETFClassID::CHeadlessHatman: + case ETFClassID::CTFTankBoss: + case ETFClassID::CMerasmus: + case ETFClassID::CZombie: + case ETFClassID::CEyeballBoss: + m_mGroups[EGroupType::WORLD_NPC].push_back(pEntity); + break; + case ETFClassID::CTFPumpkinBomb: + case ETFClassID::CTFGenericBomb: + m_mGroups[EGroupType::WORLD_BOMBS].push_back(pEntity); + break; + case ETFClassID::CCurrencyPack: + m_mGroups[EGroupType::WORLD_MONEY].push_back(pEntity); + break; + case ETFClassID::CHalloweenGiftPickup: + if (pEntity->As()->m_hTargetPlayer().Get() == m_pLocal) + m_mGroups[EGroupType::WORLD_GARGOYLE].push_back(pEntity); + break; + case ETFClassID::CSniperDot: + m_mGroups[EGroupType::MISC_DOTS].push_back(pEntity); + break; + } + } +} + +void CEntities::Clear() +{ + m_pLocal = nullptr; + m_pLocalWeapon = nullptr; + m_pObservedTarget = nullptr; + m_pPlayerResource = nullptr; + m_mGroups.clear(); + m_mIDIndex.clear(); + m_mFriends.clear(); +} + +bool CEntities::IsHealth(CBaseEntity* pEntity) +{ + switch (FNV1A::Hash(I::ModelInfoClient->GetModelName(pEntity->GetModel()))) + { + case FNV1A::HashConst("models/items/banana/plate_banana.mdl"): + case FNV1A::HashConst("models/items/medkit_small.mdl"): + case FNV1A::HashConst("models/items/medkit_medium.mdl"): + case FNV1A::HashConst("models/items/medkit_large.mdl"): + case FNV1A::HashConst("models/items/medkit_small_bday.mdl"): + case FNV1A::HashConst("models/items/medkit_medium_bday.mdl"): + case FNV1A::HashConst("models/items/medkit_large_bday.mdl"): + case FNV1A::HashConst("models/items/plate.mdl"): + case FNV1A::HashConst("models/items/plate_sandwich_xmas.mdl"): + case FNV1A::HashConst("models/items/plate_robo_sandwich.mdl"): + case FNV1A::HashConst("models/props_medieval/medieval_meat.mdl"): + case FNV1A::HashConst("models/workshopweapons/c_models/c_chocolate/plate_chocolate.mdl"): + case FNV1A::HashConst("models/workshopweapons/c_models/c_fishcake/plate_fishcake.mdl"): + case FNV1A::HashConst("models/props_halloween/halloween_medkit_small.mdl"): + case FNV1A::HashConst("models/props_halloween/halloween_medkit_medium.mdl"): + case FNV1A::HashConst("models/props_halloween/halloween_medkit_large.mdl"): + case FNV1A::HashConst("models/items/ld1/mushroom_large.mdl"): + case FNV1A::HashConst("models/items/plate_steak.mdl"): + case FNV1A::HashConst("models/props_brine/foodcan.mdl"): + return true; + } + return false; +} + +bool CEntities::IsAmmo(CBaseEntity* pEntity) +{ + switch (FNV1A::Hash(I::ModelInfoClient->GetModelName(pEntity->GetModel()))) + { + case FNV1A::HashConst("models/items/ammopack_small.mdl"): + case FNV1A::HashConst("models/items/ammopack_medium.mdl"): + case FNV1A::HashConst("models/items/ammopack_large.mdl"): + case FNV1A::HashConst("models/items/ammopack_large_bday.mdl"): + case FNV1A::HashConst("models/items/ammopack_medium_bday.mdl"): + case FNV1A::HashConst("models/items/ammopack_small_bday.mdl"): + return true; + } + return false; +} + +bool CEntities::IsSpellbook(CBaseEntity* pEntity) +{ + switch (FNV1A::Hash(I::ModelInfoClient->GetModelName(pEntity->GetModel()))) + { + case FNV1A::HashConst("models/props_halloween/hwn_spellbook_flying.mdl"): + case FNV1A::HashConst("models/props_halloween/hwn_spellbook_upright.mdl"): + case FNV1A::HashConst("models/props_halloween/hwn_spellbook_upright_major.mdl"): + case FNV1A::HashConst("models/items/crystal_ball_pickup.mdl"): + case FNV1A::HashConst("models/items/crystal_ball_pickup_major.mdl"): + case FNV1A::HashConst("models/props_monster_mash/flask_vial_green.mdl"): + case FNV1A::HashConst("models/props_monster_mash/flask_vial_purple.mdl"): // prop_dynamic in the map, probably won't work + return true; + } + return false; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Entities/Entities.h b/Amalgam/src/SDK/Helpers/Entities/Entities.h new file mode 100644 index 0000000..b7b7f04 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Entities/Entities.h @@ -0,0 +1,43 @@ +#pragma once +#include "../../../Utils/Feature/Feature.h" +#include "../../Definitions/Classes.h" +#include + +enum struct EGroupType +{ + PLAYERS_ALL, PLAYERS_ENEMIES, PLAYERS_TEAMMATES, + BUILDINGS_ALL, BUILDINGS_ENEMIES, BUILDINGS_TEAMMATES, + WORLD_HEALTH, WORLD_AMMO, WORLD_PROJECTILES, WORLD_NPC, WORLD_BOMBS, WORLD_MONEY, WORLD_SPELLBOOK, WORLD_GARGOYLE, + MISC_LOCAL_STICKIES, MISC_LOCAL_FLARES, MISC_DOTS +}; + +class CEntities +{ + CTFPlayer* m_pLocal = nullptr; + CTFWeaponBase* m_pLocalWeapon = nullptr; + CTFPlayerResource* m_pPlayerResource = nullptr; + CTFPlayer* m_pObservedTarget = nullptr; + + std::unordered_map> m_mGroups = {}; + std::unordered_map m_mIDIndex = {}; + std::unordered_map m_mFriends; + +public: + void Fill(); + void Clear(); + + bool IsHealth(CBaseEntity* pEntity); + bool IsAmmo(CBaseEntity* pEntity); + bool IsSpellbook(CBaseEntity* pEntity); + + CTFPlayer* GetLocal() { return m_pLocal; } + CTFWeaponBase* GetWeapon() { return m_pLocalWeapon; } + CTFPlayerResource* GetPR() { return m_pPlayerResource; } + CTFPlayer* GetObservedTarget() { return m_pObservedTarget; } + + const std::vector& GetGroup(const EGroupType& Group) { return m_mGroups[Group]; } + bool IsFriend(int entIdx) { return m_mFriends[entIdx]; } + bool IsFriend(uint32_t friendsID) { return m_mFriends[m_mIDIndex[friendsID]]; } +}; + +ADD_FEATURE_CUSTOM(CEntities, Entities, H); \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Fonts/Fonts.cpp b/Amalgam/src/SDK/Helpers/Fonts/Fonts.cpp new file mode 100644 index 0000000..4246c1b --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Fonts/Fonts.cpp @@ -0,0 +1,26 @@ +#include "Fonts.h" + +void CFonts::Reload(float flDPI) +{ + m_mapFonts[FONT_ESP] = { "Verdana", int(12.f * flDPI), FONTFLAG_OUTLINE, 0 }; + m_mapFonts[FONT_INDICATORS] = { "Verdana", int(13.f * flDPI), FONTFLAG_OUTLINE, 0 }; + + for (auto& [_, fFont] : m_mapFonts) + { + I::MatSystemSurface->SetFontGlyphSet + ( + fFont.m_dwFont = I::MatSystemSurface->CreateFont(), + fFont.m_szName, //name + fFont.m_nTall, //tall + fFont.m_nWeight, //weight + 0, //blur + 0, //scanlines + fFont.m_nFlags //flags + ); + } +} + +const Font_t& CFonts::GetFont(EFonts eFont) +{ + return m_mapFonts[eFont]; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Fonts/Fonts.h b/Amalgam/src/SDK/Helpers/Fonts/Fonts.h new file mode 100644 index 0000000..6206bfa --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Fonts/Fonts.h @@ -0,0 +1,29 @@ +#pragma once +#include "../../../Utils/Feature/Feature.h" +#include "../../Definitions/Interfaces/IMatSystemSurface.h" +#include + +enum EFonts +{ + FONT_ESP, + FONT_INDICATORS +}; + +struct Font_t +{ + const char* m_szName; + int m_nTall, m_nFlags, m_nWeight; + unsigned long m_dwFont; +}; + +class CFonts +{ +private: + std::unordered_map m_mapFonts = {}; + +public: + void Reload(float flDPI = 1.f); + const Font_t& GetFont(EFonts eFont); +}; + +ADD_FEATURE_CUSTOM(CFonts, Fonts, H); \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/Particles/Particles.h b/Amalgam/src/SDK/Helpers/Particles/Particles.h new file mode 100644 index 0000000..2325f36 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/Particles/Particles.h @@ -0,0 +1,111 @@ +#pragma once +#include "../../Definitions/Types.h" +#include "../../Definitions/Main/CBaseEntity.h" + +MAKE_SIGNATURE(CTE_DispatchEffect, "client.dll", "48 89 5C 24 ? 57 48 83 EC ? 48 8B D9 48 8B FA 48 8D 4C 24", 0x0); +MAKE_SIGNATURE(Get_ParticleSystemIndex, "client.dll", "40 53 48 83 EC ? 48 8B D9 48 85 C9 74 ? 48 8B 0D ? ? ? ? 48 8B D3 48 8B 01 FF 50 ? 3D", 0x0); +MAKE_SIGNATURE(UTIL_ParticleTracer, "client.dll", "48 89 5C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 4C 89 74 24 ? 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 49 63 F1", 0x0); + +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, +}; + +struct te_tf_particle_effects_colors_t +{ + Vec3 m_vecColor1; + Vec3 m_vecColor2; +}; + +struct te_tf_particle_effects_control_point_t +{ + ParticleAttachment_t m_eParticleAttachment; + Vec3 m_vecOffset; +}; + +class CEffectData +{ +public: + Vec3 m_vOrigin; + Vec3 m_vStart; + Vec3 m_vNormal; + Vec3 m_vAngles; + int m_fFlags; + int m_nEntIndex; + float m_flScale; + float m_flMagnitude; + float m_flRadius; + int m_nAttachmentIndex; + short m_nSurfaceProp; + int m_nMaterial; + int m_nDamageType; + int m_nHitBox; + unsigned char m_nColor; + bool m_bCustomColors; + te_tf_particle_effects_colors_t m_CustomColors; + bool m_bControlPoint1; + te_tf_particle_effects_control_point_t m_ControlPoint1; + int m_iEffectName; +}; + +class CParticles +{ +public: + inline void DispatchEffect(const char* pName, const CEffectData& data) + { + static auto fnDispatchEffect = S::CTE_DispatchEffect.As(); + fnDispatchEffect(pName, data); + } + + inline int GetParticleSystemIndex(const char* pParticleSystemName) + { + static auto fnGetParticleSystemIndex = S::Get_ParticleSystemIndex.As(); + return fnGetParticleSystemIndex(pParticleSystemName); + } + + inline void DispatchParticleEffect(int iEffectIndex, const Vec3& vecOrigin, const Vec3& vecStart, const Vec3& vecAngles, CBaseEntity* pEntity = nullptr) + { + CEffectData data{}; + data.m_nHitBox = iEffectIndex; + data.m_vOrigin = vecOrigin; + data.m_vStart = vecStart; + data.m_vAngles = vecAngles; + + if (pEntity) { + data.m_nEntIndex = pEntity->entindex(); + data.m_fFlags |= (1 << 0); + data.m_nDamageType = 2; + } + else { + data.m_nEntIndex = 0; + } + + data.m_bCustomColors = true; + + DispatchEffect("ParticleEffect", data); + } + + inline void DispatchParticleEffect(const char* pszParticleName, const Vec3& vecOrigin, const Vec3& vecAngles, CBaseEntity* pEntity = nullptr) + { + const int iIndex = GetParticleSystemIndex(pszParticleName); + DispatchParticleEffect(iIndex, vecOrigin, vecOrigin, vecAngles, pEntity); + } + + inline void ParticleTracer(const char* pszTracerEffectName, const Vector& vecStart, const Vector& vecEnd, int iEntIndex, int iAttachment, bool bWhiz) + { + static auto fnParticleTracer = S::UTIL_ParticleTracer.As(); + fnParticleTracer(pszTracerEffectName, vecStart, vecEnd, iEntIndex, iAttachment, bWhiz); + } +}; + +ADD_FEATURE_CUSTOM(CParticles, Particles, H) \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/TraceFilters/TraceFilters.cpp b/Amalgam/src/SDK/Helpers/TraceFilters/TraceFilters.cpp new file mode 100644 index 0000000..d8cee23 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/TraceFilters/TraceFilters.cpp @@ -0,0 +1,108 @@ +#include "TraceFilters.h" +#include "../../SDK.h" + +bool CTraceFilterHitscan::ShouldHitEntity(IHandleEntity* pServerEntity, int nContentsMask) +{ + if (!pServerEntity || pServerEntity == pSkip) + return false; + + auto pEntity = static_cast(pServerEntity)->As(); + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + + const int iTargetTeam = pEntity->m_iTeamNum(), iLocalTeam = pLocal ? pLocal->m_iTeamNum() : iTargetTeam; + bool bSniperRifle = false; + if (pLocal && pLocal == pSkip && pWeapon) + { + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_SNIPERRIFLE: + case TF_WEAPON_SNIPERRIFLE_CLASSIC: + case TF_WEAPON_SNIPERRIFLE_DECAP: + bSniperRifle = true; + } + } + + switch (pEntity->GetClassID()) + { + case ETFClassID::CTFAmmoPack: + case ETFClassID::CFuncAreaPortalWindow: + case ETFClassID::CFuncRespawnRoomVisualizer: + case ETFClassID::CSniperDot: + case ETFClassID::CTFReviveMarker: return false; + case ETFClassID::CTFMedigunShield: + if (iTargetTeam == iLocalTeam) + return false; + break; + case ETFClassID::CTFPlayer: + case ETFClassID::CObjectSentrygun: + case ETFClassID::CObjectDispenser: + case ETFClassID::CObjectTeleporter: + if (bSniperRifle && iTargetTeam == iLocalTeam) + return false; + } + + return true; +} +TraceType_t CTraceFilterHitscan::GetTraceType() const +{ + return TRACE_EVERYTHING; +} + +bool CTraceFilterProjectile::ShouldHitEntity(IHandleEntity* pServerEntity, int nContentsMask) +{ + if (!pServerEntity || pServerEntity == pSkip) + return false; + + auto pEntity = static_cast(pServerEntity)->As(); + auto pLocal = H::Entities.GetLocal(); + auto pWeapon = H::Entities.GetWeapon(); + + const int iTargetTeam = pEntity->m_iTeamNum(), iLocalTeam = pLocal ? pLocal->m_iTeamNum() : iTargetTeam; + const bool bCrossbow = (pLocal && pLocal == pSkip && pWeapon) ? pWeapon->m_iWeaponID() == TF_WEAPON_CROSSBOW : false; + + switch (pEntity->GetClassID()) + { + case ETFClassID::CBaseEntity: + case ETFClassID::CBaseDoor: + case ETFClassID::CDynamicProp: + case ETFClassID::CPhysicsProp: + case ETFClassID::CObjectCartDispenser: + case ETFClassID::CFuncTrackTrain: + case ETFClassID::CFuncConveyor: + case ETFClassID::CObjectSentrygun: + case ETFClassID::CObjectDispenser: + case ETFClassID::CObjectTeleporter: return true; + case ETFClassID::CTFPlayer: return bCrossbow ? true : iTargetTeam != iLocalTeam; + } + + return false; +} +TraceType_t CTraceFilterProjectile::GetTraceType() const +{ + return TRACE_EVERYTHING; +} + +bool CTraceFilterWorldAndPropsOnly::ShouldHitEntity(IHandleEntity* pServerEntity, int nContentsMask) +{ + if (!pServerEntity || pServerEntity == pSkip) + return false; + + auto pEntity = static_cast(pServerEntity)->As(); + switch (pEntity->GetClassID()) + { + case ETFClassID::CBaseEntity: + case ETFClassID::CBaseDoor: + case ETFClassID::CDynamicProp: + case ETFClassID::CPhysicsProp: + case ETFClassID::CObjectCartDispenser: + case ETFClassID::CFuncTrackTrain: + case ETFClassID::CFuncConveyor: return true; + } + + return false; +} +TraceType_t CTraceFilterWorldAndPropsOnly::GetTraceType() const +{ + return TRACE_EVERYTHING; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Helpers/TraceFilters/TraceFilters.h b/Amalgam/src/SDK/Helpers/TraceFilters/TraceFilters.h new file mode 100644 index 0000000..a8bdd51 --- /dev/null +++ b/Amalgam/src/SDK/Helpers/TraceFilters/TraceFilters.h @@ -0,0 +1,26 @@ +#pragma once +#include "../../Definitions/Interfaces/IEngineTrace.h" + +class CTraceFilterHitscan : public ITraceFilter +{ +public: + bool ShouldHitEntity(IHandleEntity* pServerEntity, int nContentsMask) override; + TraceType_t GetTraceType() const override; + CBaseEntity* pSkip = nullptr; +}; + +class CTraceFilterProjectile : public ITraceFilter +{ +public: + bool ShouldHitEntity(IHandleEntity* pServerEntity, int nContentsMask) override; + TraceType_t GetTraceType() const override; + CBaseEntity* pSkip = nullptr; +}; + +class CTraceFilterWorldAndPropsOnly : public ITraceFilter +{ +public: + bool ShouldHitEntity(IHandleEntity* pServerEntity, int nContentsMask) override; + TraceType_t GetTraceType() const override; + CBaseEntity* pSkip = nullptr; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/SDK.cpp b/Amalgam/src/SDK/SDK.cpp new file mode 100644 index 0000000..8679e2b --- /dev/null +++ b/Amalgam/src/SDK/SDK.cpp @@ -0,0 +1,568 @@ +#include "SDK.h" + +#include + +#pragma warning (disable : 6385) + +BOOL CALLBACK TeamFortressWindow(HWND hwnd, LPARAM lParam) +{ + char windowTitle[1024]; + GetWindowTextA(hwnd, windowTitle, sizeof(windowTitle)); + if (std::string(windowTitle).find("Team Fortress 2 - ") == 0) // support both dx9 & vulkan + *reinterpret_cast(lParam) = hwnd; + + return TRUE; +} + + + + +void SDK::Output(const char* cFunction, const char* cLog, Color_t cColor, bool bConsole, bool bChat, bool bDebug) +{ + if (bConsole) + { + I::CVar->ConsoleColorPrintf(cColor, "[%s] ", cFunction); + I::CVar->ConsoleColorPrintf({ 255, 255, 255, 255 }, "%s\n", cLog); + } + if (bChat) + I::ClientModeShared->m_pChatElement->ChatPrintf(0, std::format("{}[{}]\x1 {}", cColor.ToHex(), cFunction, cLog).c_str()); + if (bDebug) + OutputDebugStringA(std::format("[{}] {}\n", cFunction, cLog).c_str()); +} + +HWND SDK::GetTeamFortressWindow() +{ + HWND hwWindow = nullptr; + EnumWindows(TeamFortressWindow, reinterpret_cast(&hwWindow)); + return hwWindow; +} + +bool SDK::IsGameWindowInFocus() +{ + static HWND hwGame = nullptr; + if (!hwGame) + hwGame = GetTeamFortressWindow(); + + return GetForegroundWindow() == hwGame; +} + +std::wstring SDK::ConvertUtf8ToWide(const std::string& ansi) +{ + const int size = MultiByteToWideChar(CP_UTF8, 0, ansi.c_str(), -1, nullptr, 0); + std::wstring result(size, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, ansi.c_str(), -1, result.data(), size); + return result; +} + +std::string SDK::ConvertWideToUTF8(const std::wstring& unicode) +{ + const int size = WideCharToMultiByte(CP_UTF8, 0, unicode.c_str(), -1, nullptr, 0, nullptr, nullptr); + std::string result(size, '\0'); + WideCharToMultiByte(CP_UTF8, 0, unicode.c_str(), -1, result.data(), size, nullptr, nullptr); + return result; +} + +double SDK::PlatFloatTime() +{ + static auto fnPlatFloatTime = reinterpret_cast(GetProcAddress(GetModuleHandleA("tier0.dll"), "Plat_FloatTime")); + return fnPlatFloatTime(); +} + +int SDK::StdRandomInt(int min, int max) +{ + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> distr(min, max); + return distr(gen); +} + +float SDK::StdRandomFloat(float min, float max) +{ + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution distr(min, max); + return distr(gen); +} + +int SDK::SeedFileLineHash(int seedvalue, const char* sharedname, int additionalSeed) +{ + CRC32_t retval; + + CRC32_Init(&retval); + + CRC32_ProcessBuffer(&retval, &seedvalue, sizeof(int)); + CRC32_ProcessBuffer(&retval, &additionalSeed, sizeof(int)); + CRC32_ProcessBuffer(&retval, sharedname, int(strlen(sharedname))); + + CRC32_Final(&retval); + + return static_cast(retval); +} + +int SDK::SharedRandomInt(unsigned iseed, const char* sharedname, int iMinVal, int iMaxVal, int additionalSeed) +{ + const int seed = SeedFileLineHash(iseed, sharedname, additionalSeed); + I::UniformRandomStream->SetSeed(seed); + return I::UniformRandomStream->RandomInt(iMinVal, iMaxVal); +} + +void SDK::RandomSeed(int iSeed) +{ + static auto fnRandomSeed = reinterpret_cast(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomSeed")); + fnRandomSeed(iSeed); +} + +int SDK::RandomInt(int iMinVal, int iMaxVal) +{ + static auto fnRandomInt = reinterpret_cast(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomInt")); + return fnRandomInt(iMinVal, iMaxVal); +} + +float SDK::RandomFloat(float flMinVal, float flMaxVal) +{ + static auto fnRandomFloat = reinterpret_cast(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomFloat")); + return fnRandomFloat(flMinVal, flMaxVal); +} + +int SDK::HandleToIDX(unsigned int pHandle) +{ + return pHandle & 0xFFF; +} + +bool SDK::W2S(const Vec3& vOrigin, Vec3& m_vScreen) +{ + const auto& worldToScreen = H::Draw.m_WorldToProjection.As3x4(); + + float w = worldToScreen[3][0] * vOrigin[0] + worldToScreen[3][1] * vOrigin[1] + worldToScreen[3][2] * vOrigin[2] + worldToScreen[3][3]; + m_vScreen.z = 0; + + if (w > 0.001f) + { + const float fl1DBw = 1 / w; + m_vScreen.x = (H::Draw.m_nScreenW / 2.f) + (0.5 * ((worldToScreen[0][0] * vOrigin[0] + worldToScreen[0][1] * vOrigin[1] + worldToScreen[0][2] * vOrigin[2] + worldToScreen[0][3]) * fl1DBw) * H::Draw.m_nScreenW + 0.5); + m_vScreen.y = (H::Draw.m_nScreenH / 2.f) - (0.5 * ((worldToScreen[1][0] * vOrigin[0] + worldToScreen[1][1] * vOrigin[1] + worldToScreen[1][2] * vOrigin[2] + worldToScreen[1][3]) * fl1DBw) * H::Draw.m_nScreenH + 0.5); + return true; + } + + return false; +} + +bool SDK::IsOnScreen(CBaseEntity* pEntity, const matrix3x4& transform, float* pLeft, float* pRight, float* pTop, float* pBottom) +{ + Vec3 vMins = pEntity->m_vecMins(), vMaxs = pEntity->m_vecMaxs(); + + float flLeft = 0.f, flRight = 0.f, flTop = 0.f, flBottom = 0.f; + const Vec3 vPoints[] = + { + Vec3(0.f, 0.f, vMins.z), + Vec3(0.f, 0.f, vMaxs.z), + Vec3(vMins.x, vMins.y, vMaxs.z * 0.5f), + Vec3(vMins.x, vMaxs.y, vMaxs.z * 0.5f), + Vec3(vMaxs.x, vMins.y, vMaxs.z * 0.5f), + Vec3(vMaxs.x, vMaxs.y, vMaxs.z * 0.5f) + }; + for (int n = 0; n < 6; n++) + { + Vec3 vPoint; Math::VectorTransform(vPoints[n], transform, vPoint); + + Vec3 vScreenPos; + if (!W2S(vPoint, vScreenPos)) + return false; + + flLeft = n ? std::min(flLeft, vScreenPos.x) : vScreenPos.x; + flRight = n ? std::max(flRight, vScreenPos.x) : vScreenPos.x; + flTop = n ? std::max(flTop, vScreenPos.y) : vScreenPos.y; + flBottom = n ? std::min(flBottom, vScreenPos.y) : vScreenPos.y; + } + + if (pLeft) *pLeft = flLeft; + if (pRight) *pRight = flRight; + if (pTop) *pTop = flTop; + if (pBottom) *pBottom = flBottom; + + return !(flRight < 0 || flLeft > H::Draw.m_nScreenW || flTop < 0 || flBottom > H::Draw.m_nScreenH); +} + +bool SDK::IsOnScreen(CBaseEntity* pEntity) +{ + return IsOnScreen(pEntity, pEntity->RenderableToWorldTransform()); +} + +bool SDK::IsOnScreen(CBaseEntity* pEntity, Vec3 vOrigin) +{ + Vec3 vMins = pEntity->m_vecMins(), vMaxs = pEntity->m_vecMaxs(); + + float flLeft = 0.f, flRight = 0.f, flTop = 0.f, flBottom = 0.f; + const Vec3 vPoints[] = + { + Vec3(0.f, 0.f, vMins.z), + Vec3(0.f, 0.f, vMaxs.z), + Vec3(vMins.x, vMins.y, vMaxs.z * 0.5f), + Vec3(vMins.x, vMaxs.y, vMaxs.z * 0.5f), + Vec3(vMaxs.x, vMins.y, vMaxs.z * 0.5f), + Vec3(vMaxs.x, vMaxs.y, vMaxs.z * 0.5f) + }; + for (int n = 0; n < 6; n++) + { + Vec3 vPoint = vOrigin + vPoints[n]; + + Vec3 vScreenPos; + if (!W2S(vPoint, vScreenPos)) + return false; + + flLeft = n ? std::min(flLeft, vScreenPos.x) : vScreenPos.x; + flRight = n ? std::max(flRight, vScreenPos.x) : vScreenPos.x; + flTop = n ? std::max(flTop, vScreenPos.y) : vScreenPos.y; + flBottom = n ? std::min(flBottom, vScreenPos.y) : vScreenPos.y; + } + + return !(flRight < 0 || flLeft > H::Draw.m_nScreenW || flTop < 0 || flBottom > H::Draw.m_nScreenH); +} + +void SDK::Trace(const Vec3& vecStart, const Vec3& vecEnd, unsigned int nMask, ITraceFilter* pFilter, CGameTrace* pTrace) +{ + Ray_t ray; + ray.Init(vecStart, vecEnd); + I::EngineTrace->TraceRay(ray, nMask, pFilter, pTrace); +} + +void SDK::TraceHull(const Vec3& vecStart, const Vec3& vecEnd, const Vec3& vecHullMin, const Vec3& vecHullMax, unsigned int nMask, ITraceFilter* pFilter, CGameTrace* pTrace) +{ + Ray_t ray; + ray.Init(vecStart, vecEnd, vecHullMin, vecHullMax); + I::EngineTrace->TraceRay(ray, nMask, pFilter, pTrace); +} + +bool SDK::VisPos(CBaseEntity* pSkip, const CBaseEntity* pEntity, const Vec3& from, const Vec3& to, unsigned int nMask) +{ + CGameTrace trace = {}; + CTraceFilterHitscan filter = {}; + filter.pSkip = pSkip; + Trace(from, to, nMask, &filter, &trace); + if (trace.DidHit()) + return trace.m_pEnt && trace.m_pEnt == pEntity; + return true; +} +bool SDK::VisPosProjectile(CBaseEntity* pSkip, const CBaseEntity* pEntity, const Vec3& from, const Vec3& to, unsigned int nMask) +{ + CGameTrace trace = {}; + CTraceFilterProjectile filter = {}; + filter.pSkip = pSkip; + Trace(from, to, nMask, &filter, &trace); + if (trace.DidHit()) + return trace.m_pEnt && trace.m_pEnt == pEntity; + return true; +} +bool SDK::VisPosWorld(CBaseEntity* pSkip, const CBaseEntity* pEntity, const Vec3& from, const Vec3& to, unsigned int nMask) +{ + CGameTrace trace = {}; + CTraceFilterWorldAndPropsOnly filter = {}; + filter.pSkip = pSkip; + Trace(from, to, nMask, &filter, &trace); + if (trace.DidHit()) + return trace.m_pEnt && trace.m_pEnt == pEntity; + return true; +} + +int SDK::GetRoundState() +{ + auto pGameRules = I::TFGameRules->Get(); + if (!pGameRules) return 0; + auto pGameRulesProxy = pGameRules->GetProxy(); + if (!pGameRulesProxy) return 0; + return pGameRulesProxy->m_iRoundState(); +} + +EWeaponType SDK::GetWeaponType(CTFWeaponBase* pWeapon) +{ + if (!pWeapon) + return EWeaponType::UNKNOWN; + + if (pWeapon->m_iSlot() == EWeaponSlot::SLOT_MELEE || pWeapon->m_iWeaponID() == TF_WEAPON_BUILDER) + return EWeaponType::MELEE; + + switch (pWeapon->m_iItemDefinitionIndex()) + { + case Soldier_s_TheBuffBanner: + case Soldier_s_FestiveBuffBanner: + case Soldier_s_TheBattalionsBackup: + case Soldier_s_TheConcheror: + case Scout_s_BonkAtomicPunch: + case Scout_s_CritaCola: + EWeaponType::UNKNOWN; + } + + switch (pWeapon->m_iWeaponID()) + { + case TF_WEAPON_PDA: + case TF_WEAPON_PDA_ENGINEER_BUILD: + case TF_WEAPON_PDA_ENGINEER_DESTROY: + case TF_WEAPON_PDA_SPY: + case TF_WEAPON_PDA_SPY_BUILD: + case TF_WEAPON_INVIS: + case TF_WEAPON_BUFF_ITEM: + case TF_WEAPON_GRAPPLINGHOOK: + case TF_WEAPON_LASER_POINTER: + case TF_WEAPON_ROCKETPACK: + return EWeaponType::UNKNOWN; + case TF_WEAPON_ROCKETLAUNCHER: + case TF_WEAPON_FLAME_BALL: + case TF_WEAPON_GRENADELAUNCHER: + case TF_WEAPON_FLAREGUN: + case TF_WEAPON_COMPOUND_BOW: + case TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT: + case TF_WEAPON_CROSSBOW: + case TF_WEAPON_PARTICLE_CANNON: + case TF_WEAPON_DRG_POMSON: + case TF_WEAPON_FLAREGUN_REVENGE: + case TF_WEAPON_RAYGUN: + case TF_WEAPON_CANNON: + case TF_WEAPON_SYRINGEGUN_MEDIC: + case TF_WEAPON_SHOTGUN_BUILDING_RESCUE: + case TF_WEAPON_FLAMETHROWER: + case TF_WEAPON_CLEAVER: + case TF_WEAPON_PIPEBOMBLAUNCHER: + case TF_WEAPON_JAR: + case TF_WEAPON_JAR_MILK: + case TF_WEAPON_LUNCHBOX: + return EWeaponType::PROJECTILE; + } + + return EWeaponType::HITSCAN; +} + +const char* SDK::GetClassByIndex(const int nClass) +{ + static const char* szClasses[] = { + "unknown", + "scout", + "sniper", + "soldier", + "demoman", + "medic", + "heavy", + "pyro", + "spy", + "engineer" + }; + + return (nClass < 10 && nClass > 0) ? szClasses[nClass] : szClasses[0]; +} + +bool SDK::IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd) +{ + //if (pWeapon->IsInReload()) + // return false; + + if (pWeapon->m_iSlot() == SLOT_MELEE) + { + if (pWeapon->m_iWeaponID() == TF_WEAPON_KNIFE) + return ((pCmd->buttons & IN_ATTACK) && G::CanPrimaryAttack); + + float flTime = TICKS_TO_TIME(pLocal->m_nTickBase() + 1); + return fabsf(pWeapon->m_flSmackTime() - flTime) < TICK_INTERVAL * 2.f; + } + + if (pWeapon->m_iItemDefinitionIndex() == Soldier_m_TheBeggarsBazooka) + { + static bool bLoading = false, bFiring = false; + + if (pWeapon->m_iClip1() == 0) + bLoading = false, + bFiring = false; + else if (!bFiring) + bLoading = true; + + if ((bFiring || bLoading && !(pCmd->buttons & IN_ATTACK)) && G::CanPrimaryAttack) + { + bFiring = true; + bLoading = false; + return true; + } + } + else + { + const int iWeaponID = pWeapon->m_iWeaponID(); + switch (iWeaponID) + { + case TF_WEAPON_COMPOUND_BOW: + case TF_WEAPON_PIPEBOMBLAUNCHER: + case TF_WEAPON_STICKY_BALL_LAUNCHER: + case TF_WEAPON_GRENADE_STICKY_BALL: + return !(pCmd->buttons & IN_ATTACK) && pWeapon->As()->m_flChargeBeginTime() > 0.f; + case TF_WEAPON_CANNON: + return !(pCmd->buttons & IN_ATTACK) && pWeapon->As()->m_flDetonateTime() > 0.f; + case TF_WEAPON_SNIPERRIFLE_CLASSIC: + return !(pCmd->buttons & IN_ATTACK) && pWeapon->As()->m_flChargedDamage() > 0.f; + case TF_WEAPON_JAR: + case TF_WEAPON_JAR_MILK: + case TF_WEAPON_JAR_GAS: + case TF_WEAPON_GRENADE_JAR_GAS: + case TF_WEAPON_CLEAVER: + { + static float flThrowTime = 0.f; + + if (pCmd->buttons & IN_ATTACK && G::CanPrimaryAttack && !flThrowTime) + flThrowTime = I::GlobalVars->curtime + TICK_INTERVAL; + + if (flThrowTime && I::GlobalVars->curtime >= flThrowTime) + { + flThrowTime = 0.f; + return true; + } + break; + } + case TF_WEAPON_GRAPPLINGHOOK: + { + if (G::LastUserCmd->buttons & IN_ATTACK || !(pCmd->buttons & IN_ATTACK)) + return false; + + if (pLocal->InCond(TF_COND_GRAPPLINGHOOK)) + return false; + + Vec3 pos, ang; GetProjectileFireSetup(pLocal, pCmd->viewangles, { 23.5f, -8.f, -3.f }, pos, ang, false); + Vec3 forward; Math::AngleVectors(ang, &forward); + + CGameTrace trace = {}; + CTraceFilterHitscan filter = {}; filter.pSkip = pLocal; + static auto tf_grapplinghook_max_distance = U::ConVars.FindVar("tf_grapplinghook_max_distance"); + const float flGrappleDistance = tf_grapplinghook_max_distance ? tf_grapplinghook_max_distance->GetFloat() : 2000.f; + Trace(pos, pos + forward * flGrappleDistance, MASK_SOLID, &filter, &trace); + return trace.DidHit() && !(trace.surface.flags & 0x0004) /*SURF_SKY*/; + } + case TF_WEAPON_MINIGUN: + { + return (pWeapon->As()->m_iWeaponState() == AC_STATE_FIRING || pWeapon->As()->m_iWeaponState() == AC_STATE_SPINNING) && + pCmd->buttons & IN_ATTACK && G::CanPrimaryAttack; + } + } + + return pCmd->buttons & IN_ATTACK && G::CanPrimaryAttack; + } + + return false; +} + +void SDK::FixMovement(CUserCmd* pCmd, const Vec3& vecTargetAngle) +{ + const Vec3 vecMove(pCmd->forwardmove, pCmd->sidemove, pCmd->upmove); + Vec3 vecMoveAng = Vec3(); + + Math::VectorAngles(vecMove, vecMoveAng); + + const float fSpeed = Math::FastSqrt(vecMove.x * vecMove.x + vecMove.y * vecMove.y); + const float fYaw = DEG2RAD(vecTargetAngle.y - pCmd->viewangles.y + vecMoveAng.y); + + pCmd->forwardmove = (cos(fYaw) * fSpeed); + pCmd->sidemove = (sin(fYaw) * fSpeed); +} + +bool SDK::StopMovement(CTFPlayer* pLocal, CUserCmd* pCmd) +{ + if (pLocal->m_vecVelocity().IsZero()) + { + pCmd->forwardmove = 0.f; + pCmd->sidemove = 0.f; + return false; + } + + if (!G::IsAttacking) + { + const float direction = Math::VelocityToAngles(pLocal->m_vecVelocity()).y; + pCmd->viewangles = { -90, direction, 0 }; + pCmd->sidemove = 0; pCmd->forwardmove = 0; + return true; + } + else + { + Vec3 direction = pLocal->m_vecVelocity().toAngle(); + direction.y = pCmd->viewangles.y - direction.y; + const Vec3 negatedDirection = direction.fromAngle() * -pLocal->m_vecVelocity().Length2D(); + pCmd->forwardmove = negatedDirection.x; + pCmd->sidemove = negatedDirection.y; + return false; + } +} + +Vec3 SDK::ComputeMove(const CUserCmd* pCmd, CTFPlayer* pLocal, Vec3& a, Vec3& b) +{ + const Vec3 diff = (b - a); + if (diff.Length() == 0.f) + return { 0.f, 0.f, 0.f }; + + const float x = diff.x; + const float y = diff.y; + const Vec3 vSilent(x, y, 0); + Vec3 ang; + Math::VectorAngles(vSilent, ang); + const float yaw = DEG2RAD(ang.y - pCmd->viewangles.y); + const float pitch = DEG2RAD(ang.x - pCmd->viewangles.x); + Vec3 move = { cos(yaw) * 450.f, -sin(yaw) * 450.f, -cos(pitch) * 450.f }; + + // Only apply upmove in water + if (!(I::EngineTrace->GetPointContents(pLocal->GetEyePosition()) & CONTENTS_WATER)) + move.z = pCmd->upmove; + return move; +} + +void SDK::WalkTo(CUserCmd* pCmd, CTFPlayer* pLocal, Vec3& a, Vec3& b, float scale) +{ + // Calculate how to get to a vector + const auto result = ComputeMove(pCmd, pLocal, a, b); + + // Push our move to usercmd + pCmd->forwardmove = result.x * scale; + pCmd->sidemove = result.y * scale; + pCmd->upmove = result.z * scale; +} + +void SDK::WalkTo(CUserCmd* pCmd, CTFPlayer* pLocal, Vec3& pDestination) +{ + Vec3 localPos = pLocal->m_vecOrigin(); + WalkTo(pCmd, pLocal, localPos, pDestination, 1.f); +} + +void SDK::GetProjectileFireSetup(CTFPlayer* pPlayer, const Vec3& vAngIn, Vec3 vOffset, Vec3& vPosOut, Vec3& vAngOut, bool bPipes, bool bInterp) +{ + static auto cl_flipviewmodels = U::ConVars.FindVar("cl_flipviewmodels"); + if (cl_flipviewmodels && cl_flipviewmodels->GetBool()) + vOffset.y *= -1.f; + + const Vec3 vShootPos = bInterp ? pPlayer->GetEyePosition() : pPlayer->GetShootPos(); + + Vec3 forward, right, up; + Math::AngleVectors(vAngIn, &forward, &right, &up); + vPosOut = vShootPos + (forward * vOffset.x) + (right * vOffset.y) + (up * vOffset.z); + + if (bPipes) + vAngOut = vAngIn; + else + { + Vec3 vEndPos = vShootPos + (forward * 2000.f); + + CGameTrace trace = {}; + CTraceFilterHitscan filter = {}; + filter.pSkip = pPlayer; + Trace(vShootPos, vEndPos, MASK_SOLID, &filter, &trace); + if (trace.DidHit() && trace.fraction > 0.1f) + vEndPos = trace.endpos; + + Math::VectorAngles(vEndPos - vPosOut, vAngOut); + } +} + +void SDK::GetProjectileFireSetupAirblast(CTFPlayer* pPlayer, const Vec3& vAngIn, Vec3 vPosIn, Vec3& vAngOut, bool bInterp) +{ + const Vec3 vShootPos = bInterp ? pPlayer->GetEyePosition() : pPlayer->GetShootPos(); + + Vec3 forward; + Math::AngleVectors(vAngIn, &forward); + + Vec3 vEndPos = vShootPos + (forward * MAX_TRACE_LENGTH); + CGameTrace trace = {}; + CTraceFilterWorldAndPropsOnly filter = {}; + filter.pSkip = pPlayer; + Trace(vShootPos, vEndPos, MASK_SOLID, &filter, &trace); + + Math::VectorAngles(trace.endpos - vPosIn, vAngOut); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/SDK.h b/Amalgam/src/SDK/SDK.h new file mode 100644 index 0000000..be41a91 --- /dev/null +++ b/Amalgam/src/SDK/SDK.h @@ -0,0 +1,157 @@ +#pragma once + +#include "Vars.h" +#include "Globals.h" +#include "Helpers/Entities/Entities.h" +#include "Helpers/Draw/Draw.h" +#include "Helpers/Color/Color.h" +#include "Helpers/TraceFilters/TraceFilters.h" +#include "Helpers/Particles/Particles.h" +#include "Definitions/Types.h" +#include "Definitions/Interfaces.h" +#include "Definitions/Classes.h" +#include "../Utils/Signatures/Signatures.h" +#include "../Utils/Interfaces/Interfaces.h" +#include "../Utils/Hooks/Hooks.h" +#include "../Utils/Memory/Memory.h" +#include "../Utils/ConVars/ConVars.h" +#include "../Utils/KeyHandler/KeyHandler.h" +#include "../Utils/Hash/FNV1A.h" +#include "../Utils/Timer/Timer.h" +#include "../Utils/Feature/Feature.h" +#include + +#define VK_0 0x30 +#define VK_1 0x31 +#define VK_2 0x32 +#define VK_3 0x33 +#define VK_4 0x34 +#define VK_5 0x35 +#define VK_6 0x36 +#define VK_7 0x37 +#define VK_8 0x38 +#define VK_9 0x39 +#define VK_A 0x41 +#define VK_B 0x42 +#define VK_C 0x43 +#define VK_D 0x44 +#define VK_E 0x45 +#define VK_F 0x46 +#define VK_G 0x47 +#define VK_H 0x48 +#define VK_J 0x49 +#define VK_I 0x4A +#define VK_K 0x4B +#define VK_L 0x4C +#define VK_M 0x4D +#define VK_N 0x4E +#define VK_O 0x4F +#define VK_P 0x50 +#define VK_Q 0x51 +#define VK_R 0x52 +#define VK_S 0x53 +#define VK_T 0x54 +#define VK_U 0x55 +#define VK_V 0x56 +#define VK_W 0x57 +#define VK_X 0x58 +#define VK_Y 0x59 +#define VK_Z 0x5A + +enum DataCenter_t // i'm not sure all of these are actually used for tf2 servers +{ + // North America + DC_ATL = 1 << 0, // Atlanta + DC_ORD = 1 << 1, // Chicago + DC_DFW = 1 << 2, // Texas + DC_LAX = 1 << 3, // Los Angeles + DC_EAT = 1 << 4, // Moses Lake + DC_JFK = 1 << 5, // New York + DC_SEA = 1 << 6, // Seattle + DC_IAD = 1 << 7, // Virginia + + // Europe + DC_AMS = 1 << 8, // Amsterdam + DC_FRA = 1 << 9, // Frankfurt + DC_HEL = 1 << 10, // Helsinki + DC_LHR = 1 << 11, // London + DC_MAD = 1 << 12, // Madrid + DC_PAR = 1 << 13, // Paris + DC_STO = 1 << 14, /*& DC_STO2*/ // Stockholm + DC_VIE = 1 << 15, // Vienna + DC_WAW = 1 << 16, // Warsaw + + // South America + DC_EZE = 1 << 17, // Buenos Aires + DC_LIM = 1 << 18, // Lima + DC_SCL = 1 << 19, // Santiago + DC_GRU = 1 << 20, // Sao Paulo + + // Asia + DC_BOM2 = 1 << 21, // Bombay + DC_MAA = 1 << 22, // Chennai + DC_DXB = 1 << 23, // Dubai + DC_HKG = 1 << 24, // Hong Kong + DC_MAA2 = 1 << 25, // Madras + DC_BOM = 1 << 26, // Mumbai + DC_SEO = 1 << 27, // Seoul + DC_SGP = 1 << 28, // Singapore + DC_TYO = 1 << 29, // Tokyo + + // Australia + DC_SYD = 1 << 30, // Sydney + + // Africa + DC_JNB = 1 << 31, // Johannesburg +}; + +namespace SDK +{ + void Output(const char* cFunction, const char* cLog, Color_t cColor = { 255, 255, 255, 255 }, bool bConsole = true, bool bChat = false, bool bDebug = false); + + HWND GetTeamFortressWindow(); + bool IsGameWindowInFocus(); + + std::wstring ConvertUtf8ToWide(const std::string& ansi); + std::string ConvertWideToUTF8(const std::wstring& unicode); + + double PlatFloatTime(); + int StdRandomInt(int min, int max); + float StdRandomFloat(float min, float max); + + int SeedFileLineHash(int seedvalue, const char* sharedname, int additionalSeed); + int SharedRandomInt(unsigned iseed, const char* sharedname, int iMinVal, int iMaxVal, int additionalSeed); + void RandomSeed(int iSeed); + int RandomInt(int iMinVal = 0, int iMaxVal = 0x7FFF); + float RandomFloat(float flMinVal = 0.f, float flMaxVal = 1.f); + + int HandleToIDX(unsigned int pHandle); + + bool W2S(const Vec3& vOrigin, Vec3& m_vScreen); + bool IsOnScreen(CBaseEntity* pEntity, const matrix3x4& transform, float* pLeft = nullptr, float* pRight = nullptr, float* pTop = nullptr, float* pBottom = nullptr); + bool IsOnScreen(CBaseEntity* pEntity); + bool IsOnScreen(CBaseEntity* pEntity, Vec3 vOrigin); + + void Trace(const Vec3& vecStart, const Vec3& vecEnd, unsigned int nMask, ITraceFilter* pFilter, CGameTrace* pTrace); + void TraceHull(const Vec3& vecStart, const Vec3& vecEnd, const Vec3& vecHullMin, const Vec3& vecHullMax, unsigned int nMask, ITraceFilter* pFilter, CGameTrace* pTrace); + + bool VisPos(CBaseEntity* pSkip, const CBaseEntity* pEntity, const Vec3& from, const Vec3& to, unsigned int nMask = MASK_SHOT | CONTENTS_GRATE); + bool VisPosProjectile(CBaseEntity* pSkip, const CBaseEntity* pEntity, const Vec3& from, const Vec3& to, unsigned int nMask = MASK_SHOT | CONTENTS_GRATE); + bool VisPosWorld(CBaseEntity* pSkip, const CBaseEntity* pEntity, const Vec3& from, const Vec3& to, unsigned int nMask = MASK_SHOT | CONTENTS_GRATE); + + int GetRoundState(); + EWeaponType GetWeaponType(CTFWeaponBase* pWeapon); + const char* GetClassByIndex(const int nClass); + + bool IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd); + + void FixMovement(CUserCmd* pCmd, const Vec3& vecTargetAngle); + bool StopMovement(CTFPlayer* pLocal, CUserCmd* pCmd); + + Vec3 ComputeMove(const CUserCmd* pCmd, CTFPlayer* pLocal, Vec3& a, Vec3& b); + void WalkTo(CUserCmd* pCmd, CTFPlayer* pLocal, Vec3& a, Vec3& b, float scale); + void WalkTo(CUserCmd* pCmd, CTFPlayer* pLocal, Vec3& pDestination); + + void GetProjectileFireSetup(CTFPlayer* pPlayer, const Vec3& vAngIn, Vec3 vOffset, Vec3& vPosOut, Vec3& vAngOut, bool bPipes = false, bool bInterp = false); + void GetProjectileFireSetupAirblast(CTFPlayer* pPlayer, const Vec3& vAngIn, Vec3 vPosIn, Vec3& vAngOut, bool bInterp = false); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Vars.h b/Amalgam/src/SDK/Vars.h new file mode 100644 index 0000000..2ab7385 --- /dev/null +++ b/Amalgam/src/SDK/Vars.h @@ -0,0 +1,747 @@ +#pragma once +#include "../SDK/Definitions/Types.h" +#include +#include +#include + +// forward declartion of ConfigVar +template +class ConfigVar; + +class CVarBase +{ +public: + size_t m_iType; + std::string m_sName; + int m_iFlags; + + // getter for ConfigVar + template + ConfigVar* GetVar() + { + if (typeid(T).hash_code() != m_iType) + return nullptr; + + return reinterpret_cast*>(this); + } +}; + +template +class ConfigVar : public CVarBase +{ +public: + T Default; + T Value; + std::unordered_map Map; + ConfigVar(T value, std::string name, int iFlags = 0); +}; + +inline std::vector g_Vars; + +template +inline ConfigVar::ConfigVar(T value, std::string name, int iFlags) +{ + Default = value; + Value = value; + Map["default"] = value; + m_iType = typeid(T).hash_code(); + m_sName = name; + g_Vars.push_back(this); + m_iFlags = iFlags; +} + +#define NAMESPACE_BEGIN(name) \ + namespace name { \ + inline std::string GetNamespace() { return "Vars::" + std::string(#name) + "::"; } \ + inline std::string GetSubname() { return ""; } \ + +#define SUBNAMESPACE_BEGIN(name) \ + namespace name { \ + inline std::string GetSubname() { return std::string(#name) + "::"; } \ + +#define NAMESPACE_END(name) \ + } +#define SUBNAMESPACE_END(name) \ + } + +#define CVar(name, value, ...) inline ConfigVar name{ value, GetNamespace() + GetSubname() + std::string(#name), __VA_ARGS__ }; + +#define VISUAL (1 << 0) +#define NOSAVE (1 << 1) +#define NOCOND (1 << 2) + +namespace Vars +{ + NAMESPACE_BEGIN(Menu) + CVar(CheatName, std::string("Amalgam"), VISUAL) + CVar(CheatPrefix, std::string("[Amalgam]"), VISUAL) + CVar(MenuPrimaryKey, VK_INSERT, NOCOND) + CVar(MenuSecondaryKey, VK_F3, NOCOND) + + CVar(ShowBinds, false) + CVar(BindsDisplay, DragBox_t(), NOCOND) + CVar(MenuShowsBinds, false, NOCOND) + + CVar(Indicators, 0b0) + //CVar(SpectatorAvatars, false, VISUAL) + + CVar(TicksDisplay, DragBox_t(), NOCOND) + CVar(CritsDisplay, DragBox_t(), NOCOND) + CVar(SpectatorsDisplay, DragBox_t(), NOCOND) + CVar(PingDisplay, DragBox_t(), NOCOND) + CVar(ConditionsDisplay, DragBox_t(), NOCOND) + CVar(SeedPredictionDisplay, DragBox_t(), NOCOND) + + CVar(DPI, 1.f, NOCOND) + + SUBNAMESPACE_BEGIN(Theme) // possibly reduce the amount of theme vars + CVar(Accent, Color_t(255, 101, 101, 255), VISUAL) + CVar(Background, Color_t(23, 23, 23, 250), VISUAL) + CVar(Foreground, Color_t(11, 11, 11, 250), VISUAL) + CVar(Foremost, Color_t(23, 23, 23, 250), VISUAL) + CVar(Inactive, Color_t(150, 150, 150, 255), VISUAL) + CVar(Active, Color_t(255, 255, 255, 255), VISUAL) + SUBNAMESPACE_END(Theme) + NAMESPACE_END(Menu) + + NAMESPACE_BEGIN(Aimbot) + SUBNAMESPACE_BEGIN(General) + CVar(AimType, 0) // 0 - Off, 1 - Normal, 2 - Smooth, 3 - Silent + CVar(TargetSelection, 0) // 0 - FOV, 1 - Distance + CVar(Target, 0b0000001) // { Bombs, NPCs, Stickies, Teleporter, Dispenser, Sentry, Players } + CVar(Ignore, 0b00000000) // { Taunting, Disguised, Unsimulated, Vaccinator, Friends, Dead Ringer, Cloaked, Invulnerable } + CVar(AimFOV, 30.f) + CVar(Smoothing, 25.f) + CVar(MaxTargets, 2) + CVar(IgnoreCloakPercentage, 100) + CVar(TickTolerance, 7) + CVar(AutoShoot, true) + CVar(FOVCircle, true) + CVar(NoSpread, false) + SUBNAMESPACE_END(Global) + + SUBNAMESPACE_BEGIN(Hitscan) + CVar(Hitboxes, 0b00111) // { Legs, Arms, Body, Pelvis, Head } + CVar(Modifiers, 0) // { Extinguish team, Bodyaim if lethal, Auto scope, Scoped only, Wait for charge, Wait for heatshot, Tapfire } + CVar(PointScale, 0.f) + CVar(TapFireDist, 1000.f) + SUBNAMESPACE_END(HITSCAN) + + SUBNAMESPACE_BEGIN(Projectile) + CVar(StrafePrediction, 0b11) // { Ground, Air } + CVar(SplashPrediction, 0) // 0 - Off, 1 - Obstructed, 2 - Prefer, 3 - Only + CVar(AutoDetonate, 0b00) // { Flares, Stickies } + CVar(AutoAirblast, 0) // 0 - Off, 1 - Legit, 2 - Rage + CVar(Modifiers, 0b010) // { Bodyaim if lethal, Cancel charge, Charge weapon } + CVar(PredictionTime, 2.f) + CVar(Hitchance, 0.f) + CVar(AutodetRadius, 90.f) + CVar(SplashRadius, 90.f) + CVar(AutoRelease, 0.f) + + CVar(iGroundSamples, 5, NOSAVE) // debug + CVar(iAirSamples, 5, NOSAVE) // debug + CVar(VerticalShift, 5.f, NOSAVE) // debug + CVar(LatOff, 0.f, NOSAVE) // debug + CVar(HullInc, 0.f, NOSAVE) // debug + CVar(DragOverride, 0.f, NOSAVE) // debug + CVar(TimeOverride, 0.f, NOSAVE) // debug + CVar(HuntermanLerp, 50.f, NOSAVE) // debug + CVar(SplashPoints, 80, NOSAVE) // debug + CVar(SplashCount, 5, NOSAVE) // debug + SUBNAMESPACE_END(Projectile) + + SUBNAMESPACE_BEGIN(Melee) + CVar(AutoBackstab, true) + CVar(IgnoreRazorback, true) + CVar(SwingPrediction, false) + CVar(WhipTeam, false) + + CVar(SwingTicks, 13, NOSAVE) // debug + SUBNAMESPACE_END(Melee) + NAMESPACE_END(AIMBOT) + + NAMESPACE_BEGIN(CritHack) + CVar(ForceCrits, false) + CVar(AvoidRandom, false) + CVar(AlwaysMelee, false) + NAMESPACE_END(CritHack) + + NAMESPACE_BEGIN(Backtrack) + CVar(Enabled, false) + CVar(PreferOnShot, false) + CVar(Latency, 0) + CVar(Interp, 0) + CVar(Window, 185) + + CVar(Offset, 0, NOSAVE) // debug + NAMESPACE_END(Backtrack) + + NAMESPACE_BEGIN(CL_Move) + SUBNAMESPACE_BEGIN(Doubletap) + CVar(Doubletap, false) + CVar(Warp, false) + CVar(RechargeTicks, false) + CVar(AntiWarp, true) + CVar(TickLimit, 22) + CVar(WarpRate, 22) + CVar(PassiveRecharge, 0) + SUBNAMESPACE_END(DoubleTap) + + SUBNAMESPACE_BEGIN(Fakelag) + CVar(Fakelag, 0) // 0 - Off, 1 - Plain, 2 - Random, 3 - Adaptive + CVar(PlainTicks, 12) + CVar(RandomTicks, IntRange_t(14, 18)); + CVar(Options, 0b000) // { While Airborne, While Unducking, While Moving } + CVar(UnchokeOnAttack, true) + CVar(RetainBlastJump, false) + SUBNAMESPACE_END(FakeLag) + + CVar(AutoPeek, false) + + CVar(SpeedEnabled, false) + CVar(SpeedFactor, 1) + NAMESPACE_END(CL_Move) + + NAMESPACE_BEGIN(AntiHack) + SUBNAMESPACE_BEGIN(AntiAim) + CVar(Enabled, false) + CVar(PitchReal, 0) // 0 - None, 1 - Up, 2 - Down, 3 - Zero + CVar(PitchFake, 0) // 0 - None, 1 - Up, 2 - Down + CVar(YawReal, 0) // 0 - Forward, 1 - Left, 2 - Right, 3 - Backwards, 4 - Spin, 5 - Edge + CVar(YawFake, 0) // 0 - Forward, 1 - Left, 2 - Right, 3 - Backwards, 4 - Spin, 5 - Edge + CVar(RealYawMode, 0) // 0 - View, 1 - Target + CVar(FakeYawMode, 0) // 0 - View, 1 - Target + CVar(RealYawOffset, 0) + CVar(FakeYawOffset, 0) + CVar(SpinSpeed, 15.f) + CVar(MinWalk, true) + CVar(AntiOverlap, false) + CVar(InvalidShootPitch, false) + SUBNAMESPACE_END(AntiAim) + + SUBNAMESPACE_BEGIN(Resolver) + CVar(Resolver, false) + CVar(AutoResolveCheaters, false) + CVar(IgnoreAirborne, false) + SUBNAMESPACE_END(Resolver) + NAMESPACE_END(AntiHack) + + NAMESPACE_BEGIN(CheaterDetection) + CVar(Methods, 0b00001) // { Duck Speed, Aim flicking, Packet choking, Invalid pitch } + CVar(DetectionsRequired, 10) + CVar(MinimumChoking, 20) + CVar(MinimumFlick, 20.f) // min flick size to suspect + CVar(MaximumNoise, 5.f) // max different between angles before and after flick + NAMESPACE_END(CheaterDetection) + + NAMESPACE_BEGIN(ESP) + CVar(Draw, 0, VISUAL) + CVar(Player, 0, VISUAL) + CVar(Building, 0, VISUAL) + + CVar(ActiveAlpha, 255, VISUAL) + CVar(DormantAlpha, 50, VISUAL) + CVar(DormantPriority, false, VISUAL) + CVar(DormantTime, 1.f, VISUAL) + NAMESPACE_END(ESP) + + NAMESPACE_BEGIN(Chams) + SUBNAMESPACE_BEGIN(Friendly) + CVar(Players, false, VISUAL) + CVar(Buildings, false, VISUAL) + CVar(Ragdolls, false, VISUAL) + CVar(Projectiles, false, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, VISUAL) + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), VISUAL) + SUBNAMESPACE_END(Friendly) + + SUBNAMESPACE_BEGIN(Enemy) + CVar(Players, false, VISUAL) + CVar(Buildings, false, VISUAL) + CVar(Ragdolls, false, VISUAL) + CVar(Projectiles, false, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, VISUAL) + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), VISUAL) + SUBNAMESPACE_END(Enemy) + + SUBNAMESPACE_BEGIN(Player) + CVar(Local, false, VISUAL) + CVar(Friend, false, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, VISUAL) + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), VISUAL) + SUBNAMESPACE_END(Player) + + SUBNAMESPACE_BEGIN(World) + CVar(NPCs, false, VISUAL) + CVar(Pickups, false, VISUAL) + CVar(Bombs, false, VISUAL) + CVar(Halloween, false, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, VISUAL) + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), VISUAL) + SUBNAMESPACE_END(World) + + SUBNAMESPACE_BEGIN(Backtrack) + CVar(Enabled, false, VISUAL) + CVar(Draw, 0, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, NOSAVE) // unused + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), NOSAVE) // unused + SUBNAMESPACE_END(Backtrack) + + SUBNAMESPACE_BEGIN(FakeAngle) + CVar(Enabled, false, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, NOSAVE) // unused + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), NOSAVE) // unused + SUBNAMESPACE_END(FakeAngle) + + SUBNAMESPACE_BEGIN(Viewmodel) + CVar(Weapon, false, VISUAL) + CVar(Hands, false, VISUAL) + + CVar(VisibleMaterial, std::vector { "Original" }, VISUAL) + CVar(OccludedMaterial, std::vector {}, NOSAVE) // unused + CVar(VisibleColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(OccludedColor, Color_t(255, 255, 255, 255), NOSAVE) // unused + SUBNAMESPACE_END(Viewmodel) + NAMESPACE_END(Chams) + + NAMESPACE_BEGIN(Glow) + SUBNAMESPACE_BEGIN(Friendly) + CVar(Players, false, VISUAL) + CVar(Buildings, false, VISUAL) + CVar(Ragdolls, false, VISUAL) + CVar(Projectiles, false, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(Friendly) + + SUBNAMESPACE_BEGIN(Enemy) + CVar(Players, false, VISUAL) + CVar(Buildings, false, VISUAL) + CVar(Ragdolls, false, VISUAL) + CVar(Projectiles, false, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(Enemy) + + SUBNAMESPACE_BEGIN(Player) + CVar(Local, false, VISUAL) + CVar(Friend, false, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(Player) + + SUBNAMESPACE_BEGIN(World) + CVar(NPCs, false, VISUAL) + CVar(Pickups, false, VISUAL) + CVar(Bombs, false, VISUAL) + CVar(Halloween, false, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(World) + + SUBNAMESPACE_BEGIN(Backtrack) + CVar(Enabled, false, VISUAL) + CVar(Draw, 0, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(Backtrack) + + SUBNAMESPACE_BEGIN(FakeAngle) + CVar(Enabled, false, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(FakeAngle) + + SUBNAMESPACE_BEGIN(Viewmodel) + CVar(Weapon, false, VISUAL) + CVar(Hands, false, VISUAL) + + CVar(Stencil, false, VISUAL) + CVar(Blur, false, VISUAL) + CVar(StencilScale, 1, VISUAL) + CVar(BlurScale, 1, VISUAL) + SUBNAMESPACE_END(Viewmodel) + NAMESPACE_END(GLOW) + + NAMESPACE_BEGIN(Visuals) + SUBNAMESPACE_BEGIN(Removals) + CVar(Scope, false, VISUAL) + CVar(Interpolation, false) + CVar(Disguises, false, VISUAL) + CVar(ScreenOverlays, false, VISUAL) + CVar(Taunts, false, VISUAL) + CVar(ScreenEffects, false, VISUAL) + CVar(ViewPunch, false, VISUAL) + CVar(AngleForcing, false, VISUAL) + CVar(MOTD, false, VISUAL) + CVar(ConvarQueries, false, VISUAL) + CVar(PostProcessing, false, VISUAL) + CVar(DSP, false, VISUAL) + SUBNAMESPACE_END(Removals) + + SUBNAMESPACE_BEGIN(UI) + CVar(FieldOfView, 0, VISUAL) + CVar(ZoomFieldOfView, 0, VISUAL) + CVar(RevealScoreboard, false, VISUAL) + CVar(ScoreboardPlayerlist, false) + CVar(CleanScreenshots, true) + CVar(ScoreboardColors, false, VISUAL) + CVar(SniperSightlines, false, VISUAL) + CVar(PickupTimers, false, VISUAL) + SUBNAMESPACE_END(Viewmodel) + + SUBNAMESPACE_BEGIN(Viewmodel) + CVar(CrosshairAim, false, VISUAL) + CVar(ViewmodelAim, false, VISUAL) + CVar(OffsetX, 0, VISUAL) + CVar(OffsetY, 0, VISUAL) + CVar(OffsetZ, 0, VISUAL) + CVar(Roll, 0, VISUAL) + CVar(Sway, false, VISUAL) + CVar(SwayScale, 5.f, VISUAL) + CVar(SwayInterp, 0.05f, VISUAL) + SUBNAMESPACE_END(Viewmodel) + + SUBNAMESPACE_BEGIN(Tracers) + CVar(ParticleTracer, std::string("Off"), VISUAL) + CVar(ParticleTracerCrits, std::string("Off"), VISUAL) + SUBNAMESPACE_END(Tracers) + + SUBNAMESPACE_BEGIN(Beams) // as of now, these will stay out of the menu + CVar(Active, false, VISUAL) + CVar(BeamColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(Model, std::string("sprites/physbeam.vmt"), VISUAL) + CVar(Life, 2.f, VISUAL) + CVar(Width, 2.f, VISUAL) + CVar(EndWidth, 2.f, VISUAL) + CVar(FadeLength, 10.f, VISUAL) + CVar(Amplitude, 2.f, VISUAL) + CVar(Brightness, 255.f, VISUAL) + CVar(Speed, 0.2f, VISUAL) + CVar(Flags, 0b10000000100000000, VISUAL) // { Reverse, Halobeam, Forever, Is active, End visible, Start visible, Use hitboxes, No tile, Only noise once, Shade out, Shade in, Solid, Sine noise, Fade out, Fade in, End entity, Start entity } + CVar(Segments, 2, VISUAL) + SUBNAMESPACE_END(Beans) + + SUBNAMESPACE_BEGIN(Ragdolls) + CVar(NoRagdolls, false, VISUAL) + CVar(NoGib, false, VISUAL) + CVar(Enabled, false, VISUAL) + CVar(EnemyOnly, false, VISUAL) + CVar(Effects, 0, VISUAL) + CVar(Type, 0, VISUAL) + CVar(Force, 1.f, VISUAL) + CVar(ForceHorizontal, 1.f, VISUAL) + CVar(ForceVertical, 1.f, VISUAL) + SUBNAMESPACE_END(RagdollEffects) + + SUBNAMESPACE_BEGIN(Bullet) + CVar(BulletTracer, false, VISUAL) + SUBNAMESPACE_END(Bullet) + + SUBNAMESPACE_BEGIN(Simulation) + CVar(Enabled, false, VISUAL) + CVar(Timed, false, VISUAL) + CVar(Separators, false, VISUAL) + CVar(SeparatorLength, 12, VISUAL) + CVar(SeparatorSpacing, 6, VISUAL) + CVar(ProjectileTrajectory, false, VISUAL) + CVar(ProjectileCamera, false, VISUAL) + CVar(ProjectileWindow, WindowBox_t(), NOCOND) + CVar(TrajectoryOnShot, false, VISUAL) + CVar(SwingLines, false, VISUAL) + SUBNAMESPACE_END(ProjectileTrajectory) + + SUBNAMESPACE_BEGIN(Trajectory) + CVar(Overwrite, false, NOSAVE) // debug + CVar(OffX, 16.f, NOSAVE) // debug + CVar(OffY, 8.f, NOSAVE) // debug + CVar(OffZ, -6.f, NOSAVE) // debug + CVar(Pipes, true, NOSAVE) // debug + CVar(Hull, 5.f, NOSAVE) // debug + CVar(Speed, 1200.f, NOSAVE) // debug + CVar(Gravity, 1.f, NOSAVE) // debug + CVar(NoSpin, false, NOSAVE) // debug + CVar(LifeTime, 2.2f, NOSAVE) // debug + CVar(UpVelocity, 200.f, NOSAVE) // debug + CVar(AngVelocityX, 600.f, NOSAVE) // debug + CVar(AngVelocityY, -1200.f, NOSAVE) // debug + CVar(AngVelocityZ, 0.f, NOSAVE) // debug + CVar(Drag, 1.f, NOSAVE) // debug + CVar(DragBasisX, 0.003902f, NOSAVE) // debug + CVar(DragBasisY, 0.009962f, NOSAVE) // debug + CVar(DragBasisZ, 0.009962f, NOSAVE) // debug + CVar(AngDragBasisX, 0.003618f, NOSAVE) // debug + CVar(AngDragBasisY, 0.001514f, NOSAVE) // debug + CVar(AngDragBasisZ, 0.001514f, NOSAVE) // debug + CVar(MaxVelocity, 2000.f, NOSAVE) // debug + CVar(MaxAngularVelocity, 3600.f, NOSAVE) // debug + SUBNAMESPACE_END(ProjectileTrajectory) + + SUBNAMESPACE_BEGIN(Hitbox) + CVar(ShowHitboxes, false, VISUAL) + SUBNAMESPACE_END(Hitbox) + + SUBNAMESPACE_BEGIN(ThirdPerson) + CVar(Enabled, false, VISUAL) + CVar(Distance, 200.f, VISUAL) + CVar(Right, 0.f, VISUAL) + CVar(Up, 0.f, VISUAL) + CVar(Crosshair, false, VISUAL) + SUBNAMESPACE_END(ThirdPerson) + + SUBNAMESPACE_BEGIN(FOVArrows) + CVar(Enabled, false, VISUAL) + CVar(Offset, 25, VISUAL) + CVar(MaxDist, 1000.f, VISUAL) + SUBNAMESPACE_END(Arrows) + + SUBNAMESPACE_BEGIN(World) + CVar(Modulations, 0b00000, VISUAL) // { Fog, Particle, Prop, Sky, World } + CVar(SkyboxChanger, std::string("Off"), VISUAL) + CVar(WorldTexture, std::string("Default"), VISUAL) + CVar(NearPropFade, false, VISUAL) + CVar(NoPropFade, false, VISUAL) + SUBNAMESPACE_END(World) + NAMESPACE_END(Visuals) + + NAMESPACE_BEGIN(Radar) + SUBNAMESPACE_BEGIN(Main) + CVar(Enabled, false, VISUAL) + CVar(AlwaysDraw, true, VISUAL) + CVar(Style, 0, VISUAL) // 0 - Circle, 1 - Rectangle + CVar(Window, WindowBox_t(), NOCOND) + CVar(Range, 1500, VISUAL) + CVar(BackAlpha, 128, VISUAL) + CVar(LineAlpha, 255, VISUAL) + SUBNAMESPACE_END(Main) + + SUBNAMESPACE_BEGIN(Players) + CVar(Enabled, false, VISUAL) + CVar(Background, true, VISUAL) + CVar(IconType, 1, VISUAL) // 0 - Icons, 1 - Portraits, 2 - Avatars + CVar(Draw, 0b11010, VISUAL) // { Cloaked, Friends, Team, Enemy, Local } + CVar(IconSize, 24, VISUAL) + CVar(Health, false, VISUAL) + CVar(Height, false, VISUAL) + SUBNAMESPACE_END(Players) + + SUBNAMESPACE_BEGIN(Buildings) + CVar(Enabled, false, VISUAL) + CVar(Background, true, VISUAL) + CVar(Draw, 0b1011, VISUAL) // { Friends, Team, Enemy, Local } + CVar(Health, false, VISUAL) + CVar(IconSize, 18, VISUAL) + SUBNAMESPACE_END(Buildings) + + SUBNAMESPACE_BEGIN(World) + CVar(Enabled, false, VISUAL) + CVar(Background, true, VISUAL) + CVar(Draw, 0b00011, VISUAL) // { Halloween, Bombs, Money, Ammo, Health } + CVar(IconSize, 14, VISUAL) + SUBNAMESPACE_END(World) + NAMESPACE_END(Radar) + + NAMESPACE_BEGIN(Misc) + SUBNAMESPACE_BEGIN(Movement) + CVar(AutoStrafe, 0) + CVar(AutoStrafeTurnScale, 0.5f) + CVar(Bunnyhop, false) + CVar(AutoJumpbug, false) + CVar(AutoRocketJump, false) + CVar(AutoCTap, false) + CVar(FastStop, false) + CVar(FastAccel, false) + CVar(FastStrafe, false) + CVar(NoPush, false) + CVar(CrouchSpeed, false) + + CVar(TimingOffset, -1, NOSAVE) // debug + CVar(ApplyAbove, 0, NOSAVE) // debug + SUBNAMESPACE_END(Movement) + + SUBNAMESPACE_BEGIN(Exploits) + CVar(CheatsBypass, false) + CVar(BypassPure, false) + CVar(PingReducer, false) + CVar(PingTarget, 1) + CVar(EquipRegionUnlock, false) + SUBNAMESPACE_END(Exploits) + + SUBNAMESPACE_BEGIN(Automation) + CVar(AntiBackstab, false) + CVar(AntiAFK, false) + CVar(AntiAutobalance, false) + CVar(AcceptItemDrops, false) + CVar(TauntControl, false) + CVar(KartControl, false) + CVar(BackpackExpander, true) + SUBNAMESPACE_END(Automation) + + SUBNAMESPACE_BEGIN(Sound) + CVar(Block, 0) + CVar(GiantWeaponSounds, false) + CVar(HitsoundAlways, false) + SUBNAMESPACE_END(Sound) + + SUBNAMESPACE_BEGIN(Game) + CVar(NetworkFix, false) + CVar(PredictionErrorJitterFix, false) + CVar(SetupBonesOptimization, false) + SUBNAMESPACE_END(Game) + + SUBNAMESPACE_BEGIN(Queueing) + CVar(ForceRegions, 0) + CVar(FreezeQueue, false) + CVar(AutoCasualQueue, false) + SUBNAMESPACE_END(Queueing) + + SUBNAMESPACE_BEGIN(MannVsMachine) + CVar(InstantRespawn, false) + CVar(InstantRevive, false) + SUBNAMESPACE_END(Sound) + + SUBNAMESPACE_BEGIN(Chat) + CVar(Tags, false) + SUBNAMESPACE_END(Chat) + + SUBNAMESPACE_BEGIN(Steam) + CVar(EnableRPC, false) + CVar(MatchGroup, 0) // 0 - Special Event; 1 - MvM Mann Up; 2 - Competitive; 3 - Casual; 4 - MvM Boot Camp; + CVar(OverrideMenu, false) // Override matchgroup when in main menu + CVar(MapText, std::string("Fedoraware")) + CVar(GroupSize, 1337) + SUBNAMESPACE_END(Steam) + NAMESPACE_END(Misc) + + NAMESPACE_BEGIN(Colors) + CVar(FOVCircle, Color_t(255, 255, 255, 100), VISUAL) + CVar(Relative, false, VISUAL) + CVar(TeamRed, Color_t(225, 60, 60, 255), VISUAL) + CVar(TeamBlu, Color_t(75, 175, 225, 255), VISUAL) + CVar(Enemy, Color_t(225, 60, 60, 255), VISUAL) + CVar(Team, Color_t(75, 175, 225, 255), VISUAL) + CVar(Local, Color_t(255, 255, 255, 255), VISUAL) + CVar(Target, Color_t(255, 0, 0, 255), VISUAL) + CVar(Invulnerable, Color_t(125, 100, 175, 255), VISUAL) + CVar(Cloak, Color_t(150, 175, 210, 255), VISUAL) + CVar(Overheal, Color_t(75, 175, 255, 255), VISUAL) + CVar(HealthBar, Gradient_t({ 255, 0, 0, 255 }, { 0, 200, 125, 255 }), VISUAL) + CVar(UberBar, Color_t( 127, 255, 255, 255 ), VISUAL) + CVar(Health, Color_t(0, 225, 75, 255), VISUAL) + CVar(Ammo, Color_t(175, 175, 175, 255), VISUAL) + CVar(NPC, Color_t(255, 255, 255, 255), VISUAL) + CVar(Bomb, Color_t(255, 75, 0, 255), VISUAL) + CVar(Money, Color_t(0, 150, 75, 255), VISUAL) + CVar(Halloween, Color_t(100, 0, 255, 255), VISUAL) + + CVar(WorldModulation, Color_t(255, 255, 255, 255), VISUAL) + CVar(SkyModulation, Color_t(255, 255, 255, 255), VISUAL) + CVar(PropModulation, Color_t(255, 255, 255, 255), VISUAL) + CVar(ParticleModulation, Color_t(255, 255, 255, 255), VISUAL) + CVar(FogModulation, Color_t(255, 255, 255, 255), VISUAL) + + CVar(BulletTracer, Color_t(255, 255, 255, 255), VISUAL) + CVar(PredictionColor, Color_t(255, 255, 255, 255), VISUAL) + CVar(ProjectileColor, Color_t(255, 100, 100, 255), VISUAL) + CVar(ClippedColor, Color_t(255, 255, 255, 0), VISUAL) + CVar(HitboxEdge, Color_t(255, 255, 255, 255), VISUAL) + CVar(HitboxFace, Color_t(255, 255, 255, 0), VISUAL) + NAMESPACE_END(Colors) + + NAMESPACE_BEGIN(Logging) + CVar(Logs, 0b0011) // { Damage, Class Changes, Vote cast, Vote start, Cheat Detection, Tags } + // LogTo // { Console, Party, Chat, Toasts } + CVar(Lifetime, 5.f, VISUAL) + + SUBNAMESPACE_BEGIN(VoteStart) + CVar(LogTo, 0b0001) + SUBNAMESPACE_END(VoteStart) + + SUBNAMESPACE_BEGIN(VoteCast) + CVar(LogTo, 0b0001) + SUBNAMESPACE_END(VoteCast) + + SUBNAMESPACE_BEGIN(ClassChange) + CVar(LogTo, 0b0001) + SUBNAMESPACE_END(ClassChange) + + SUBNAMESPACE_BEGIN(Damage) + CVar(LogTo, 0b0001) + SUBNAMESPACE_END(Damage) + + SUBNAMESPACE_BEGIN(CheatDetection) + CVar(LogTo, 0b0001) + SUBNAMESPACE_END(CheatDetection) + + SUBNAMESPACE_BEGIN(Tags) + CVar(LogTo, 0b0001) + SUBNAMESPACE_END(Tags) + NAMESPACE_END(Logging) + + NAMESPACE_BEGIN(Debug) + CVar(Info, false, NOSAVE) + CVar(Logging, false, NOSAVE) + CVar(ServerHitbox, false, NOSAVE) + CVar(AntiAimLines, false, NOSAVE) + NAMESPACE_END(Debug) + + NAMESPACE_BEGIN(Fonts) + SUBNAMESPACE_BEGIN(FONT_ESP) + CVar(szName, std::string("Tahoma"), VISUAL | NOCOND) + CVar(nTall, 12, VISUAL | NOCOND) + CVar(nWeight, 0, VISUAL | NOCOND) + CVar(nFlags, 512, VISUAL | NOCOND) + SUBNAMESPACE_END(FONT_ESP) + + SUBNAMESPACE_BEGIN(FONT_NAME) + CVar(szName, std::string("Tahoma"), VISUAL | NOCOND) + CVar(nTall, 12, VISUAL | NOCOND) + CVar(nWeight, 0, VISUAL | NOCOND) + CVar(nFlags, 512, VISUAL | NOCOND) + SUBNAMESPACE_END(FONT_NAME) + + SUBNAMESPACE_BEGIN(FONT_INDICATORS) + CVar(szName, std::string("Tahoma"), VISUAL | NOCOND) + CVar(nTall, 13, VISUAL | NOCOND) + CVar(nWeight, -1, VISUAL | NOCOND) + CVar(nFlags, 512, VISUAL | NOCOND) + SUBNAMESPACE_END(FONT_INDICATORS) + NAMESPACE_END(Fonts) +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Assert/Assert.h b/Amalgam/src/Utils/Assert/Assert.h new file mode 100644 index 0000000..ae1443e --- /dev/null +++ b/Amalgam/src/Utils/Assert/Assert.h @@ -0,0 +1,10 @@ +#pragma once + +#define FUNCSIG __FUNCSIG__ +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define LINE_STRING STRINGIZE(__LINE__) + +#define Assert(cond) if (!cond) { MessageBoxA(0, #cond "\n\n" FUNCSIG " Line " LINE_STRING, "Error", MB_OK | MB_ICONERROR); } +#define AssertFatal(cond) if (!cond) { MessageBoxA(0, #cond "\n\n" FUNCSIG " Line " LINE_STRING, "Error", MB_OK | MB_ICONERROR); exit(EXIT_FAILURE); } +#define AssertCustom(cond, message) if (!cond) { MessageBoxA(0, message, "Error", MB_OK | MB_ICONERROR); } \ No newline at end of file diff --git a/Amalgam/src/Utils/ConVars/ConVars.cpp b/Amalgam/src/Utils/ConVars/ConVars.cpp new file mode 100644 index 0000000..c8fc001 --- /dev/null +++ b/Amalgam/src/Utils/ConVars/ConVars.cpp @@ -0,0 +1,30 @@ +#include "ConVars.h" + +#include "../../SDK/Definitions/Interfaces/ICVar.h" + +void CConVars::Initialize() +{ + ConCommandBase* pCmdBase = I::CVar->GetCommands(); + while (pCmdBase != nullptr) + { + mFlagMap[pCmdBase] = pCmdBase->m_nFlags; + pCmdBase->m_nFlags &= ~(FCVAR_HIDDEN | FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT | FCVAR_NOT_CONNECTED); + pCmdBase = pCmdBase->m_pNext; + } +} + +void CConVars::Unload() +{ + for (auto& [pCmdBase, nFlags] : mFlagMap) + { + if (pCmdBase) + pCmdBase->m_nFlags = nFlags; + } +} + +ConVar* CConVars::FindVar(const char* cvarname) +{ + if (!mCVarMap.contains(FNV1A::HashConst(cvarname))) + mCVarMap[FNV1A::HashConst(cvarname)] = I::CVar->FindVar(cvarname); + return mCVarMap[FNV1A::HashConst(cvarname)]; +} \ No newline at end of file diff --git a/Amalgam/src/Utils/ConVars/ConVars.h b/Amalgam/src/Utils/ConVars/ConVars.h new file mode 100644 index 0000000..924b40a --- /dev/null +++ b/Amalgam/src/Utils/ConVars/ConVars.h @@ -0,0 +1,19 @@ +#pragma once +#include "../Feature/Feature.h" +#include "../../SDK/Definitions/Misc/ConVar.h" +#include "../Hash/FNV1A.h" +#include + +class CConVars +{ +private: + std::unordered_map mCVarMap; + std::unordered_map mFlagMap; + +public: + void Initialize(); + void Unload(); + ConVar* FindVar(const char* cvarname); +}; + +ADD_FEATURE_CUSTOM(CConVars, ConVars, U); \ No newline at end of file diff --git a/Amalgam/src/Utils/Feature/Feature.h b/Amalgam/src/Utils/Feature/Feature.h new file mode 100644 index 0000000..5bd39ee --- /dev/null +++ b/Amalgam/src/Utils/Feature/Feature.h @@ -0,0 +1,4 @@ +#pragma once + +#define ADD_FEATURE_CUSTOM(type, name, scope) namespace scope { inline type name; } +#define ADD_FEATURE(type, name) ADD_FEATURE_CUSTOM(type, name, F) \ No newline at end of file diff --git a/Amalgam/src/Utils/Hash/FNV1A.h b/Amalgam/src/Utils/Hash/FNV1A.h new file mode 100644 index 0000000..70df75c --- /dev/null +++ b/Amalgam/src/Utils/Hash/FNV1A.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include + +using FNV1A_t = std::uint32_t; + +namespace FNV1A +{ + inline constexpr std::uint32_t ullBasis = 0x811C9DC5; + inline constexpr std::uint32_t ullPrime = 0x1000193; + + // compile-time hashes + constexpr FNV1A_t HashConst(const char* szString, const FNV1A_t uValue = ullBasis) noexcept + { + return (szString[0] == '\0') ? uValue : HashConst(&szString[1], (uValue ^ FNV1A_t(szString[0])) * ullPrime); + } + + // runtime hashes + inline FNV1A_t Hash(const char* szString) + { + FNV1A_t uHashed = ullBasis; + + for (std::size_t i = 0U; i < strlen(szString); ++i) + { + uHashed ^= szString[i]; + uHashed *= ullPrime; + } + + return uHashed; + } +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Hooks/Hooks.cpp b/Amalgam/src/Utils/Hooks/Hooks.cpp new file mode 100644 index 0000000..e5ce140 --- /dev/null +++ b/Amalgam/src/Utils/Hooks/Hooks.cpp @@ -0,0 +1,27 @@ +#include "Hooks.h" + +#include "../Assert/Assert.h" +#include "../../Hooks/Direct3DDevice9_EndScene.h" + +CHook::CHook(std::string sName, void* pInitFunc) +{ + this->m_pInitFunc = pInitFunc; + U::Hooks.m_mHooks[sName] = this; +} + +void CHooks::Initialize() +{ + MH_Initialize(); + + WndProc::Initialize(); + for (const auto& [_, pHook] : m_mHooks) + reinterpret_cast(pHook->m_pInitFunc)(); + + AssertCustom(MH_EnableHook(MH_ALL_HOOKS) == MH_OK, "MH failed to enable all hooks!"); +} + +void CHooks::Unload() +{ + AssertCustom(MH_Uninitialize() == MH_OK, "MH failed to unload all hooks!"); + WndProc::Unload(); +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Hooks/Hooks.h b/Amalgam/src/Utils/Hooks/Hooks.h new file mode 100644 index 0000000..08c9c85 --- /dev/null +++ b/Amalgam/src/Utils/Hooks/Hooks.h @@ -0,0 +1,52 @@ +#pragma once +#include "../Feature/Feature.h" +#include +#include +#include + +class CHook +{ +public: + void* m_pOriginal = nullptr; + void* m_pInitFunc = nullptr; + +public: + CHook(std::string sName, void* pInitFunc); + + inline void Create(void* pSrc, void* pDst) + { + MH_CreateHook(pSrc, pDst, &m_pOriginal); + } + + template inline fn Original() + { + return reinterpret_cast(m_pOriginal); + } +}; + +#define MAKE_HOOK(name, address, type, callconvo, ...) namespace Hooks \ +{\ + namespace name\ + {\ + void Init(); \ + inline CHook Hook(#name, Init); \ + using FN = type(callconvo *)(__VA_ARGS__); \ + type callconvo Func(__VA_ARGS__); \ + }\ +} \ +void Hooks::name::Init() { Hook.Create(reinterpret_cast(address), Func); } \ +type callconvo Hooks::name::Func(__VA_ARGS__) + +class CHooks +{ +public: + std::unordered_map m_mHooks = {}; + +public: + void Initialize(); + void Unload(); +}; + +ADD_FEATURE_CUSTOM(CHooks, Hooks, U); + +#define CALL_ORIGINAL Hook.Original() \ No newline at end of file diff --git a/Amalgam/src/Utils/Interfaces/Interfaces.cpp b/Amalgam/src/Utils/Interfaces/Interfaces.cpp new file mode 100644 index 0000000..f4295f8 --- /dev/null +++ b/Amalgam/src/Utils/Interfaces/Interfaces.cpp @@ -0,0 +1,109 @@ +#include "Interfaces.h" +#include "../Memory/Memory.h" +#include "../Assert/Assert.h" +#include "../../SDK/Definitions/Interfaces.h" +#include +#include +#include + +#pragma warning (disable: 4172) + +const char* SearchForDLL(const char* pszDLLSearch) +{ + HANDLE hProcessSnap = INVALID_HANDLE_VALUE; + PROCESSENTRY32 pe32; + hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hProcessSnap == INVALID_HANDLE_VALUE) + return pszDLLSearch; + + pe32.dwSize = sizeof(PROCESSENTRY32); + if (!Process32First(hProcessSnap, &pe32)) + { + CloseHandle(hProcessSnap); + return pszDLLSearch; + } + + do + { + if (pe32.szExeFile == strstr(pe32.szExeFile, "tf_win64.exe")) + { + HANDLE hModuleSnap = INVALID_HANDLE_VALUE; + MODULEENTRY32 me32; + hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe32.th32ProcessID); + if (hModuleSnap == INVALID_HANDLE_VALUE) + return pszDLLSearch; + + me32.dwSize = sizeof(MODULEENTRY32); + + if (!Module32First(hModuleSnap, &me32)) + { + CloseHandle(hModuleSnap); + return pszDLLSearch; + } + + do + { + if (strstr(me32.szModule, "shaderapi")) + { + CloseHandle(hModuleSnap); + return me32.szModule; + } + } while (Module32Next(hModuleSnap, &me32)); + + CloseHandle(hModuleSnap); + break; + } + } while (Process32Next(hProcessSnap, &pe32)); + + CloseHandle(hProcessSnap); + return pszDLLSearch; +} + +InterfaceInit_t::InterfaceInit_t(void** pPtr, const char* sDLLName, const char* sVersion, int nOffset, int nDereferenceCount, bool bSearchDLL) +{ + m_pPtr = pPtr; + m_pszDLLName = sDLLName; + m_pszVersion = sVersion; + m_nOffset = nOffset; + m_nDereferenceCount = nDereferenceCount; + m_bSearchDLL = bSearchDLL; + + U::Interfaces.AddInterface(this); +} + +void CInterfaces::Initialize() +{ + for (auto& Interface : m_vecInterfaces) + { + if (!Interface->m_pPtr || !Interface->m_pszDLLName || !Interface->m_pszVersion) + continue; + + if (Interface->m_bSearchDLL) + Interface->m_pszDLLName = SearchForDLL(Interface->m_pszDLLName); + + if (Interface->m_nOffset == -1) + *Interface->m_pPtr = U::Memory.FindInterface(Interface->m_pszDLLName, Interface->m_pszVersion); + else + { + auto dwDest = U::Memory.FindSignature(Interface->m_pszDLLName, Interface->m_pszVersion); + if (!dwDest) + { + AssertCustom(dwDest, std::format("CInterfaces::Initialize() Failed to initialize ({} {})", Interface->m_pszDLLName, Interface->m_pszVersion).c_str()); + continue; + } + + auto dwAddress = U::Memory.RelToAbs(dwDest); + *Interface->m_pPtr = reinterpret_cast(dwAddress + Interface->m_nOffset); + + for (int n = 0; n < Interface->m_nDereferenceCount; n++) + { + if (Interface->m_pPtr) + *Interface->m_pPtr = *reinterpret_cast(*Interface->m_pPtr); + } + } + + AssertCustom(*Interface->m_pPtr, std::format("CInterfaces::Initialize() Failed to initialize ({} {})", Interface->m_pszDLLName, Interface->m_pszVersion).c_str()); + } + + H::Interfaces.Initialize(); // Initialize any null interfaces +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Interfaces/Interfaces.h b/Amalgam/src/Utils/Interfaces/Interfaces.h new file mode 100644 index 0000000..8fb6f61 --- /dev/null +++ b/Amalgam/src/Utils/Interfaces/Interfaces.h @@ -0,0 +1,57 @@ +#pragma once +#include "../../Utils/Feature/Feature.h" +#include + +struct InterfaceInit_t +{ + void** m_pPtr = nullptr; + const char* m_pszDLLName = {}; + const char* m_pszVersion = {}; + int m_nOffset = -1; //if not -1 we're going to sig scan (m_sVersion is the sig) + int m_nDereferenceCount = 0; + bool m_bSearchDLL = false; + + InterfaceInit_t(void** pPtr, const char* sDLLName, const char* sVersion, int nOffset, int nDereferenceCount, bool bSearchDLL = false); +}; + +#define MAKE_INTERFACE_VERSION(type, name, dll, version) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, version, -1, 0); \ +} + +#define MAKE_INTERFACE_SIGNATURE(type, name, dll, signature, offset, deref) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, signature, offset, deref); \ +} + +#define MAKE_INTERFACE_NULL(type, name) namespace I { inline type *name = nullptr; } + +#define MAKE_INTERFACE_VERSION_SEARCH(type, name, dll, version) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, version, -1, 0, true); \ +} + +#define MAKE_INTERFACE_SIGNATURE_SEARCH(type, name, dll, signature, offset, deref) namespace I { inline type *name = nullptr; } \ +namespace MAKE_INTERFACE_SCOPE \ +{\ + inline InterfaceInit_t name##InterfaceInit_t(reinterpret_cast(&I::name), dll, signature, offset, deref, true); \ +} + +class CInterfaces +{ +private: + std::vector m_vecInterfaces = {}; + +public: + void Initialize(); + + inline void AddInterface(InterfaceInit_t* pInterface) + { + m_vecInterfaces.push_back(pInterface); + } +}; + +ADD_FEATURE_CUSTOM(CInterfaces, Interfaces, U); \ No newline at end of file diff --git a/Amalgam/src/Utils/KeyHandler/KeyHandler.cpp b/Amalgam/src/Utils/KeyHandler/KeyHandler.cpp new file mode 100644 index 0000000..e184a8e --- /dev/null +++ b/Amalgam/src/Utils/KeyHandler/KeyHandler.cpp @@ -0,0 +1,75 @@ +#include "KeyHandler.h" + +#include "../../SDK/SDK.h" +#include +#include + +void CKeyHandler::StoreKey(int iKey, KeyStorage* pStorage) +{ + if (!pStorage) + pStorage = &StorageMap[iKey]; + + // down + const bool bDown = iKey && GetAsyncKeyState(iKey) & 0x8000 && SDK::IsGameWindowInFocus(); + + // pressed + const bool bPressed = bDown && !pStorage->bIsDown; + + // double click + const auto iEpoch = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + const bool bDouble = bPressed && iEpoch < pStorage->iPressTime + 250; + + // released + const bool bReleased = !bDown && pStorage->bIsDown; + + pStorage->bIsDown = bDown; + pStorage->bIsPressed = bPressed; + pStorage->bIsDouble = bDouble; + pStorage->bIsReleased = bReleased; + if (bPressed) + pStorage->iPressTime = iEpoch; +} + +bool CKeyHandler::Down(int iKey, const bool bStore, KeyStorage* pStorage) +{ + if (!pStorage) + pStorage = &StorageMap[iKey]; + + if (bStore) + StoreKey(iKey, pStorage); + + return pStorage->bIsDown; +} + +bool CKeyHandler::Pressed(int iKey, const bool bStore, KeyStorage* pStorage) +{ + if (!pStorage) + pStorage = &StorageMap[iKey]; + + if (bStore) + StoreKey(iKey, pStorage); + + return pStorage->bIsPressed; +} + +bool CKeyHandler::Double(int iKey, const bool bStore, KeyStorage* pStorage) +{ + if (!pStorage) + pStorage = &StorageMap[iKey]; + + if (bStore) + StoreKey(iKey, pStorage); + + return pStorage->bIsDouble; +} + +bool CKeyHandler::Released(int iKey, const bool bStore, KeyStorage* pStorage) +{ + if (!pStorage) + pStorage = &StorageMap[iKey]; + + if (bStore) + StoreKey(iKey, pStorage); + + return pStorage->bIsReleased; +} \ No newline at end of file diff --git a/Amalgam/src/Utils/KeyHandler/KeyHandler.h b/Amalgam/src/Utils/KeyHandler/KeyHandler.h new file mode 100644 index 0000000..aad0e79 --- /dev/null +++ b/Amalgam/src/Utils/KeyHandler/KeyHandler.h @@ -0,0 +1,34 @@ +#pragma once +#include "../Feature/Feature.h" +#include + +struct KeyStorage +{ + bool bIsDown = false; + bool bIsPressed = false; + bool bIsDouble = false; + bool bIsReleased = false; + long long iPressTime = 0; +}; + +class CKeyHandler +{ + std::unordered_map StorageMap; + +public: + void StoreKey(int iKey, KeyStorage* pStorage = nullptr); + + // Is the button currently down? + bool Down(int iKey, const bool bStore = true, KeyStorage* pStorage = nullptr); + + // Was the button just pressed? This will only be true once. + bool Pressed(int iKey, const bool bStore = true, KeyStorage* pStorage = nullptr); + + // Was the button double clicked? This will only be true once. + bool Double(int iKey, const bool bStore = true, KeyStorage* pStorage = nullptr); + + // Was the button just released? This will only be true once. + bool Released(int iKey, const bool bStore = true, KeyStorage* pStorage = nullptr); +}; + +ADD_FEATURE_CUSTOM(CKeyHandler, KeyHandler, U); \ No newline at end of file diff --git a/Amalgam/src/Utils/Math/Math.h b/Amalgam/src/Utils/Math/Math.h new file mode 100644 index 0000000..7e27475 --- /dev/null +++ b/Amalgam/src/Utils/Math/Math.h @@ -0,0 +1,451 @@ +#pragma once + +#include "../../SDK/Definitions/Types.h" + +#include +#include +#include +#include + +#undef min +#undef max + +#define PI 3.14159265358979323846 +#define M_RADPI 57.295779513082 +#define DEG2RAD(x) ((float)(x) * (float)((float)(PI) / 180.0f)) +#define RAD2DEG(x) ((float)(x) * (float)(180.0f / (float)(PI))) + +#pragma warning (push) +#pragma warning (disable : 26451) +#pragma warning (disable : 4244) + +#define floatCompare(x, y) (fabsf(x - y) <= FLT_EPSILON * fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y)))) + +namespace Math +{ + inline double FastSqrt(double n) + { + return std::sqrt(n); + } + + inline float NormalizeAngle(float ang) + { + return (!std::isfinite(ang) ? 0.0f : std::remainder(ang, 360.0f)); + } + + inline void SinCos(float radians, float* sine, float* cosine) + { + *sine = std::sin(radians); + *cosine = std::cos(radians); + } + + inline void ClampAngles(Vec3& v) + { + v.x = std::max(-89.0f, std::min(89.0f, NormalizeAngle(v.x))); + v.y = NormalizeAngle(v.y); + v.z = 0.0f; + } + + inline float NormalizeRad(float a) noexcept + { + return std::isfinite(a) ? std::remainder(a, PI * 2) : 0.f; + } + + inline float AngleDiffRad(float a1, float a2) noexcept + { + double delta = NormalizeRad(a1 - a2); + if (a1 > a2) + { + if (delta >= PI) { delta -= PI * 2; } + } + else + { + if (delta <= -PI) { delta += PI * 2; } + } + return static_cast(delta); + } + + inline void VectorAngles(const Vec3& forward, Vec3& angles) + { + float tmp, yaw, pitch; + + if (forward.y == 0 && forward.x == 0) + { + yaw = 0; + + if (forward.z > 0) + pitch = 270; + else + pitch = 90; + } + + else + { + yaw = RAD2DEG(atan2f(forward.y, forward.x)); + + if (yaw < 0) + yaw += 360; + + tmp = forward.Length2D(); + pitch = RAD2DEG(atan2f(-forward.z, tmp)); + + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; + } + + inline void AngleVectors(const Vec3& angles, Vec3* forward) + { + float sp, sy, cp, cy; + + SinCos(DEG2RAD(angles.x), &sp, &cp); + SinCos(DEG2RAD(angles.y), &sy, &cy); + + if (forward) + { + forward->x = cp * cy; + forward->y = cp * sy; + forward->z = -sp; + } + } + + inline void AngleVectors(const Vec3& angles, Vec3* forward, Vec3* right, Vec3* up) + { + float sr, sp, sy, cr, cp, cy; + SinCos(DEG2RAD(angles.x), &sp, &cp); + SinCos(DEG2RAD(angles.y), &sy, &cy); + SinCos(DEG2RAD(angles.z), &sr, &cr); + + 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; + } + } + + inline Vec3 CalcAngle(const Vec3& source, const Vec3& destination, bool clamp = true) + { + Vec3 angles = {}; + Vec3 delta = source - destination; + float fHyp = std::sqrtf((delta.x * delta.x) + (delta.y * delta.y)); + + angles.x = (atanf(delta.z / fHyp) * M_RADPI); + angles.y = (atanf(delta.y / delta.x) * M_RADPI); + angles.z = 0.0f; + + if (delta.x >= 0.0f) + angles.y += 180.0f; + + if (clamp) + ClampAngles(angles); + + return angles; + } + + inline float CalcFov(const Vec3& src, const Vec3& dst) + { + Vec3 v_src = Vec3(); + AngleVectors(src, &v_src); + + Vec3 v_dst = Vec3(); + AngleVectors(dst, &v_dst); + + float result = RAD2DEG(acos(v_dst.Dot(v_src) / v_dst.LengthSqr())); + + if (!isfinite(result) || isinf(result) || isnan(result)) + result = 0.0f; + + return result; + } + + inline void CreateVector(const Vec3& angle, Vec3& vector) + { + float pitch, yaw, tmp; + + pitch = float(angle[0] * PI / 180); + yaw = float(angle[1] * PI / 180); + tmp = float(cos(pitch)); + + vector[0] = float(-tmp * -cos(yaw)); + vector[1] = float(sin(yaw) * tmp); + vector[2] = float(-sin(pitch)); + } + + inline float GetFov(const Vec3& angle, const Vec3& source, const Vec3& destination) + { + Vec3 ang, aim; + float mag, u_dot_v; + ang = CalcAngle(source, destination); + + CreateVector(angle, aim); + CreateVector(ang, ang); + + mag = sqrtf(pow(aim.x, 2) + pow(aim.y, 2) + pow(aim.z, 2)); + u_dot_v = aim.Dot(ang); + + return RAD2DEG(acos(u_dot_v / (pow(mag, 2)))); + } + + inline void VectorTransform(const Vec3& input, const matrix3x4& matrix, Vec3& output) + { + for (auto i = 0; i < 3; i++) + output[i] = input.Dot((Vec3&)matrix[i]) + matrix[i][3]; + } + + 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 = std::clamp(cVal, 0.0f, 1.0f); + + return C + (D - C) * cVal; + } + + inline Vec3 VelocityToAngles(const Vec3& direction) + { + auto Magnitude = [&](const Vec3& v) -> float { + return sqrtf(v.Dot(v)); + }; + + float yaw, pitch; + + if (direction.y == 0.0f && direction.x == 0.0f) + { + yaw = 0.0f; + + if (direction.z > 0.0f) + pitch = 270.0f; + + else pitch = 90.0f; + } + + else + { + yaw = RAD2DEG(atan2f(direction.y, direction.x)); + pitch = RAD2DEG(atan2f(-direction.z, Magnitude(Vec3(direction)))); + + if (yaw < 0.0f) + yaw += 360.0f; + + if (pitch < 0.0f) + pitch += 360.0f; + } + + return { pitch, yaw, 0.0f }; + } + + inline void MatrixSetColumn(const Vec3& in, int column, matrix3x4& out) + { + out[0][column] = in.x; + out[1][column] = in.y; + out[2][column] = in.z; + } + + inline void AngleMatrix(const Vec3& angles, matrix3x4& matrix) + { + float sr, sp, sy, cr, cp, cy; + + SinCos(DEG2RAD(angles[1]), &sy, &cy); + SinCos(DEG2RAD(angles[0]), &sp, &cp); + SinCos(DEG2RAD(angles[2]), &sr, &cr); + + 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; + } + + inline void MatrixAngles(const matrix3x4& matrix, Vec3& angles) + { + const Vec3 forward = { matrix[0][0], matrix[1][0], matrix[2][0] }; + const Vec3 left = { matrix[0][1], matrix[1][1], matrix[2][1] }; + const Vec3 up = { 0.f, 0.f, matrix[2][2] }; + + float len = forward.Length2D(); + + if (len > 0.001f) + { + angles.x = RAD2DEG(std::atan2(-forward.z, len)); + angles.y = RAD2DEG(std::atan2(forward.y, forward.x)); + angles.z = RAD2DEG(std::atan2(left.z, up.z)); + } + else + { + angles.x = RAD2DEG(std::atan2(-forward.z, len)); + angles.y = RAD2DEG(std::atan2(-left.x, left.y)); + angles.z = 0.f; + } + } + + inline void RotateTriangle(std::array& points, float rotation) + { + Vec2 points_center = (points[0] + points[1] + points[2]) / 3; + + for (auto& point : points) + { + point -= points_center; + float temp_x = point.x; + float temp_y = point.y; + float theta = DEG2RAD(rotation); + float c = cosf(theta); + float s = sinf(theta); + point.x = temp_x * c - temp_y * s; + point.y = temp_x * s + temp_y * c; + point += points_center; + } + } + + inline bool RayToOBB(const Vec3& origin, const Vec3& direction, const Vec3& position, const Vec3& min, const Vec3& max, const matrix3x4 orientation) + { + Vec3 p = position - origin; + + Vec3 X = { orientation[0][0], orientation[0][1], orientation[0][2] }; + Vec3 Y = { orientation[1][0], orientation[1][1], orientation[1][2] }; + Vec3 Z = { orientation[2][0], orientation[2][1], orientation[2][2] }; + + Vec3 f = { X.Dot(direction), Y.Dot(direction), Z.Dot(direction) }; + Vec3 e = { X.Dot(p), Y.Dot(p), Z.Dot(p) }; + + float t[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + + for (int i = 0; i < 3; ++i) + { + if (floatCompare(f[i], 0.0f)) + { + if (-e[i] + min[i] > 0.0f || -e[i] + max[i] < 0.0f) + return false; + + f[i] = 0.00001f; + } + + t[i * 2 + 0] = (e[i] + max[i]) / f[i]; + t[i * 2 + 1] = (e[i] + min[i]) / f[i]; + } + + float tmin = fmaxf(fmaxf(fminf(t[0], t[1]), fminf(t[2], t[3])), fminf(t[4], t[5])); + float tmax = fminf(fminf(fmaxf(t[0], t[1]), fmaxf(t[2], t[3])), fmaxf(t[4], t[5])); + + if (tmax < 0.0f) + return false; + + if (tmin > tmax) + return false; + + return true; + } + + inline void VectorRotate(Vec3& in1, const matrix3x4& in2, Vec3& out) + { + out[0] = in1.Dot(in2[0]); + out[1] = in1.Dot(in2[1]); + out[2] = in1.Dot(in2[2]); + } + + inline auto GetRotatedPosition(Vec3 start, const float rotation, const float distance) + { + const auto rad = DEG2RAD(rotation); + start.x += cosf(rad) * distance; + start.y += sinf(rad) * distance; + + return start; + } + + inline void MatrixCopy(const matrix3x4& source, matrix3x4& target) + { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + target[i][j] = source[i][j]; + } + } + } + + inline void GetMatrixOrigin(const matrix3x4& source, Vec3& target) + { + target.x = source[0][3]; + target.y = source[1][3]; + target.z = source[2][3]; + } + + inline void ConcatTransforms(const matrix3x4& in1, const matrix3x4& in2, matrix3x4& out) + { + if (&in1 == &out) + { + matrix3x4 in1b; + MatrixCopy(in1, in1b); + ConcatTransforms(in1b, in2, out); + return; + } + + if (&in2 == &out) + { + matrix3x4 in2b; + MatrixCopy(in2, in2b); + ConcatTransforms(in1, in2b, out); + return; + } + + 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[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + 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[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + 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]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; + } +} + +#pragma warning (pop) \ No newline at end of file diff --git a/Amalgam/src/Utils/Memory/Memory.cpp b/Amalgam/src/Utils/Memory/Memory.cpp new file mode 100644 index 0000000..da91bb9 --- /dev/null +++ b/Amalgam/src/Utils/Memory/Memory.cpp @@ -0,0 +1,116 @@ +#include "Memory.h" +#include +#include +#include + +#define INRANGE(x, a, b) (x >= a && x <= b) +#define GetBits(x) (INRANGE((x & (~0x20)),'A','F') ? ((x & (~0x20)) - 'A' + 0xA) : (INRANGE(x,'0','9') ? x - '0' : 0)) +#define GetBytes(x) (GetBits(x[0]) << 4 | GetBits(x[1])) + +typedef void* (*InstantiateInterfaceFn)(); + +struct InterfaceInit_t +{ + InstantiateInterfaceFn m_pInterface = nullptr; + const char* m_pszInterfaceName = nullptr; + InterfaceInit_t* m_pNextInterface = nullptr; +}; + +std::vector pattern_to_byte(const char* pattern) +{ + // Prerequisites + auto bytes = std::vector{}; + const auto start = const_cast(pattern); + const char* const end = const_cast(pattern) + strlen(pattern); + + // Convert signature into corresponding bytes + for (char* current = start; current < end; ++current) + { + // Is current byte a wildcard? Simply ignore that that byte later + if (*current == '?') + { + ++current; + + // Check if following byte is also a wildcard + if (*current == '?') + ++current; + + // Dummy byte + bytes.push_back(-1); + } + else + { + // Convert character to byte on hexadecimal base + bytes.push_back(std::strtoul(current, ¤t, 16)); + } + } + + return bytes; +} + +std::uintptr_t CMemory::FindSignature(const char* szModule, const char* szPattern) +{ + if (const auto hMod = GetModuleHandleA(szModule)) + { + // Get module information to search in the given module + MODULEINFO module_info; + if (!GetModuleInformation(GetCurrentProcess(), hMod, &module_info, sizeof(MODULEINFO))) + return {}; + + // The region where we will search for the byte sequence + const auto image_size = module_info.SizeOfImage; + + // Check if the image is faulty + if (!image_size) + return {}; + + // Convert IDA-Style signature to a byte sequence + const auto pattern_bytes = pattern_to_byte(szPattern); + + const auto image_bytes = reinterpret_cast(hMod); + + const auto signature_size = pattern_bytes.size(); + const int* signature_bytes = pattern_bytes.data(); + + // Now loop through all bytes and check if the byte sequence matches + for (auto i = 0ul; i < image_size - signature_size; ++i) + { + auto byte_sequence_found = true; + + // Go through all bytes from the signature and check if it matches + for (auto j = 0ul; j < signature_size; ++j) + { + if (image_bytes[i + j] != signature_bytes[j] // Bytes don't match + && signature_bytes[j] != -1) // Byte isn't a wildcard either, WHAT THE HECK + { + byte_sequence_found = false; + break; + } + } + + // All good, now return the right address + if (byte_sequence_found) + return { reinterpret_cast(&image_bytes[i]) }; + } + + // Byte sequence wasn't found + return {}; + } + + return 0x0; +} + +using CreateInterfaceFn = void* (*)(const char* pName, int* pReturnCode); + +PVOID CMemory::FindInterface(const char* szModule, const char* szObject) +{ + const auto hModule = GetModuleHandleA(szModule); + if (!hModule) + return nullptr; + + const auto createFn = reinterpret_cast(GetProcAddress(hModule, "CreateInterface")); + if (!createFn) + return nullptr; + + return createFn(szObject, nullptr); +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Memory/Memory.h b/Amalgam/src/Utils/Memory/Memory.h new file mode 100644 index 0000000..58fe271 --- /dev/null +++ b/Amalgam/src/Utils/Memory/Memory.h @@ -0,0 +1,24 @@ +#pragma once +#include "../Feature/Feature.h" +#include +#include + +class CMemory +{ +public: + std::uintptr_t FindSignature(const char* szModule, const char* szPattern); + PVOID FindInterface(const char* szModule, const char* szObject); + + inline void* GetVFunc(void* instance, size_t index) + { + const auto vtable = *static_cast(instance); + return vtable[index]; + } + + inline std::uintptr_t RelToAbs(const std::uintptr_t address) + { + return *reinterpret_cast(address + 0x3) + address + 0x7; + } +}; + +ADD_FEATURE_CUSTOM(CMemory, Memory, U) \ No newline at end of file diff --git a/Amalgam/src/Utils/Minidump/Minidump.cpp b/Amalgam/src/Utils/Minidump/Minidump.cpp new file mode 100644 index 0000000..2f7bbe9 --- /dev/null +++ b/Amalgam/src/Utils/Minidump/Minidump.cpp @@ -0,0 +1,77 @@ +#include "Minidump.h" + +#include +#include +#include +#include + +[[noreturn]] void ExitWithMessage(const TCHAR* msg) +{ + MessageBox( + nullptr, + msg, + _T("Unhandled exception"), + MB_OK | MB_ICONERROR + ); + + ExitProcess(0); +} + +LONG __stdcall Minidump::ExceptionFilter(PEXCEPTION_POINTERS exPtr) +{ + const HMODULE hLib = LoadLibrary(_T("dbghelp")); + if (!hLib) + { + ExitWithMessage(_T("Could not load dbghelp!")); + } + + const auto pMiniDumpWriteDump = reinterpret_cast(GetProcAddress(hLib, "MiniDumpWriteDump")); + + // Get the MiniDumpWriteDump function + if (!pMiniDumpWriteDump) + { + ExitWithMessage(_T("Could not load MiniDumpWriteDump!")); + } + + // Get the dump folde (Desktop) + TCHAR buf[512]; + const auto gfpResult = SHGetFolderPath(nullptr, CSIDL_DESKTOP, nullptr, SHGFP_TYPE_CURRENT, buf); + if (FAILED(gfpResult)) + { + ExitWithMessage(_T("Failed to get folder path!")); + } + + // Create a file handle + TCHAR fileName[MAX_PATH]; + const int curTime = static_cast(time(nullptr) % 100000); + wsprintf(fileName, _T("%s\\Crash_Amalgam_%x.dmp"), buf, curTime); + const HANDLE hFile = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + + if (hFile == INVALID_HANDLE_VALUE) + { + wsprintf(buf, _T("Could not create minidump file!\n\n- Error: %ul\n- File: %s"), GetLastError(), fileName); + ExitWithMessage(buf); + } + + // Write the minidump + MINIDUMP_EXCEPTION_INFORMATION mdei = { + GetCurrentThreadId(), + exPtr, + FALSE + }; + + if (pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, nullptr, nullptr)) + { + wsprintf(buf, _T("Minidump created.\n\n- Build: " __TIMESTAMP__ "\n- File: %s"), fileName); + } + else + { + wsprintf(buf, _T("Could not create minidump!\n- Error: %ul\n- File: %s"), GetLastError(), fileName); + } + + // Cleanup + FreeLibrary(hLib); + CloseHandle(hFile); + + ExitWithMessage(buf); +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Minidump/Minidump.h b/Amalgam/src/Utils/Minidump/Minidump.h new file mode 100644 index 0000000..4a215c5 --- /dev/null +++ b/Amalgam/src/Utils/Minidump/Minidump.h @@ -0,0 +1,8 @@ +#pragma once +#include "../Feature/Feature.h" +#include + +namespace Minidump +{ + LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exPtr); +} \ No newline at end of file diff --git a/Amalgam/src/Utils/NetVars/NetVars.cpp b/Amalgam/src/Utils/NetVars/NetVars.cpp new file mode 100644 index 0000000..7beb08d --- /dev/null +++ b/Amalgam/src/Utils/NetVars/NetVars.cpp @@ -0,0 +1,37 @@ +#include "NetVars.h" + +#include "../Hash/FNV1A.h" + +int CNetVars::GetOffset(RecvTable* pTable, const char* szNetVar) +{ + auto uHash = FNV1A::Hash(szNetVar); + for (int i = 0; i < pTable->m_nProps; i++) + { + RecvProp Prop = pTable->m_pProps[i]; + + if (uHash == FNV1A::Hash(Prop.m_pVarName)) + return Prop.GetOffset(); + + if (auto DataTable = Prop.GetDataTable()) + { + if (auto nOffset = GetOffset(DataTable, szNetVar)) + return nOffset + Prop.GetOffset(); + } + } + + return 0; +} + +int CNetVars::GetNetVar(const char* szClass, const char* szNetVar) +{ + ClientClass* pClasses = I::BaseClientDLL->GetAllClasses(); + + auto uHash = FNV1A::Hash(szClass); + for (auto pCurrNode = pClasses; pCurrNode; pCurrNode = pCurrNode->m_pNext) + { + if (uHash == FNV1A::Hash(pCurrNode->m_pNetworkName)) + return GetOffset(pCurrNode->m_pRecvTable, szNetVar); + } + + return 0; +} \ No newline at end of file diff --git a/Amalgam/src/Utils/NetVars/NetVars.h b/Amalgam/src/Utils/NetVars/NetVars.h new file mode 100644 index 0000000..5e60c77 --- /dev/null +++ b/Amalgam/src/Utils/NetVars/NetVars.h @@ -0,0 +1,41 @@ +#pragma once +#include "../Feature/Feature.h" +#include "../../SDK/Definitions/Interfaces/IVEngineClient.h" +#include "../../SDK/Definitions/Misc/dt_recv.h" +#include + +class CNetVars +{ +public: + int GetOffset(RecvTable* pTable, const char* szNetVar); + int GetNetVar(const char* szClass, const char* szNetVar); +}; + +ADD_FEATURE_CUSTOM(CNetVars, NetVars, U); + +#define NETVAR(_name, type, table, name) type& _name() \ +{ \ + static int nOffset = U::NetVars.GetNetVar(table, name); \ + return *reinterpret_cast(std::uintptr_t(this) + nOffset); \ +} + +#define NETVAR_OFF(_name, type, table, name, offset) type& _name() \ +{ \ + static int nOffset = U::NetVars.GetNetVar(table, name) + offset; \ + return *reinterpret_cast(std::uintptr_t(this) + nOffset); \ +} + +#define OFFSET(name, type, offset) type& name() \ +{ \ + return *reinterpret_cast(std::uintptr_t(this) + offset); \ +} + +#define VIRTUAL(name, type, fn, base, index) type name() \ +{ \ + return reinterpret_cast(U::Memory.GetVFunc(base, index))(base); \ +} + +#define CONDGET(name, conditions, cond) bool name() \ +{ \ + return (conditions & cond); \ +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Signatures/Signatures.cpp b/Amalgam/src/Utils/Signatures/Signatures.cpp new file mode 100644 index 0000000..5bb07e3 --- /dev/null +++ b/Amalgam/src/Utils/Signatures/Signatures.cpp @@ -0,0 +1,35 @@ +#include "Signatures.h" + +#include "../Memory/Memory.h" +#include +#include + +CSignature::CSignature(const char* sDLLName, const char* sSignature, int nOffset, const char* sName) +{ + m_pszDLLName = sDLLName; + m_pszSignature = sSignature; + m_nOffset = nOffset; + m_pszName = sName; + + U::Signatures.AddSignature(this); +} + +void CSignature::Initialize() +{ + m_dwVal = U::Memory.FindSignature(m_pszDLLName, m_pszSignature); + if (!m_dwVal) + OutputDebugStringA(std::format("CSignature::Initialize() failed to initialize:\n {}\n {}\n {}\n", m_pszName, m_pszDLLName, m_pszSignature).c_str()); + + m_dwVal += m_nOffset; +} + +void CSignatures::Initialize() +{ + for (auto Signature : m_vecSignatures) + { + if (!Signature) + continue; + + Signature->Initialize(); + } +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Signatures/Signatures.h b/Amalgam/src/Utils/Signatures/Signatures.h new file mode 100644 index 0000000..f6b3c3b --- /dev/null +++ b/Amalgam/src/Utils/Signatures/Signatures.h @@ -0,0 +1,44 @@ +#pragma once +#include "../Feature/Feature.h" +#include +#include + +class CSignature +{ +private: + std::uintptr_t m_dwVal = 0x0; + const char* m_pszDLLName = {}; + const char* m_pszSignature = {}; + int m_nOffset = 0; + const char* m_pszName = {}; + +public: + CSignature(const char* sDLLName, const char* sSignature, int nOffset, const char* sName); + + void Initialize(); + + inline std::uintptr_t operator()() + { + return m_dwVal; + } + + template T As() { return reinterpret_cast(this->operator()()); } +}; + +#define MAKE_SIGNATURE(name, dll, sig, offset) namespace S { inline CSignature name(dll, sig, offset, #name); } + +class CSignatures +{ +private: + std::vector m_vecSignatures = {}; + +public: + void Initialize(); + + inline void AddSignature(CSignature* pSignature) + { + m_vecSignatures.push_back(pSignature); + } +}; + +ADD_FEATURE_CUSTOM(CSignatures, Signatures, U); \ No newline at end of file diff --git a/Amalgam/src/Utils/Timer/Timer.cpp b/Amalgam/src/Utils/Timer/Timer.cpp new file mode 100644 index 0000000..6f94afd --- /dev/null +++ b/Amalgam/src/Utils/Timer/Timer.cpp @@ -0,0 +1,29 @@ +#include "Timer.h" + +#include + +Timer::Timer() +{ + Last = std::chrono::steady_clock::now(); +} + +bool Timer::Check(unsigned ms) const +{ + const auto currentTime = std::chrono::steady_clock::now(); + return std::chrono::duration_cast(currentTime - Last).count() >= ms; +} + +bool Timer::Run(unsigned ms) +{ + if (Check(ms)) + { + Update(); + return true; + } + return false; +} + +inline void Timer::Update() +{ + Last = std::chrono::steady_clock::now(); +} \ No newline at end of file diff --git a/Amalgam/src/Utils/Timer/Timer.h b/Amalgam/src/Utils/Timer/Timer.h new file mode 100644 index 0000000..334ac8b --- /dev/null +++ b/Amalgam/src/Utils/Timer/Timer.h @@ -0,0 +1,18 @@ +#pragma once +#include + +/* + * Credits to cathook (nullifiedcat) + */ + +class Timer +{ +private: + std::chrono::steady_clock::time_point Last; + +public: + Timer(); + bool Check(unsigned ms) const; + bool Run(unsigned ms); + inline void Update(); +}; \ No newline at end of file